To implement web fonts, we need to use the @font-face directive in our CSS… well, SCSS.
The @font-face declaration block looks like this in its vanilla CSS form:
@font-face {
font-family: fontName;
src: url('path/to/font.eot'); /*IE9 Compat Modes*/
src: url('path/to/font.eot?#iefix') format('embedded-opentype'), /*IE6-IE8 */
url('path/to/font.woff') format('woff'), /*Modern Browsers*/
url('path/to/font.ttf') format('truetype'), /*Safari, Android, iOS*/
url('path/to/font.svg#fontName') format('svg'); /*iOS devices*/
font-weight: normal;
font-style: normal;
}Now, if you're using more than one style or font family, you need to repeat the whole @font-face declaration block for each font file. This is not very DRY (Don't Repeat Yourself).
Yes that's a pretty hefty piece of CSS to handle web fonts, oh man.
To keep our sanity, let's turn the prior @font-face CSS declaration block to a Sass mixin:
@mixin fontFace($font-family, $file-path) {
@font-face {
font: {
family: $font-family;
weight: normal;
style: normal;
}
//IE9 Compat Modes
src: url('#{$file-path}.eot');
//IE6-IE8
src: url('#{$file-path}.eot?#iefix') format('embedded-opentype'),
//Modern Browsers
url('#{$file-path}.woff') format('woff'),
//Safari, Android, iOS
url('#{$file-path}.ttf') format('truetype'),
//Safari, Android, iOS
url('#{$file-path}.svg') format('svg');
}
}The usage is a single line of code to call the font file. Let's use the typeface Oswald:
@include fontFace(oswald-light, '../fonts/oswald-light');
Using it on any element is a matter of adding the font name at the beginning of the font stack, as shown here:
p { font: 2.2rem oswald-bold, Arial, "Helvetica Neue", Helvetica, sans-serif; }If we need to include more than one font file, just add another line calling the mixin but specifying the other font name:
@include fontFace(oswald-light, '../fonts/oswald-light');
@include fontFace(oswald-regular, '../fonts/oswald-regular');
The preceding two lines of code will compile to the following CSS:
@font-face {
font-family: oswald-light;
font-weight: normal;
font-style: normal;
src: url("../fonts/oswald-light.eot");
src: url("../fonts/oswald-light.eot?#iefix") format("embedded-opentype"), url("../fonts/oswald-light.woff") format("woff"), url("../fonts/oswald-light.ttf") format("truetype"), url("../fonts/oswald-light.svg") format("svg");
}
@font-face {
font-family: oswald-regular;
font-weight: normal;
font-style: normal;
src: url("../fonts/oswald-regular.eot");
src: url("../fonts/oswald-regular.eot?#iefix") format("embedded-opentype"), url("../fonts/oswald-regular.woff") format("woff"), url("../fonts/oswald-regular.ttf") format("truetype"), url("../fonts/oswald-regular.svg") format("svg");
}That's a pretty nifty way of creating all that CSS with a mere two lines of code, eh? However, if we want to make things right, let's analyze what we're doing here:
.eot font..ttf font..svg file..woff font. According to CanIUse.com, .woff font files are 99 percent supported, with the exception of Opera Mini at the time of writing this book (http://caniuse.com/#search=woff).So the question is: Can we gracefully degrade the experience for legacy browsers and OS's and let them use a system font instead?
Sure we can!
After optimizing the mixin to use only .woff fonts, this is what it looks like:
@mixin fontFace($font-family, $file-path) {
@font-face {
font: {
family: $font-family;
weight: normal;
style: normal;
}
//Modern Browsers
src: url('#{$file-path}.woff') format('woff');
}
}The usage is exactly the same:
@include fontFace(oswald-light, '../fonts/oswald-light'); @include fontFace(oswald-regular, '../fonts/oswald-regular');
The compiled CSS is much shorter:
@font-face {
font-family: oswald-light;
font-weight: normal;
font-style: normal;
src: url("../fonts/oswald-light.woff") format("woff");
}
@font-face {
font-family: oswald-regular;
font-weight: normal;
font-style: normal;
src: url("../fonts/oswald-regular.woff") format("woff");
}Using it on a couple of elements looks like this:
h1 { font: 4.1rem oswald-regular, Arial, "Helvetica Neue", Helvetica, sans-serif; }
p { font: 2.4rem oswald-light, Arial, "Helvetica Neue", Helvetica, sans-serif; }Serving only the .woff font puts a lot less file management on our plate, which helps free our brains from unnecessary tasks and allow us to focus on what matters most: building a memorable experience. Not to mention, it makes our CSS code more streamlined and scalable.
But wait, we're letting legacy browsers gracefully degrade to system fonts, and we still need to define the font sizes in pixels for them!
Pixels-to-rems Sass mixin to the rescue!
Remember to see the base-10 model in the <html> tag for easier calculations:
//Base-10 model
html { font-size: 62.5%; }Then let's declare the font sizes and font families:
h1 {
@include fontSize(4.1);
font-family: oswald-regular, Arial, "Helvetica Neue", Helvetica, sans-serif;
}
p {
@include fontSize(2.4);
font-family: oswald-light, Arial, "Helvetica Neue", Helvetica, sans-serif;
}The compiled CSS looks to this:
h1 {
font-size: 41px;
font-size: 4.1rem;
font-family: oswald-regular, Arial, "Helvetica Neue", Helvetica, sans-serif;
}
p {
font-size: 24px;
font-size: 2.4rem;
font-family: oswald-light, Arial, "Helvetica Neue", Helvetica, sans-serif;
}Thus, by harnessing the superpowers of two simple Sass mixins, we can easily embed web fonts and use rems for our font-sizes while providing pixel-based font sizes for legacy browsers.
This is a great example of robust scalability.
Here's a demo I created for this in CodePen:
http://codepen.io/ricardozea/pen/9c93240a3404f12ffad83fa88f14d6ef
Without losing any momentum, let's change gears and talk about how to improve the legibility of our pages by accomplishing a minimum line length with the awesome FlowType.js jQuery plugin by Simple Focus.