Skip to content

Instantly share code, notes, and snippets.

@jonathantneal
Last active April 19, 2024 11:51
Show Gist options
  • Save jonathantneal/d0460e5c2d5d7f9bc5e6 to your computer and use it in GitHub Desktop.
Save jonathantneal/d0460e5c2d5d7f9bc5e6 to your computer and use it in GitHub Desktop.
SASS @font-face mixin

Font Face

A mixin for writing @font-face rules in SASS.

Usage

Create a font face rule. Embedded OpenType, WOFF2, WOFF, TrueType, and SVG files are automatically sourced.

@include font-face(Samplino, fonts/Samplino);

Rendered as CSS:

@font-face {
	font-family: "Samplino";
	src: url("fonts/Samplino.eot?") format("eot"),
		 url("fonts/Samplino.woff2") format("woff2"),
		 url("fonts/Samplino.woff") format("woff"),
		 url("fonts/Samplino.ttf") format("truetype"),
		 url("fonts/Samplino.svg#Samplino") format("svg");
}

Create a font face rule that applies to bold and italic text.

@include font-face("Samplina Neue", fonts/SamplinaNeue, bold, italic);

Rendered as CSS:

@font-face {
	font-family: "Samplina Neue";
	font-style: italic;
	font-weight: bold;
	src: url("fonts/SamplinaNeue.eot?") format("eot"),
	     url("fonts/SamplinaNeue.woff2") format("woff2"),
	     url("fonts/SamplinaNeue.woff") format("woff"),
	     url("fonts/SamplinaNeue.ttf") format("truetype"),
	     url("fonts/SamplinaNeue.svg#Samplina_Neue") format("svg");
}

Create a font face rule that only sources a WOFF.

@include font-face(Samplinoff, fonts/Samplinoff, null, null, woff);

Rendered as CSS:

@font-face {
	font-family: "Samplinoff";
	src: url("fonts/Samplinoff.woff") format("woff");
}

Create a font face rule that applies to 500 weight text and sources EOT, WOFF2, and WOFF.

@include font-face(Samplinal, fonts/Samplinal, 500, normal, eot woff2 woff);

Rendered as CSS:

@font-face {
	font-family: "Samplinal";
	font-style: normal;
	font-weight: 500;
	src: url("fonts/Samplinal.eot?") format("eot"),
	     url("fonts/Samplinal.woff2") format("woff2"),
	     url("fonts/Samplinal.woff") format("woff");
}

Notes

IE≥9 prioritizes valid font formats over invalid ones. Therefore, while embedded-opentype is the correct format for an .eot font, eot is used to fool modern IE into prioritizing other, newer font formats.

IE≤8 only supports .eot fonts and parses the src property incorrectly, interpreting everything between the first opening parenthesis ( and the last closing parenthesis ) as a single URL. Therefore, a ? is appended to the .eot’s URL, fooling older IE into reading all other sources as query parameters.

// =============================================================================
// String Replace
// =============================================================================
@function str-replace($string, $search, $replace: "") {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
@return $string;
}
// =============================================================================
// Font Face
// =============================================================================
@mixin font-face($name, $path, $weight: null, $style: null, $exts: eot woff2 woff ttf svg) {
$src: null;
$extmods: (
eot: "?",
svg: "#" + str-replace($name, " ", "_")
);
$formats: (
otf: "opentype",
ttf: "truetype"
);
@each $ext in $exts {
$extmod: if(map-has-key($extmods, $ext), $ext + map-get($extmods, $ext), $ext);
$format: if(map-has-key($formats, $ext), map-get($formats, $ext), $ext);
$src: append($src, url(quote($path + "." + $extmod)) format(quote($format)), comma);
}
@font-face {
font-family: quote($name);
font-style: $style;
font-weight: $weight;
src: $src;
}
}
@richware
Copy link

My css project uses sass. So I have converted the scss to sass and have expanded to include an additional step to allow multiple font faces to be generated at one time. Here is my sass mixins: (don't forget to include the str-replace function)

@use "sass:map"

@mixin font-face-multiple($fonts)
  @each $font in $fonts
    $name: if(map-has-key($font,"name"), map-get($font,"name"), null)
    $path: if(map-has-key($font,"path"), map-get($font,"path"), null)
    $weight: if(map-has-key($font,"weight"), map-get($font,"weight"), null)
    $style: if(map-has-key($font,"style"), map-get($font,"style"), null)
    $display: if(map-has-key($font,"display"), map-get($font,"display"), null)
    $exts: if(map-has-key($font,"exts"), map-get($font,"exts"), null)
    @include font-face($name,$path,$weight,$style,$display,$exts)

@mixin font-face($name, $path, $weight: null, $style: null, $display: null, $exts: (eot woff2 woff ttf svg))
  // extensions: eot woff2 woff ttf svg
  $src: null

  $extmods: (eot:"?",svg:"#"+str-replace($name," ","_"))
  $formats: (otf: "opentype",ttf: "truetype")

  @each $ext in $exts
    $extmod: if(map-has-key($extmods, $ext), $ext + map-get($extmods, $ext), $ext)
    $format: if(map-has-key($formats, $ext), map-get($formats, $ext), $ext)
    $src: append($src, url(quote($path + "." + $extmod)) format(quote($format)), comma,)

  @font-face
    font-family: quote($name)
    font-style: $style
    font-weight: $weight
    @if($display)
      font-display: $display
    src: $src

Then all I have to do is create the mapping and include the mixin font-face-multiple and I have the code I am looking for

Example:

$font-list: ()

$font-list: append($font-list,("name": "Old Town","path": "..fonts/OldTown", "exts": (ttf)))
$font-list: append($font-list,("name": Roboto,"path": "..fonts/Roboto-Regular", "weight":400,"style":normal, "exts": (ttf)))

@include font-face-multiple($font-list)

Result:

@font-face {
  font-family: "Old Town";
  src: url("..fonts/OldTown.ttf") format("truetype");
}
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 400;
  src: url("..fonts/Roboto-Regular.ttf") format("truetype");
}

Disclaimer: The code here does not have any validation and there are some subtle issues needing resolution.

Happy coding!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment