Serving custom fonts with cssbundling-rails

Choosing a font 


My font of choice is Open Sans; I downloaded it and added the various font files to the `app/assets/fonts/OpenSans` directory. 


Using .css.erb 


First, to make the `asset_url` helpers work, we need to use a `.css.erb` file to direct the fonts through the asset pipeline. Using paths directly won't be possible in production when the assets have had a digest added to them.
 

lang-scss
// ./app/assets/stylesheets/opensans.css.erb

@font-face {
  font-family: "Open Sans";
  src: url("<%= font_path('OpenSans/Bold/OpenSans-Bold.woff2') %>") format("woff2"),
       url("<%= font_path('OpenSans/Bold/OpenSans-Bold.woff') %>") format("woff"),
       url("<%= font_path('OpenSans/Bold/OpenSans-Bold.ttf') %>") format("truetype");
  font-weight: bold;
  font-style: normal;
}
@font-face {
  font-family: "Open Sans";
  src: url("<%= font_path('OpenSans/BoldItalic/OpenSans-BoldItalic.woff2') %>") format("woff2"),
       url("<%= font_path('OpenSans/BoldItalic/OpenSans-BoldItalic.woff') %>") format("woff"),
       url("<%= font_path('OpenSans/BoldItalic/OpenSans-BoldItalic.ttf') %>") format("truetype");
  font-weight: bold;
  font-style: italic;
}
@font-face {
  font-family: "Open Sans";
  src: url("<%= font_path('OpenSans/ExtraBold/OpenSans-ExtraBold.woff2') %>") format("woff2"),
       url("<%= font_path('OpenSans/ExtraBold/OpenSans-ExtraBold.woff') %>") format("woff"),
       url("<%= font_path('OpenSans/ExtraBold/OpenSans-ExtraBold.ttf') %>") format("truetype");
  font-weight: 800;
  font-style: normal;
}
@font-face {
  font-family: "Open Sans";
  src: url("<%= font_path('OpenSans/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff2') %>") format("woff2"),
       url("<%= font_path('OpenSans/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff') %>") format("woff"),
       url("<%= font_path('OpenSans/ExtraBoldItalic/OpenSans-ExtraBoldItalic.ttf') %>") format("truetype");
  font-weight: 800;
  font-style: italic;
}

Newer rails versions have fixed this problem in the following PR. Since December 2021 it should be possible to make it work with the following adjustments:
 

lang-scss
// ./app/assets/stylesheets/opensans.css

@font-face {
  font-family: "Open Sans";
  src: url("OpenSans/Bold/OpenSans-Bold.woff2") format("woff2"),
       url("OpenSans/Bold/OpenSans-Bold.woff") format("woff"),
       url("OpenSans/Bold/OpenSans-Bold.ttf") format("truetype");
  font-weight: bold;
  font-style: normal;
}
@font-face {
  font-family: "Open Sans";
  src: url("OpenSans/BoldItalic/OpenSans-BoldItalic.woff2") format("woff2"),
       url("OpenSans/BoldItalic/OpenSans-BoldItalic.woff") format("woff"),
       url("OpenSans/BoldItalic/OpenSans-BoldItalic.ttf") format("truetype");
  font-weight: bold;
  font-style: italic;
}
@font-face {
  font-family: "Open Sans";
  src: url("OpenSans/ExtraBold/OpenSans-ExtraBold.woff2") format("woff2"),
       url("OpenSans/ExtraBold/OpenSans-ExtraBold.woff") format("woff"),
       url("OpenSans/ExtraBold/OpenSans-ExtraBold.ttf") format("truetype");
  font-weight: 800;
  font-style: normal;
}
@font-face {
  font-family: "Open Sans";
  src: url("OpenSans/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff2") format("woff2"),
       url("OpenSans/ExtraBoldItalic/OpenSans-ExtraBoldItalic.woff") format("woff"),
       url("OpenSans/ExtraBoldItalic/OpenSans-ExtraBoldItalic.ttf") format("truetype");
  font-weight: 800;
  font-style: italic;
}


Adding opensans.css to manifest.js 


Then we have to add the particular font file to the asset manifest. This step ensures that the assets are served both in development and production.
 

lang-js
// ./app/assets/config/manifest.js

//= link_tree ../fonts
//= link_tree ../images
//= link_tree ../builds
//= link opensans.css
//= link_tree ../../javascript .js



Configure TailwindCSS 


To use our custom font as default in TailwindCSS, we need to add `Open Sans` to them sans fonts.
 

lang-js
// ./tailwind.config.js

module.exports = {
  content: [
    "./app/**/*.html.erb",
    "./app/helpers/**/*.rb",
    "./app/javascript/**/*.js",
    "./app/assets/stylesheets/**/*.js",
    "./app/components/**/*.js",
    "./app/components/**/*.css"
  ],
  theme: {
    fontFamily: {
      sans: [
        "Open Sans",
        "ui-sans-serif",
        "system-ui",
        "-apple-system",
        "BlinkMacSystemFont",
        '"Segoe UI"',
        "Roboto",
        '"Helvetica Neue"',
        "Arial",
        '"Noto Sans"',
        "sans-serif",
        '"Apple Color Emoji"',
        '"Segoe UI Emoji"',
        '"Segoe UI Symbol"',
        '"Noto Color Emoji"'
      ]
    }
  }
}



Precompiling opensans.css.erb 


Precompile the erb asset to make use of it in the assets pipeline:
 

lang-ruby
# ./app/config/initializers/assets.rb

Rails.application.config.assets.precompile += %w[opensans.css.erb]



Loading opensans 


The last step is to load the font file in the application.html.erb.
 

lang-erb
<!-- app/views/layouts/application.html.erb -->

<!DOCTYPE html>
<html class="min-h-screen">
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag "opensans", "data-turbo-track": "reload", defer: true %>
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload", defer: true %>
    <%= javascript_importmap_tags %>
  </head>
</html>