Mime Type The CSS @font-face rule is a way to embed fonts in web pages.

The ever popular Bootstrap uses web fonts to show Glyph Icons and there's always Font Awesome should you need more.

Google Fonts and MyFonts also have 100s and 1000s of free and commercial fonts should you need them.

The problem is that IE and Chrome won't always display / use these fonts until they are served correctly from the web / application server.

Following an answer I recently posted on StackOverflow, I'll explain how to correctly serve web fonts from BedSheet; an application server for the Fantom JVM language.

Web font files typically have the extensions .eot, .otf, svg, .ttf and .woff. For browsers to recognise them, they need to be served up with the correct Content-Type in the HTTP Header. The value of the Content-Type field is a MIME type.

MIME Types :: The Official List

Over the years, there has been a lot of confusion as what the actual MIME types for web fonts should be. Most have only been resolved recently (as late as March 2013) by the official internet authorities: Internet Assigned Numbers Authority (IANA) and the W3C.

With supporting links, here are the official MIME types for web fonts:

Note there is a movement to change all the above to MIME types of font/XXX, as backed by the W3C in its proposal for WOFF v2. This is being tracked by the Internet Engineering Task Force (IETF) under The font Top Level Type, so it may all change yet!

It's worth mentioning that HTTP responses may gzip (or otherwise compress) all the above font formats except for .woff & .woff2, which are already heavily compressed.

How to Configure BedSheet / Fantom

When BedSheet serves up web font files, it converts the file extension (.eot, .otf, ...) to a MIME Type. It does this using the Fantom's MimeType.forExt() method which, in turn, uses the file %FAN_HOME%/etc/sys/ext2mime.props as a lookup table. By default, Fantom does not have definitions in this file for web fonts, so we have to manually add them.

Open up %FAN_HOME%/etc/sys/ext2mime.props and add the following:

eot=application/vnd.ms-fontobject
otf=application/font-sfnt
ttf=application/font-sfnt
woff=application/font-woff
woff2=font/woff2

Note that SVG is already defined so we do not add it. (Doing so would result in an error.)

Also note that BedSheet is configured out of the box to gzip compress web fonts, so no extra work is required for that.

And that's it! Fantom and BedSheet are now configured to serve up web font files!

How to Configure Heroku

Editing Fantom system files is fine on dev, or even a prod machine; but what do you do when deploying to a cloud platform such as Heroku? For each time your app is deployed, it downloads a fresh installation of Fantom!

Thankfully the Fantom Build Pack for Heroku has a build hook where we can automate the MIME type addition. Add the following to your build.fan:

select all
using build

class Build : BuildPod {

  @Target { help = "Heroku pre-compile hook" }
  Void herokuPreCompile() {

    ...

    // patch web font mime types
    patchMimeTypes([
      "eot"   : "application/vnd.ms-fontobject",
      "otf"   : "application/font-sfnt",
      "svg"   : "image/svg+xml",
      "ttf"   : "application/font-sfnt",
      "woff"  : "application/font-woff",
      "woff2" : "font/woff2"
    ])
  }

  private Void patchMimeTypes(Str:Str extToMimeTypes) {
    ext2mime := Env.cur.findFile(`etc/sys/ext2mime.props`)
    mimeTypes := ext2mime.readProps

    toAdd := extToMimeTypes.exclude |mime, ext->Bool| {
      mimeTypes.containsKey(ext)
    }

    if (!toAdd.isEmpty) {
      log.indent
      exts := toAdd.keys.sort.join(", ")
      log.info("Mime type for file extension(s) ${exts} do not exist")
      log.info("Patching `${ext2mime.normalize}`...")
      toAdd.keys.sort.each |ext| {
        mimeTypes = mimeTypes.rw.add(ext, extToMimeTypes[ext])
        log.info(" - ${ext} : " + mimeTypes[ext])
      }
      ext2mime.writeProps(mimeTypes)
      log.info("Done.")
      log.unindent
    }
  }
}

When deployed to Heroku, your console should give the following message:

Mime type for file extension(s) eot, otf, ttf, woff do not exist
  Patching `file:/C:/Apps/fantom-1.0.65/etc/sys/ext2mime.props`...
   - eot : application/vnd.ms-fontobject
   - otf : application/font-sfnt
   - ttf : application/font-sfnt
   - woff : application/font-woff
   - woff2 : font/woff2
  Done.

Have fun!

Edits

  • 8 Dec 2016 - Added WOFF v2 and the W3Cs proposal for a top level font/ MIME type.

Discuss