Drawing with CSS

Wenting Zhang has this great video where she gives an introduction to drawing with CSS. She created an icon set in CSS, which doubles as a great learning resource.

She mentions that she decided to create CSS Icon because she wanted to leverage CSS animations. What I don't understand about the whole drawing with CSS movement is why not use SVG instead.

I looked into this because I had been seeing many examples of people drawing amazing things on CodePen using CSS. I was blown away by this Simpson's collection.

CSS3 Patterns Gallery is a great resource to learn how to produce CSS-only background and filler patterns. Great for mastering the background property, CSS gradients and the creative use of color and transparency.

CSSBattle. CSS code-golfing. Replicate targets with the smallest possible code. It's great deliberate practice although only for a subset of CSS. You also won't be using in production many of the tricks and hacks that you'll learn to keep the code small, but it's a lot of fun and it will get you to master positioning, pseudo-elements, backgrounds, borders, box-shadows and many others.

Agathe Cocco has a three-part series on drawing with CSS (1, 2 and 3).

CSS-in-JS

Using system fonts

Triggered by "The New System Font Stack?", I decided to look into using that on my web projects. That article suggests using the following snippet:

css
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
}

That's from September 2016, inspired by WordPress 4.6, so it's a bit out of date. In September 2017, CSS-Tricks provides a similar stack but gives this warning:

This method should only be used on the font-family property instead of the font shorthand. Booking.com published a thorough write-up on the warnings it generates due to the leading font appearing to be a vendor prefix.

They also mention an alternative interesting strategy, using @font-face:

css
/* Define the "system" font family */
@font-face {
font-family: system;
font-style: normal;
font-weight: 300;
src: local('.SFNSText-Light'), local('.HelveticaNeueDeskInterface-Light'),
local('.LucidaGrandeUI'), local('Ubuntu Light'), local('Segoe UI Light'),
local('Roboto-Light'), local('DroidSans'), local('Tahoma');
}
/* Now, let's apply it on an element */
body {
font-family: 'system';
}

Using the system-font.css you can use eight variations of the system-ui font family; light (300) light italic, normal (400), normal italic, medium (500), medium italic, bold (700), and bold italic. Like this:

css
body {
font-family: system-ui;
}
blockquote {
font: italic 300 system-ui;
}
p {
font: 400 system-ui;
}

Note that in the previous two cases, the font faces system and system-ui were being defined in the accompanying CSS. On the other hand, system-ui was added as a possible value for the font-family property in CSS. It seems decently supported.

It seems appropriate to use the following:

css
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;

But this, so W(ho)TF knows. I just checked Bootstrap and they use this:

css
font-family: -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';

Loading fonts

To read: Web Font Optimization.

This article gives a great overview of strategies to improve the loading of Google Fonts. Some of the tips apply to fonts in general.

We typically load Google Fonts by adding this piece of markup:

html
<link
href="https://fonts.googleapis.com/css?family=Muli:400"
rel="stylesheet"
/>

That returns a stylesheet full of @font-face declarations like this one:

css
@font-face {
font-family: 'Muli';
font-style: normal;
font-weight: 400;
src: local('Muli Regular'), local('Muli-Regular'),
url(https://fonts.gstatic.com/s/muli/v12/7Auwp_0qiz-afTzGLQjUwkQ1OQ.woff2)
format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

This tries to load fonts locally if they're available, before going to fonts.gstatic.com. That's not too bad, specially considering that Google's severs are good, but we have a couple of problems with this approach:

  1. We're performing a minimum of 2 separate requests to different hosts - first for the stylesheet at fonts.googleapis.com, and then to a unique URL for each font hosted at fonts.gstatic.com.

  2. We have no control over flash-of-invisible-text (FOIT) and flash-of-unstyled-text (FOUT) while fonts are loading. Setting the font-display property in the @font-face would give us that control, but it’s defined in the Google Fonts stylesheet.

  3. Finally, while rare, if Google Fonts is down, we won’t get our fonts. If our own CDN is down, then at least we are consistently delivering nothing to our users, right?

Two strategies are suggested. At the very least, warm up the DNS lookup, TCP handshake, and TLS negotiation to fonts.gstatic.com with preconnect:

html
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin />
<link
href="https://fonts.googleapis.com/css?family=Muli:400"
rel="stylesheet"
/>

Alternatively, self-host. Use google-webfonts-helper and follow instructions.

“Modern Browsers” will give you WOFF and WOFF2 formats while “Best Support” will also give you TTF, EOT, and SVG. A reasonable option is to chose to only host WOFF and WOFF2 while selecting system fonts as fallbacks for older browsers.

In your pages, use preload for fonts that you're sure you'll be using: "Preload is a declarative fetch, allowing you to force the browser to make a request for a resource without blocking the document’s onload event." (Preload, Prefetch And Priorities in Chrome).

All the browsers that support preload also support WOFF2 so we can safely choose only WOFF2.

html
<link
rel="preload"
as="font"
type="font/woff2"
href="./fonts/muli-v12-latin-regular.woff2"
crossorigin
/>
<link
rel="preload"
as="font"
type="font/woff2"
href="./fonts/muli-v12-latin-700.woff2"
crossorigin
/>
  • rel="preload" tells the browser to declaratively fetch the resource but not “execute” it (our CSS will queue usage).

  • as="font" tells the browser what it will be downloading so that it can set an appropriate priority. Without it, the browser would set a default low priority.

  • type="font/woff2 tells the browser the file type so that it only downloads the resource if it supports that file type.

  • crossorigin is required because fonts are fetched using anonymous mode CORS.

If you’re okay with FOUT, or flash of unstyled text, then we can fix FOIT by adding font-display: swap; to our @font-face declarations. More info in this glitch. It explains the use of the font-display property:

  • Font loading follows three stages: block, swap, failure.

  • font-display is applied per font-face.

  • font-display: block produces FOIT but is good in cases where your font branding is important and you don't want people to see you site with fallback fonts.

  • font-display: swap produces FOUT, the text is shown immediately in the fallback font until the custom font loads.

  • font-display: fallback somewhere in between block and swap. The text is invisible for a short period of time (100ms). Then if the custom font hasn't downloaded, the text is shown in a fallback font (for about 3s), then swapped after the custom font loads.

  • font-display: optional like fallback but the browser can decide to not use the custom font at all, based on the user's connection speed.

subfont is a command line tool to optimize your webfont loading. Aggressive subsetting based on your font use, self-hosting of Google fonts and preloading. If you're cool, you use Gatsby and life's good: there's a plugin for that.