Documentation for adding fonts to Liveview Project

I am using Tailwinds and I want to use a font family I found on Google. I have a url for the font, but I think it would be safer to download and add the font to my project. I can’t find any documentation (on the Phoenix site) on how to do this. I have found some previous Elixir Forum posts, but they are old posts and don’t know if they apply to 1.5.

Could someone point me in the right direction?

1 Like

You should be able to just replace the URL with a relative path name like

src: url('/fonts/my-font.ttf');
2 Likes

Its also worth noting that this is not exclusive to LiveView. It’s just how phoenix in general deals with assets.

This is one of the reasons why I really love Phoenix. It does such a great job at creating a clear boundary between assets and framework. (Sorry Rail’s asset pipeline still triggers me")

Basically how it works is you use router helpers to point to the correct path of the asset. It’s also important to understand how mix phx.digest plays a role in this too when you get to deploying.

1 Like

Another way I believe is to install them via npm and put in you tailwind config, see livebook’s tailwind.config.js and package.json

1 Like

I wonder if postcss purge can work out what fonts are bing used?

Sorry. I’m probably asking a stupid question, but I’m super new to this. Would I download and put the fonts in my_app/assets/static OR my_app/repo/static/css? I was looking through the forum earlier and saw both directories mentioned. I wasn’t sure which one is the right place to store fonts. It seems confusing to see another static/css folder under repo. Not sure the difference between that one and css/static up in assets.

The one in priv/static is the output from the build tool, what your local webserver will use to serve the assets to you. assets/ is where you write your css and js. Put them in there and they’ll get copied to priv/static.

I made a small script to retrieve fonts and have them locally…

#!/bin/sh

for family in $*; do
for url in $( {
for agent in \
'Mozilla/5.0 (X11; Linux i686; rv:6.0) Gecko/20100101 Firefox/6.0' \
'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1' \
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)' ;
do
curl -A "$agent" -s "http://fonts.googleapis.com/css?family=$family" | \
grep -oE 'http://[A-Za-z0-9/._-]+'; \
done } | sort -u ) ;
do
extn=${url##*.} ;
file=$(echo "$family"| tr +[:upper:] _[:lower:]);
echo $url $file.$extn;
curl -s "$url" -o "$file.$extn";
done
done

For example.

$ ./get_font.sh Roboto
http://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxM.woff roboto.woff
http://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxPKTU1Kg.ttf roboto.ttf

Usually I put them in assets/fonts and have them processed by webpack, and file loader.

Then I just add a font stylesheet… like this.

@font-face {
  font-family: roboto;
  src: url("../fonts/roboto.ttf") format("truetype"); /* For IE */
  src: local("roboto"), url("../fonts/roboto.ttf") format("truetype"); /* For non-IE */

  src: local("roboto"), url("../fonts/roboto.woff") format("woff");
}

and the webpack rule.

        // Load fonts
        {
          test: /\.(woff|woff2|eot|ttf|otf)$/,
          use: [
            {
              loader: "file-loader",
              options: {
                name: "[name].[ext]",
                // Relative to output public_path
                outputPath: "./fonts/"
              }
            }
          ]
        },

You need to install file_loader npm package to do this…

4 Likes

Oh! That explains why there are two css directories and why there is tailwind code in the priv/static file! Thank you! That definitely clears up that mystery. :slight_smile:

I’m still struggling to get the font to work. Here’s what I’m doing. Does anyone see what I’m doing wrong?

Font File

  • I created a folder called “fonts” within my_app/css
  • I downloaded the Oswald font from Google and put the file in the “fonts” directory

app.scss
I added the follwing code into this file:

@layer base {
  h1 {
    @apply text-2xl;
  }
  h2 {
    @apply text-xl;
  }
  @font-face {
    font-family: Oswald;
    font-weight: 400;
    src: url('/fonts/Oswald/Oswald-VariableFont_wght.ttf');
  }
}

** tailwind.config.js**
I extended the font theme by adding this code in the tailwind.config.js file:

theme: {
    screens: {
      sm: '480px',
      md: '768px',
      lg: '976px',
      xl: '1440px',
    },
    extend: {},
    fontFamily: {
      sans: ['Oswald', 'Graphik', 'sans-serif'],
      serif: ['Merriweather', 'serif'],
    },
  },

** I recompiled using phx.server**
I have no idea if I needed to do this, but thought it couldn’t hurt.

Using the new font
I then used this code to try to use the Oswald font:

<section class="text-gray-700" style="font-family: 'Source Oswald', sans-serif">
</section>

I was hoping that all the text in that section would show in Oswald font, but it continues to just be in font-sans. Sigh. I’ve combed the documentation but most of it is about how to extend the theme in tailwind.config.js. I seem to be doing that correctly.

You said the font is called Oswald, but here you are referencing it Source Oswald:

<section class="text-gray-700" style="font-family: 'Source Oswald', sans-serif">

Did you try matching the names so they are the same?

Good catch! I thought “Source” was required but you’re right. Google page says to use this line:

font-family: 'Oswald', sans-serif;

So I went back and changed my code but still doesn’t work.

<section class="text-gray-700" style="font-family: 'Oswald', sans-serif">

I tried it inside of the h1 tag, I tried adding the semicolon at the end and removing it, I restarted server and reloaded web page. No change. :frowning:

Am I supposed to rebuild something every time I update the tailwind.config.js file?

Are You sure for the path?

Maybe try ./fonts… (note the starting dot, for relative path)

Also since you’re using Tailwind and put Oswald into the sans fontFamily, you should be able to just do class="text-gray-700 font-sans" and let Tailwind take care of it.

1 Like

You can have a look at the patterns for live_reload in your config/dev.exs file. It defines when to reload. It looks like this.

    patterns: [
      ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
      ~r"priv/gettext/.*(po)$",
      ~r"lib/my_app_web/(live|views)/.*(ex)$",
      ~r"lib/my_app_web/templates/.*(eex)$",
    ]
2 Likes

Ah! Good to know! Did a rebuild and I can see in the terminal that it’s getting the font. So at least now I know it’s pointing to the font directory:

[info] GET /fonts/Oswald/Oswald-VariableFont_wght.ttf

I’m struggling to understand how that works. I put Oswald in the ‘sans’ fontFamily along with other fonts. How do I specify that I want Oswald specifically and not … Special_Elite or sans-serif instead? If I just say class=“font-sans” then it’s going to have multiple sans fonts to choose from.

fontFamily: {
      'sans': ['Special_Elite', 'Oswald', 'Graphik', 'sans-serif'],
      'serif': ['Merriweather', 'serif'],
      'title': ['Special_Elite'],
      'body': ['Merriweather']
    },

I caught that as well. I realized it needed a …/fonts/Oswald/…

So I updated the path in my app.scss file but it oddly would not update the file in app.css … even after I restarted the server. In Web Inspector, I can see that it’s not finding the font because there is a red warning message for Oswald-Regular.ttf that says:

Failed to load resource: the server responded with a status of 404 (Not Found). 

So then I used Web Inspector to go into the app.css to see what path it was using. It was using the wrong path (despite me fixing it in app.scss) so I just opened up app.css and changed the path manually. I realize that I’m somehow not rebuilding things correctly because that file is not getting updated … but I haven’t figured out why that is happening.

Anyway, despite correcting the path manually in app.css … I’m still getting errors for finding the path to my fonts. I’m still hunting around to see why it can’t find my fonts.

The list goes in order of priority. Starting with the first option, it checks if that font is available, compatible, and has all the necessary characters to display the text. If it does, then it will use that font. Otherwise, it moves on to the next option in the list.

Note this is not a Tailwind-specific thing (see font-family - CSS: Cascading Style Sheets | MDN for more details)

1 Like

It looks like I need a loader! I just realized that there is an error flying by that I hadn’t seen because I needed to scroll up quite a bit to see it:

ERROR in ./css/app.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleParseError: Module parse failed: Unexpected character '' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)

 ERROR in ./fonts/Oswald/static/Oswald-Regular.ttf 1:0
    Module parse failed: Unexpected character '' (1:0)
    You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
    (Source code omitted for this binary file)
     @ ./css/app.scss (./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./css/app.scss) 4:36-88
    
    ERROR in ./fonts/Special_Elite/SpecialElite-Regular.ttf 1:0
    Module parse failed: Unexpected character '' (1:0)
    You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
    (Source code omitted for this binary file)
     @ ./css/app.scss (./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./css/app.scss) 5:36-94
    
    ERROR in ./fonts/Merriweather/Merriweather-Regular.ttf 1:0
    Module parse failed: Unexpected character '' (1:0)
    You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
    (Source code omitted for this binary file)

I had originally specified the source files for the fonts as follows:

src: url('../fonts/Oswald/static/Oswald-Regular.ttf') format('truetype');

But I noticed it was barfing on those single quotes, so I removed them. But it still seems to be having issues with that file … even though I’ve removed the single quotes. I feel like I keep restarting the server but it’s not quite rebuilding everything based on my changes in app.scss.