native-font

Native font stacks for web wizards

1
0
1
SCSS
public

native-font

Native font stacks for web wizards

About

This library intends to help you make use of native font stacks on the web.

It comes bundled with 76 pre-defined fonts. But don’t worry! You only ship to
the browser what you need. And these are native fonts, so there won’t be any
downloading of font files. It’s just the definitions needed to use the fonts
that are pre-installed on the end user machine.

Install

npm install --save-dev native-font

Include

mixins

@use "native-font";

.some-rule {
  @include native-font.variables();
}

fonts

@use "native-font/arial";
@use "native-font/arial-black";
@use "native-font/courier-new";

Background

What is a font stack?

In web development, we don’t know beforehand about all the fonts that will be
available on the user device. So we can define a stack of fonts; the first
font will be used if available. If not, we proceed to the next font on the
stack until we hit one that is available on the user device. That one will be
used. The trick then becomes to find those fonts available on the platforms we
want to target, that resemble each other enough so that one can be used as a
fallback for the other. People have done that work and published their results
on sites like cssfontstack.com and
modernfontstacks.com.

Why this module?

This module acts both as a format for defining font stacks in a re-usable way
and as a repository for fonts that can be used. Hopefully, we will be able to
expand the repository of ready-made fonts with open source contributions.

We define font stacks in such a way that we can re-use one font stack in the
definition of another and use the power of sass to automatically resolve the
dependency tree and generate the CSS definitions.

The fonts will be made available through css variables. For example, this sass
code:

@use "native-font";
@use "native-font/industrial";

:root, ::backdrop {
  @include native-font.variables();
}

h1 {
  font-family: var(--industrial);
}

results in this CSS:

:root, ::backdrop {
  --color-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  --sans-serif: "Helvetica Neue", "Arial Nova", "Nimbus Sans", Helvetica, Arial, sans-serif, var(--color-emoji);
  --industrial: Bahnschrift, "DIN Alternate", "Franklin Gothic Medium", "Nimbus Sans Narrow", sans-serif-condensed, var(--sans-serif);
}

h1 {
  font-family: var(--industrial);
}

You get a CSS variable --industrial that represents the font stack for the
font you selected. And in addition, you get CSS variable --sans-serif because
--industrial uses --sans-serif as fallback and you get --color-emoji
because sans-serif in turn has --color-emoji as fallback. All these
dependencies were resolved for you automatically.

Your font-family assignments become short and readable and the font stack
itself becomes explicit and managed in a structured way.

Use

Lets first look at how to apply a font to your text and cover
how to define a set of fonts and
output the styles later. Lastly we will discuss how you
can add your own fonts to the set of available fonts.

Apply a font

You apply a font by assigning a CSS variable to the font-family
property of the element(s) you want to style. For example:

<p>Text in my font</p>
p {
  font-family: var(--arial);
}

This would assign the font arial to the text in the p element. The CSS
variable name --arial can be easily derived from the name of the font. For
example, for Arial Black it would be --arial-black and for Segoe UI it would
be --segoe-ui.

Now lets look at how to define a set of fonts and output the styles for it.

Define a set of fonts

To define a set of fonts, you can use sass (recommended), or you
can use a predefined set,

Use sass

With sass you can automatically build up the font set as you @use fonts in
your code:

// load the 'arial' font
@use "native-font/arial";
// load more fonts if you need
// a dependency tree is created automatically

Dependencies are automatically resolved because each font actually @uses the
fonts it depends on and whenever a font is used for the first time, it is added
to the set.

Font stacks list the most specific fonts first, then less specific fonts as
fallbacks for when the most specific font is not available. For example, the
font stack for Arial might look something like Arial, Helvetica, sans-serif,
which means so much as ‘use Arial, but if that is not available, use Helvetica.
If that too is not available, use any sans-serif font’. So it makes sense to
think of fonts as ‘deriving’ from generic fonts. And that is exactly what this
library does. That is also why the predefined sets start with the most generic
fonts like serif, sans-serif and monospace first and we only add the more
specific fonts later. Because those fonts actually build on top of the more
generic fonts in the stack.

Use a predefined set

There are also some predefined sets available that you can load:

  • w3c: The family names defined by the World Wide Web Consortium
  • base: The w3C fonts plus 3 extra generic names
  • modern: A set of modern web fonts
  • cssfonts: The web-safe fonts we know and love
  • extra: cssfonts + some extra
  • all: The complete set of all of the above

You can load a set of fonts by @useing the set like this:

@use "native-font/sets/modern"

You still have to output the styles for the set.

Or, you can load these predefined sets by importing the CSS stylesheet:

@import 'native-font/sets/modern.css';

This already includes the styles so you don’t have to output them yourself.

When you go the CSS route, you can also select the minified version:

@import 'native-font/sets/modern.min.css';

Output the styles

Once we have defined the set of fonts we want to use, we need to output the
styles for them. That is actually as simple as this:

// load native-font mixins
@use "native-font";
// load fonts
@use "native-font/arial";
// output the styles
:root, ::backdrop {
  // render the CSS variables
  @include native-font.variables();
}

Outputs:

