Search code examples
cssfontsfont-facewebfonts

Dealing with multiple font files easier


I want to import a local font to use in my styles. However, the way it is usually suggested is far from optimal. For a normal, non-variable font, it would take up to 20 @font-face, each with up to 5 links for different types inside. That results in having to more or less manually linking up to 100 different files - and only for one font. Imagine amount of effort required when there are multiple fonts in a project.

Is there a better way to do it?


Solution

  • You could safely remove some older file types (unless you need the best legacy support):

    Example: "Inter" - generated by google web font helper

    @font-face {
        font-family: 'Inter';
        font-style: normal;
        font-weight: 400;
        src: url('fonts/inter-v11-latin-regular.eot'); 
        src: local(''),
             url('fonts/inter-v11-latin-regular.eot?#iefix') format('embedded-opentype'), 
             url('fonts/inter-v11-latin-regular.woff2') format('woff2'), 
             url('fonts/inter-v11-latin-regular.woff') format('woff'), 
             url('fonts/inter-v11-latin-regular.ttf') format('truetype'),
             url('fonts/inter-v11-latin-regular.svg#Inter') format('svg'); 
      }
    

    Could be reduced to:

    @font-face {
        font-family: 'Inter';
        font-style: normal;
        font-weight: 400;
        src: url('fonts/inter-v11-latin-regular.woff2') format('woff2'),
             url('fonts/inter-v11-latin-regular.woff') format('woff');
      }
    

    woff should suffice as a fallback for older browsers by now. (Even supported by ie 9 - see caniuse record).

    eot was exclusively used by Microsoft's Internet Explorer. If you're not developing for special cases like windows embedded system applications (depending on custom ie builds) you don't need them.

    svg only supported by some legacy safari versions - ditch them.

    truetype Overall probably the best browser support (widely used for desktop applications) but not as optimized for web usage (larger in file size). Might be needed for tasks like dynamic pdf generation (e.g domPdf or mPdf: most of the time you'll need to manually define embedded fonts at some point)

    local better remove this rule! Especially firefox had issues displaying local fonts due to security settings.

    CSS preprocessor mixin

    As @Parapluie already pointed out you could use a mixin to simplify your css coding.

    SCSS mixin
    based on @jonathantneal gist

    @mixin font-face($name, $path, $weight: null, $style: null, $exts: woff2 woff ttf otf) {
        $src: null;
        $formats: (
            otf: "opentype",
            ttf: "truetype"
        );
    
        @each $ext in $exts {
            $format: if(map-has-key($formats, $ext), map-get($formats, $ext), $ext);
            $src: append($src, url(quote($path + "." + $ext)) format(quote($format)), comma
          );
        }
    
        @font-face {
            font-family: quote($name);
            font-style: $style;
            font-weight: $weight;
            src: $src;
        }
    }
    
    @include font-face('Inter', 'fonts/Inter', 400, normal, woff2 woff ttf);
    @include font-face('Inter', 'fonts/Inter', 400, italic, woff2 woff ttf);  
    

    Codepen example:
    You can switch between compiled/uncompiled css view to see the output.

    Variable fonts

    font-face property values accept ranges like e.g for a weight range from 100–900 (light/thin to black).

    @font-face {
      font-family: 'Inter';
      font-style: normal;
      font-weight: 100 900;
      src: url('https://fonts.gstatic.com/s/inter/v11/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2') format('woff2')
    }
    

    SCSS code

    @include font-face('Inter VF', 'https://fonts.gstatic.com/s/inter/v11/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw', 100 900, normal, woff2);
    

    A presumably more accurate rule would add specific variable font format values like format('woff2-variations') and format('woff2 supports variations'):

    @font-face {
      font-family: 'Inter';
      font-style: normal;
      font-weight: 100 900;
      src: url('https://fonts.gstatic.com/s/inter/v11/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2') format('woff2 supports variations'),
      url('https://fonts.gstatic.com/s/inter/v11/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2') format('woff2-variations');
    }
    

    Unfortunately, these declarations are not yet supported by some browsers and many documentations are outdated due to recent API changes.

    So you should still test your rules in different browsers.

    How to fetch google variable fonts

    When using the google fonts UI you might not get the actual variable font .woff2 file.

    "fonts.googleapis.com/css2?family=Inter:[email protected]"
    

    should work in most modern browsers:
    The returned css will contain variable font file URLs

    "fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900"
    

    (generated using the UI) will return seperate font files for each weight.

    See also MDN Docs: Variable fonts guide