:root, ::backdrop {
  --color-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  --sans-serif: "Helvetica Neue", "Arial Nova", "Nimbus Sans", Helvetica, Arial, sans-serif, var(--color-emoji);
  --arial: "Arial Nova", Arial, "Helvetica Neue", Helvetica, var(--sans-serif);
}

As you can see, you actually get 3 variables. This font stack defines an extra
generic font name for color-emoji and makes it the fallback for the other
generic fonts, in order to improve emoji support across devices. The generic
fonts themselves are also defined as font stacks, which is why we get
sans-serif defined here as well. Because that is the fallback for arial,
the font we actually selected.

Add your own fonts

To add your own font, you create a folder named after your font and add an
index.scss file that defines the font. Inside that file, you @use the fonts
you will use as fallback.

As an example, lets imagine we want to define our own font ‘comic-sans’ based
on this font stack:

  --comic-sans: "Comic Sans MS", "Comic Sans", "Comic Neue", cursive;

To turn this into a native-font, we would create this .scss file:

fonts/comic-sans/index.scss

@use "sass:meta";
@use "native-font";
@use "native-font/cursive";

$name: 'comic-sans';
$title: 'Comic Sans';
$ref: 'https://example.com/fonts/comic-sans';
$fallback: cursive.$name;
$font: native-font.add($name, meta.inspect((
  'Comic Sans MS',
  'Comic Sans',
  'Comic Neue',
  var(--#{$fallback}),
)));

Now, you can use your comic-sans font like this:

@use "native-font";
@use "./fonts/comic-sans";

:root, ::backdrop {
  @include native-font.variables();
}

h1 {
  font-family: var(--comic-sans);
}

Which generates this CSS:

:root,
::backdrop {
  --color-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  --cursive: cursive, var(--color-emoji);
  --comic-sans: "Comic Sans MS", "Comic Sans", "Comic Neue", var(--cursive);
}

h1 {
  font-family: var(--comic-sans);
}

Note how --comic-sans uses --cursive as a fallback, which in turn uses
--color-emoji as a fallback. This increases emoji support for some fonts on
some devices, by explicitly falling back to some popular fonts with known
good emoji support for characters missing from the target font.

Available fonts (by set)

w3c

@use "native-font/sets/w3c";

Contains 14 fonts (± 1.4kB, ~800 bytes gzipped):

base

@use "native-font/sets/base";

Contains 17 fonts (± 1.5kB, ~840 bytes gzipped), all 14 from w3c, plus these 3:

  • emojicon
  • ui-emoji
  • ui-emojicon

modern

scss

@use "native-font/sets/modern";

Contains 28 fonts (± 2.6kB, ~1.2kB gzipped), all 17 from base, plus these 11:

cssfonts

scss

@use "native-font/sets/cssfonts";

Contains 64 fonts (± 5.3kB, ~1.8kB gzipped), all 17 from base, plus these 47:

extra

scss

@use "native-font/sets/extra";

Contains 65 fonts (± 5.3kB, ~1.8kB gzipped), all 64 from cssfonts, plus this 1:

  • comic-sans

all

scss

@use "native-font/sets/all";

Contains 76 fonts: (± 6.4kB, ~2.0kB gzipped)

About the extra fonts in base

The base font set adds three extra font names to the set defined
by w3c. Here is the reasoning behind these additions.

ui-emoji

Traditionally, the standard font names defined by w3c, such as sans-serif,
are used as fallbacks in font stacks to indicate the type of family of font
we would like to get when the main font is not available. The standard font
emoji fits in this category of fallback fonts. However, recently we have
seen a desire amongst web designers to communicate the intention of ‘give us
the font that the host system uses for UI’. So instead of trying to specify
in generic terms which fallback font we want, we would like to say quitte
specifically actually that we want ‘the ui font’. so we are not talking about
a fallback scenario here. And indeed we tend to specify fonts like system-ui
and ui-monospace at the start of the font stack, instead of at the end.

For this reason I find it strange that there is no ui-emoji, even though we
did get ui-serif, ui-sans-serif and ui-monospace. Just like with the other
ui-* fonts, ui-emoji would be intended to say ‘the font the host system UI
uses for emoji’, instead of the much more generic ‘a font intended for emoji’.
So base adds ui-emoji for completeness.

emojicon

Emojis are somewhat of an oddity amongst the other characters and symbols, because
normally characters are not colored by themselves. Text is usually monochrome in
nature and we apply color via CSS rules like color: green;. However Emoji are
different. These characters often do get colors and usually don’t respond to the
color CSS rule. Icon fonts on the other hand use the fact that characters usually
are monochrome and only get color through CSS to allow designers to display the same
icon in many different colors just like they can do with text.

Noto Emoji is a recent example of a font that specifically adresses this, by offering
all the Unicode emoji as monochrome icons that can be colored by CSS rules.

I think it would be convenient to be able to express the idea of ‘icons based on
emoji’. Its not just an emoji font. Its an emoji font specifically for
icons. Hence the contraction emojicon. i wrote
a blog post
about this idea and I am taking the liberty of introducing it in this library in the hope
that other developers will be able to build on it so we can work towards portable icons
on the web together.

ui-emojicon

The font the host OS uses for displaying emojicon.
Adding this font seems like the consistent choice to make. Don’t expect too much in
terms of support but it is here and we can tune it in the future.

v0.3.3[beta]