Web Standards

Keen is an analytics tool that makes it wonderfully easy to collect data. But Keen is unique in that it is designed not just to help you look at that data, but to share that data with your own customers! Customer-facing metrics, as it were.

Keen works just the way you would hope: it's super easy to install, has great docs, makes it very easy to customize to collect exactly what you need, and crucially, it is just as easy to query it and get the data you want to build the visualizations you need. As I'm sure you well know: you only improve what you measure, and what you measure is unique to your business and your customers.

Doesn't it tickle your brain a little? What kind of metrics might your customers want to see in relation to your app? What kind of features might they pay for?

The idea of Customer-Facing Metrics is that you can deliver personalized data to your user right through the front-end of the app. It could be the fundamental offering of your app! Or it could be a bonus paid feature, a lot of people love looking at their numbers! Imagine a social platform where users are able to see their most popular content, check the sources of the traffic, and explore all that through time and other filters.

Customer facing data, powered by Keen

Have you ever seen an incredible data visualization and imagined how that could be useful in your own app? You can probably follow a tutorial to help you build the visual part, but those tutorials generally assume you already have the data and skip over that part. Keen helps you with the hard part: collecting, storing, and querying all that data. Not to mention scales as you do.

Charts from Quartz, powered by Keen

Part of the beauty of Keen is how easy it is to get started. It works in whatever stack you've got in any language. Just a few lines of code to get up and running and get a proof of concept going.

In fact, if you're using Keen for the web, you might be interested in the Auto-Collector, which means you don't have to configure and send events manually, it will collect all pageviews, clicks, and form submissions automatically. That's particularly nice as you can answer questions you might have instantly, because you've already collected the information, you don't need to configure new collections and then wait. This is particularly great to help you get a proof-of-concept up very quickly and start figuring out things that your customers are sure to be interested in.

Here’s a great post by Roman Komarov on what he learned by improving the performance of his personal website. There’s a couple of neat things he does to tackle font loading in particular, such as adding the <link rel="preload"> tags for fonts. This will encourage those font files to download a tiny bit faster which prevents that odd flash of un-styled text we know all too well. Roman also subsets his font files based on language which I find super interesting – as only certain pages of his website use Cyrillic glyphs.

He writes:

I was digging into some of the performance issues during my work for a few weeks, and I thought that it can be interesting to see how those could be applied to my site. I was already quite happy with how it performed (being just a small static site) but managed to find a few areas to improve.

I had also never heard of Squoosh, which happens to be an incredible image optimization tool that looks like this when you’re editing an image:

With that slider in the middle, it shows the difference between the original image and the newly optimized one, which is both super neat and helpful.

Well done, Mark Boulton, John Allsopp, Kimberly Blessing, Jeremy Keith, Remy Sharp, Craig Mod, Martin Akolo Chiteri, Angela Ricci, and Brian Suda! I love that it was written in React and the font is an actual replication of what was used back then. What a cool project.

Well, I had seen this pattern so often that I thought Custom Properties could only be used for color values like rgba or hex – although that’s certainly not the case! After a little bit of experimentation and sleuthing around, I realized that it’s possible to use Custom Properties to set image paths, too.

Kinda neat, huh? I think this could be used to make an icon system where you could define a whole list of images in the :root and call it whenever you needed to. Or you could make it easier to theme certain classes based on their state or perhaps in a media query, as well. Remember, too, that custom properties can be overridden within an element:

I love posts like this. It's just about adding a little icon to the end of certain links, but it ends up touching on a million things along the way. I think this is an example of why some people find front-end fun and some people rather dislike it.

Things involved:

Cool [attribute] selectors that identify off-site links

Deliberating on whether it's OK to use additional HTML within links or not

Usage of white-space

Combining margin-left and padding-right to place icons into placeholder space

How do we avoid the most common mistakes when it comes to setting type on the web? That’s the question that’s been stuck in my head lately as I’ve noticed a lot of typography that’s lackluster, frustrating, and difficult to read. So, how can we improve interfaces so that our content is easy to read at all times and contexts? How do learn from everyone else’s mistakes, too?

These questions encouraged me to jot down some rules that are easy to apply and have the greatest impact on legibility, based on my own personal experience. And, if you didn't know, I'm kinda a geek when it comes to typography. So, I thought I'd share the following six rules that I've come to adopt to get us started.

Rule #1: Set a good max-width for paragraphs

This is typically referred to as the measure in typographic circles and highly esteemed typographers will recommend that a paragraph have a width of around 75 characters for legibility reasons. Anything longer than that becomes difficult to read and causes unnecessary strain on the eyes because of the distance the eye has to travel left-to-right and back again (assuming ltr that is).

Here’s a quick example of a good max-width setting for a paragraph. Oh, and make sure to check out this demo on larger screen devices.

Now, this all depends on a ton of factors that great designers contemplate when setting a paragraph. However, as web designers, the difficulty for us is that we have to make sure that paragraphs feel good in additional contexts, like on mobile devices, too. So, while this rule of ~75 characters is nice to have in our back pocket, it's most helpful when we’re trying to figure out the maximum width of our text block. More on this in a bit.

Also, I’d recommend setting that width on a container or grid class that wraps the paragraph instead of setting a max-width value on the paragraph element itself.

Otherwise, there may be moments in the future when there's a need for certain paragraphs to be bigger and have a wider measure (like for introductory paragraphs perhaps). In those situations, making a different container class that just handles the larger width of the elements inside them is a nice and modular approach.

I’ve found that by having a system of classes that just deals with the width of things encourages writing much less code but also much more legible code as well. Although, yes, there is more HTML to write but I’d say that’s preferable to a lot of whacky CSS that has to be refactored in the future.

In short: make sure to set a good max-width for our paragraphs but also ensure that we set the widths on a parent class to keep our code readable.

Rule #2: Make the line height smaller than you think

One problem I often see in the wild is with paragraphs that have a line height that’s just way too big. This makes reading long blocks of text pretty exhausting and cumbersome as each hop from one line to the next feels like an enormous jump.

On mobile devices this is particularly egregious as I tend to see something like this often:

For some reason, a lot of folks tend to think that paragraphs on smaller devices require a larger line-height value — but this isn’t the case! Because the width of paragraphs are smaller, line-height can be even smaller than you might on desktop displays. That’s because on smaller screens, and with smaller paragraphs, the reader’s eye has a much shorter distance to hop from the end of one line to the beginning of the next.

This demo certainly isn’t typographically perfect (there’s no such thing), but it’s much easier to read than the majority of websites I stumble across today. In this example, notice how the line-height is probably much smaller than you’re familiar with and see how it feels as you read it:

Another common mistake I frequently see is the use of very large margins on either side of a paragraph of text, it's often on mobile devices that make for blocks of text that are difficult to read like this:

Just — yikes! How are we expected to read this?

Instead try using no more than 10-15px of margin on either side of the paragraph because we need to ensure that our paragraphs are as wide as possible on smaller devices.

I even see folks bump the font-size down on mobile to try and have a nice paragraph width but I’d highly recommend to avoid this as well. Think of the context, because mobile devices are often held in front of the user's face. There's no need to force the user to bring the device any closer to read a small block of text.

Most of the time, smaller margins are the better solve.

Rule #4: Make sure that the type isn’t too thin

This is perhaps my biggest complaint when it comes to typography on the web because so many websites use extraordinarily thin sans-serif typefaces for paragraph text. This makes reading difficult because it’s harder to see each stroke in a letter when they begin to fade away into the background due to the lack of contrast.

Try and read the text there. Do you notice yourself struggling to read it? Because we’re using the light weight of Open Sans in this example, letterforms start to break apart and fall to bits. More focus is required to read it. Legibility decreases and reading becomes much more annoying than it really has to be.

I recommend picking a regular weight for body text, then trying to read a long string of text with those settings. Thin fonts look cute and pretty at a glance, but reading it in a longer form will reveal the difficulties.

Rule #5: Use bold weights for headings

Clear hierarchy is vital for controlling the focus of the reader, especially in complex applications that show a ton of data. And although it used to be more common a couple of years ago, I still tend to see a lot folks use very thin weights or regular weights for headings on websites. Again, this isn’t necessarily a die-hard rule — it’s a suggestion. That said, how difficult is it to scan this headline:

It’s a little difficult to see in this example but it's easy to missing the headline altogether in a large application with lots of UI. I’ve often found that inexperienced typographers tend to create hierarchy with font-size whilst experienced typographers will lead with font-weight instead.

In this example, I’ve set the paragraph text to a dark gray and the heading to a color closer to black while applying a bold weight. It’s not a substantial change in the code but it’s an enormous improvement in terms of hierarchy.

Little improvement like this will quickly add up to a better experience overall when the user is asked to slog through a ton of text.

Rule #6: Don’t use Lorem Ipsum to typeset a page

I think this advice might be the most underrated and I rarely hear it raised in front-end, typography, or design groups. I’ve even noticed seasoned designers struggle to typeset a page because Lorem Ipsum is used for the placeholder content, which makes it impossible for to gauge whether a paragraph of text is easy to read or not.

Instead, pick text that you really enjoy reading. Ideally, typesetting would be done with finalized content but that's often a luxury in front-end development. That's why I’d recommend picking text that sounds close to the voice and tone of the project if there's a lack of actual content.

Seriously though, this one change will have an enormous impact on legibility and hierarchy because it encourages reading the text instead of looking at it all aesthetically. I noticed a massive improvement in my own designs when I stopped using undecipherable Lorem Ipsum text and picked content from my favorite novels instead.

And that’s it! There sure are a lot of rules when it comes to typography and these are merely the ones I tend to see broken the most. What kind of typographic issues do you see on the web though? Let us know in the comments!

Taimur Abdaal leads design at Retool, a fast way to build internal tools. They're working on a new design system for their platform, to let anyone easily build beautiful custom apps. Typography will be a huge part of this and Taimur wrote this based on that experience.

You may have read the title for this post and thought, "Why on earth does a developer need to know anything about typography?" I mean, there’s already a lot on your plate and you’re making hundreds of decisions a day. Should you use React or Vue? npm or Yarn? ES6 or ES7? Sadly, this often leaves something like type as an afterthought. But, let’s remember that web design is 95% typography:

95% of the information on the web is written language. It is only logical to say that a web designer should get good training in the main discipline of shaping written information, in other words: Typography.

Even though we deal with content everyday — whether reading, writing, or designing it — typography can be daunting to delve into because it’s filled with jargon and subjectivity, and it’s uncommon to see it taught extensively at school.

This is intended as a practical guide for developers to learn web typography. We’ll cover a range of practical and useful topics, like how to choose and use custom fonts on the web, but more importantly, how to lay text out to create a pleasant user experience. We’ll go over the principles of typography and the CSS properties that control them, as well as handy tips to get good results, quickly.

What is typography?

First and foremost, typography is about usability. Type is the user interface for conveying information, and conveying information is what we’re here to do on the web. There are many levers we can pull to affect the usability of reading text, and only by being deliberate about these can we create a pleasant experience for our users.

After (and only after) usability, typography is about emotion. Do the letters complement your content, or contradict it? Do they amplify your brand’s personality, or dampen it? Applied to the same text, different type will make people feel different things. Being deliberate about typography lets us control these feelings.

Same text, different personalities. I’ll bet the first experience is much more expensive. Typefaces: Bodoni 72 (Top), Tsukushi A Round Gothic (Bottom)

Despite what many golden ratio enthusiasts might try to tell you, typography isn’t an exact science. Good guidelines will get you most of the way there, but you’ll need to apply a little intuition too. Luckily, you’ve been reading text your whole life — books, magazines, the Internet — so you have a lot more untapped intuition than you think!

What’s in a font?

Let’s start off by getting a handle on some basic terminology and how fonts are categorized.

Typeface vs. Font

This is how the two have traditionally been defined and distinguished from one another:

Typeface: The design of a collection of glyphs (e.g. letters, numbers, symbols)

In essence, a typeface is like a song and a font is like its MP3 file. You’ll see both terms used in typography literature, so it’s worth knowing the distinction. "Font vs. Typeface" is also a bit of meme in the design community — you might see it crop up on Twitter, so it’ll help to be "in the know."

HOW 2 MAJOR IN GRAPHIC DESIGN:- CHOOSE A FONT- "ITS CALLED A TYPEFACE NOT A FONT"- CHOOSE A GODDAMN TYPEFACE- U MADE THE WRONG CHOICE

But, more recently, you can essentially use both terms interchangeably and people will know what you mean.

How fonts are categorized

The broadest split is between serif and sans-serif typefaces. It’s likely you’ve come across these terms just by seeing some some typeface names floating around (like, ahem, Comic Sans).

A "serif" is a small stroke attached to the ends of letters, giving them a traditional feel. In fact, most books and newspapers are set in serif typefaces. On the contrary, sans-serif typefaces don’t have these extra strokes, giving them a smooth, modern feel.

Times (left) and Helvetica Neue (right)

Both serif and sans-serif have categories within them. For example, serif has sub-categories including didone, slab and old style.

Didot (left), Rockwell (center) and Hoefler Text (right)

As far as sans-serif goes, it includes humanist, geometric and grotesk as sub-categories.

Gill Sans (left), Futura (center) and Aktiv Grotesk (right)

Monospace fonts (yes, fonts) are a noteworthy category all its own. Each glyph (i.e. letter/number/symbol) in a monospace font has the same width (hence the mono spacing terminology), so it’s possible to arrange them into visual structures. You may be well familiar with monospace because we see it often when writing code, where it’s helpful to make brackets and indents line up visually. The code editor you have open right now is likely using monospace.

Monaco
How to choose fonts and font pairings

This is subjective, and depends on what you’re trying to do. Each typeface has its own personality, so you’ll have to find one that aligns with your brand or the content it’s communicating. Typefaces have to be considered within the context that they’re being applied. Are we looking for formality? Maybe start with the serif family. Warm, fun and friendly? That might be a cue for sans-serif. Heck, there’s a time and a place even for Comic Sans… really! Just know that there is no hard science to choosing a font, and even the most trained of typographers are considering contextual cues to find the "right" one.

But fonts can be paired together in the same design. For example, some designs use one typeface for headings and another for body text. This is a good way to get a unique look, but it does take a fair bit of work to get it right. Like colors in a palette, some typefaces work well together while others clash. And even purposeful clashing can make sense, again, given the right context.

The only way to find out if two fonts are complementary is to see them together. Tools like FontPair and TypeConnection can help with this. If a font catches your eye when surfing the web, WhatFont is a great browser extension to help identify it. Another great resource is Typewolf which allows you to see examples of great web typography, including different font combinations in use:

If you’re building a complex web app UI, you might need a range of font weights to establish hierarchy in different contexts. For something less complex, say a blog, you’ll likely be fine with just a couple.

It's still early days — there aren't many variable fonts available right now, and browser support is limited. But definitely a space worth watching!

Consider the legibility of a font

Some typefaces are harder to read than others. Stay away from elaborate fonts when it comes to paragraphs, and if you must have tiny text somewhere, make sure its typeface is legible at those tiny sizes.

Of these two examples, which is easier on the eyes? (There is a right answer here. &#x1f642;)

Making a font bold isn’t as simple as adding an outline to the text, and italics are more than slanted letters. Good fonts have specific bold and italic styles, without which the browser tries to "fake" it:

What we’ve looked at so far are the high level characteristics and features of fonts that can help us decide which to choose for a particular design or context. There are many other things that can (and probably should) be taken into consideration, including:

Language support: Some fonts have glyphs for foreign characters, which may be a requirement for a project geared toward a multilingual audience or that contains multilingual content.

Ligatures: Some fonts (typically serifs) have glyphs to replace otherwise awkward characters, like ? and ? which are multiple characters in a single glyph.

File size: You’re a developer, so I know you care about performance. Some fonts come in bigger files than others and those can cause a site to take a hit on load times.

Using fonts on the world wide web

A mere 10 years ago, there were two complex ways to use custom fonts on the web:

SiFR: Embedding a Flash (remember that thing?) widget to render text.

cufon: converting the font to a proprietary format, and using a specific JavaScript rendering engine to generate the text using VML on an HTML <canvas>.

Today, there’s all we need is a single simple one: @font-face. It lets you specify a font file URL, which the browser then downloads and uses on your site.

Even though @font-face is light years ahead of the old school approaches to custom web fonts, there is quite a bit to consider as far as browser support goes. Here’s a guide to getting the right amount of cross-browser support.

The impact of fonts on performance

Performance is the only downside to using custom fonts on the web. Fonts are relatively large assets — often hundreds of kilobytes in size — and will have and adverse effect on the speed of any site.

One tool that can help tailor a font file to suit your needs is Transfonter. Just make sure you have the rights to any font that you want to use on your site because, well, it’s just the right thing to do.

Some services will host web fonts for you

One other significant way to shed some of the weight of using custom web fonts is to use a service that will host and serve them for you. The benefit here is that third-parties store the files on a speedy CDN, optimize them, and serve them to your site via a JavaScript snippet that gets dropped into the document head. In short: it takes a lot of hassle off your hands.

How easy is it to use a hosted service? Consider that using anything on Google Fonts only requires a single <link> in the HTML head:

This example was taken from Google Fonts — the most popular hosted font service. It’s free to use, and, at the time of writing, has a catalogue of 915 font families. The quality of these can be hit-or-miss. Some are truly top-notch — beautiful design, many weights, true bold/italics, and advanced features like ligatures. Others, typically the more novel designs, are bare-bones, and might not be suitable for serious projects with evolving needs.

Adobe Fonts is also very popular. It comes bundled with Adobe’s Creative Cloud offering, which starts at $20.99 per month. At the time of writing, it has a catalogue of 1,636 font families. These are typically high quality fonts that you’d have to pay for, but with Adobe Fonts, you can access them all in a Netflix all-you-can-eat model.

Here are some other options:

Adobe Edge Web Fonts: This is the free version of Adobe Fonts. Adobe partnered with Google on this, so there’s a lot of overlap with the Google Fonts library. It has 503 font families in total.

Fontspring: This is a massive library of over 14,000 font families, but with an individual licensing model. This means paying more up-front, starting at ~$20 per individual font (and per weight or style), but no recurring costs. It’s also self-serve — you’ll have to host the files yourself.

MyFonts by Monotype: This is major type foundry. Similar to Fontspring: massive library of font families with an individual licensing model.

Fonts.com: This is similar to Fontspring. Options for one-off or pay-as-you go pricing (based on page views).

Cloud.typography by Hoefler&Co: This is a major type foundry. Over 1,000 font families (all by Hoefler&Co), with options for hosted (subscription, starting at $99 per year) or self-hosted (individually licensed) web fonts. The benefit here is that you get access to a library of fonts you cannot find anywhere else.

Fontstand: This services allows you to "rent" individual fonts cheaply on a monthly basis, starting ~$10 per month), which you get to own automatically after 12 months. To date, it boasts 1,500 families, with a hosted web font service.

CSS and Typography

OK, let’s move on to the intersection of design and development. We’ve covered a lot of the foundational terms and concepts of typography, but now we can turn our attention to what affordances we have to manipulate and style type, specifically with CSS.

Adjusting font sizing

Changing the size of a font is something that inevitably pops up in a typical project. Size is important because it creates hierarchy, implicitly guiding the user through the page. So, in this section, we’re going to look at two CSS features that are available in our tool belt for adjusting font sizes to create better content hierarchy.

Sizes can be expressed in a different units of measure

Did you know that there are 15 different units for sizing in CSS? Crazy, right? Most of us are probably aware of and comfortable working with pixels (px) but there are so many other ways we can define the size of a font.

Some of these are relative units, and others are absolute. The actual size of an element expressed in relative units depends on other parts of the page, while the actual size of an element expressed in absolute units is always the same. And, as you might expect, that difference is important because they serve different functions, depending on a design’s needs.

Of the 15 units we have available, we will selectively look at two in particular: px and em. Not only are these perhaps the two most used units that you’ll see used to define font sizes, but they also perfectly demonstrate the difference between absolute and relative sizing.

First off, px is an absolute unit and it actually doesn’t have much to do with pixels (it’s considered an angular measurement), but it’s defined so that a line of width 1px appears sharp and visible, no matter the screen resolution. The px value corresponds, roughly, to a little more than the distance from the highest ascender (e.g. the top of the letter A) to the lowest descender (e.g. the bottom of the letter p) in the font. Some fonts have taller letters than others, so 16px in one font might look noticeably "bigger" than 16px in another. Yet another consideration to take into account when choosing a font!

Interestingly enough, when it comes to typography, the px is a unit to be understood, but not used. The true purpose of px units is to serve as the foundation of a type system based on relative units. In other words, it’s an absolute value that a relative unit can point to in order to define its own size relative to that value.

Which takes us to em, a relative unit. Text with a font size of 2em would be twice as big as the font-size of its parent element. The body doesn’t have a parent element, but each device has its own default font-size for the body element. For example, desktop browsers usually default to 16px. Other devices (e.g. mobile phones and TVs) might have different defaults that are optimized for their form factors.

The em lets you reason about your typography intuitively: "I want this title to be twice as big as the paragraph text" corresponds directly to 2em. It’s also easy to maintain — if you need a media query to make everything bigger on mobile, it’s a simple matter of increasing one font-size attribute. Dealing in em units also lets you set other typographical elements in relation to font-size, as we’ll see later.

There are semantic HTML elements that CSS can target to adjust size

You’re sold on the em, but how many em units should each element be? You’ll want to have a range of text sizes to establish hierarchy between different elements of your page. More often than not, you’ll see hierarchies that are six level deep, which corresponds to the HTML heading elements, h1 through h6.

The right size scale depends on the use case. As a guideline, many people choose to use a modular scale. That refers to a scale based on a constant ratio for successive text elements in the hierarchy.

Example of a modular scale with a ratio of 1.4

Modular Scales is a tool by Tim Brown, who popularized this approach, which makes it easy to visualize different size scales.

Adjusting a font’s vertical spacing and alignment

The physical size of a font is a super common way we use CSS to style a font, but vertical spacing is another incredibly powerful way CSS can help improve the legibility of content.

Use line-height to define how tall to make a line of text

Line height is one of the most important factors affecting readability. It’s controlled by the line-height property, best expressed as a unit-less number that corresponds to a multiple of the defined font size.

Let’s say we are working with a computed font size of 16px (specified in the CSS as em units, of course), a line-height of 1.2 would make each line 19.2px tall. (Remember that px aren’t actually pixels, so decimals are valid!)

Most browsers default to a line-height of 1.2 but the problem is that this is usually too tight — you probably want something closer to 1.5 because provides a little more breathing room for your eyes when reading.

Here are some general guidelines to define a good line height:

Increase line-height for thick fonts

Increase line-height when fonts are a dark color

Increase line-height for long-form content

Increasing the line-height can drastically improve legibility
Fonts can’t dance, but they still have rhythm

Rhythm describes how text flows vertically on a page. Much like music, some amount of consistency and structure usually leads to good "rhythm." Like most design techniques, rhythm isn’t an exact science but there are some sensible guidelines that give good results.

One school of thought prescribes the use of paragraph line height as a baseline unit from which all other spacing is derived. This includes gaps between paragraphs and headings, and padding between the text and other page elements.

Under this system, you might set the line height of a heading to twice the line height of paragraphs, and leave a one-line gap between a heading and paragraph. Handily, you can use the same em units to define margins and padding, so there’s really no need to hard-code anything.

Hopefully you’re convinced by now that vertical spacing is an important factor in improving legibility that we can control in CSS. Equally important is the horizontal spacing of individual characters and the overall width of content.

CSS can control the space between letters

Letter spacing is one of the most important factors affecting legibility. It is controlled by the CSS letter-spacing property, best expressed (again) in em units to keep everything relative. Tracking (the typography term for "letter spacing") depends entirely on the font — some fonts will look great by default, while others might need a little tweaking.

In general, you only need to worry about letter spacing for text elements that are particularly big or small because most fonts are spaced well at a typical paragraph size.

For larger text, like headings and titles, you’ll often want to reduce the space between letters. And a little bit of space goes a long way. For example, -0.02em is a tiny decimal, but a good starting point, which can be tweaked until it looks just right to your eye. The only time you should think about increasing letter spacing is when dealing with stylistically unusual text — things like all-capped titles and even some number sequences.

Adding or subtracting as little as 0.02em can refine the appearance of words

Some specific pairs of letters, like AV, can look awkwardly spaced without a little manual tweaking. Well-crafted fonts typically specify custom spacing for such pairs, and setting the font-kerning property to normal lets you enable this. Browsers disable this on smaller text by default. Here is a little more on letter spacing, as well as other CSS tools we have to control font spacing in general.

The length of a line of text is more important than you might think

It’s unpleasant for our eyes to move long distances while reading, so the width of lines should be deliberate. General consensus is that a good width is somewhere between 60 and 70 characters per line. If you find that a line of text (especially for long-form content) drastically falls outside this range, then start adjusting.

The ch is a little-known CSS unit that we didn’t cover earlier, but can be helpful to keep line length in check. It’s a relative unit, defined as the width of the 0 character in the element’s font. Because narrow characters like l and i are relatively frequent, setting the width of a text container to something like 50ch should result in lines that are 60-70 character long.

p {
width: 50ch;
}
CSS can smooth otherwise crispy fonts

-webkit-font-smoothing is a nifty CSS property that controls how fonts are anti-aliased. This is a fancy way of saying it can draw shades of gray around otherwise square pixels to create a smoother appearance. Do note, however, the -webkit prefix there, because that indicates that the property is only supported by WebKit browsers, e.g. Safari.

The default setting is subpixel-antialiased, but it’s worth seeing what your type looks like when it’s set to just antialiased. It can improve the way many fonts look, especially for text on non-white backgrounds.

At small font sizes, this should be used with caution — it lowers contrast, affecting readability. You should also make sure to adjust letter-spacing when using this, since greater anti-aliasing will increase the space between letters.

Anti-aliased (left) Subpixel Anti-aliased (right)
Wrapping up

Phew! We covered a lot of ground in a relatively short amount of space. Still, this is by no means an exhaustive guide, but rather, something that I hope will encourage you to take more control over the typography in your future projects, and to seek an even deeper knowledge of the topic. For that, I’ve compiled a list of additional resources to help you level up from here.

Styling row and column gaps. I've also heard requested styling grid cells directly, rather than needing to place an element there and style that element.

Multiple gap values. I wanted this just the other week, and I was told to use an empty column or row instead of a gap. The size of that column can be controlled, and things are placed accordingly to treat it like a gap. Sort of OK, except that isn't particularly friendly to implicit grids.

Autoflow patterns. This is clever. Check out Michelle's use case and proposal.

calc() with the fr unit. This is a mindbender. I can see wanting to do something like calc(1fr - 100px), but then isn't the leftover space 100px short and 1fr recalcuated to fill that space? Seems infinite loopy.

Aspect ratio grid cells. I suspect, if we get this, it'll be a generic aspect ratio solution that will work on any element, including elements placed onto a grid.

Subgrid is also starting to be hotly requested, and I can see why. While building the last page layout I did using grid, I found myself strongly wishing I could share the overall page grid lines within sub-elements.

Rachel Andrew talked about its status about six months ago in CSS Grid Level 2: Here Comes Subgrid. I'm not sure where it's at now, but I don't think any browser is supporting it quite yet. (I'm not even sure if the spec is technically done.)

Brad put a point on the desire here:

Container queries and subgrid would make my design system work so much easier.

Define a grid and throw some components in there, then watch them snap into place to the parent grid and look great no matter what the container dimensions are.

If we combine subgrid with grid-template-areas within the cards (read my last post if you don't know about Grid Areas, it'll blow your mind), complex responsive card-based layouts become trivial.

The prospect of a subgrid on both axes gives us a way to sort of accomplish relative grid positioning, at least for semantically grouped items, like I wished I had above! Group your stuff in a container, position your container on the grid, make that container a subgrid on both axes, and declare your tracks relative to the subgrid element's grid position!

Between Flexbox, Grid, display: contents, and subgrids, we will finally have everything we need to write very slim, clean, semantic markup with basically no fluff or purely structural elements. It will be a huge boon for accessibility, SEO, and just developers trying to understand your markup!

This is why I’ve come to the same conclusion other grid experts (like Rachel) already have: subgrids are a major component of grid layout, and should be a part of any grid layout implementation when it emerges from developer-preview status. If that means delaying the emergence of grids, I think it’s worth it.

Not only has CSS Grid reshaped the way we think and build layouts for the web, but it has also contributed to writing more resilient code, replacing "hacky" techniques we've used before, and in some cases, killing the need to rely on code for specific resolutions and viewports. What's so cool about this era in web development is that we're capable of doing more and more with fewer lines of code.

In this article, we'll start dipping our toes into the power of CSS Grid by building a couple of common responsive navigation layouts. It's easier than what you may think, and since CSS Grid was built with responsiveness in mind, it'll take less code than writing media queries all over the place. Let’s do this!

We'll kick off this set of examples by creating a common website layout: A full-width hero section, with a grid of cards below.

Both elements will respond to window resizing and adapt accordingly. Though this might seem like a lot of code at first glance, the responsive behavior is done with only six lines of CSS Grid code, and without writing a single @media rule. Let's break down the code to see what's going on:

We have a bunch of background styles to enable the beer background, a bit of padding to separate the content from the edge of the screen, and then three lines of grid styles:

The first line (display: grid;) is changing the behavior of the .hero element to be a grid container. That means the elements inside .hero are now grid items.

The second line (align-items: center;) is going to vertically center the columns on our grid. But these two lines don't do anything on their own until we set the columns of our grid.

And that's where the third line comes in. A lot of stuff is going on in that single property, so let's go one step at a time.

The repeat() function

Generally speaking, what we usually do to define our columns and rows on a CSS Grid is to add the value for each track after defining the property, like this:

.element {
/* This will result on four columns, each one of 1fr */
grid-template-columns: 1fr 1fr 1fr 1fr;
/* This will result on two rows, each one of 300px */
grid-template-rows: 300px 300px;
}

Now, that's quite dull. We can use the repeat() function to make that less verbose and easier to follow. The function takes two parameters:

The number of times to repeat the value.

The value itself.

After refactoring our code to use repeat(), we should expect the same results from these lines of code:

.element {
/* this is the same as grid-template-columns: 1fr 1fr 1fr 1fr; */
grid-template-columns: repeat(4, 1fr);
/* this is the same as grid-template-rows: 300px 300px; */
grid-template-rows: repeat(2, 300px);
}

Much cleaner, yeah?

The minmax() function

Now, the above examples are explicitly defining sizes for the tracks (1fr and 300px). That might work for some scenarios, but for our beer example here, we need to be able to automatically calculate the size of the track, based on the width of the viewport, and automatically adjust the number of columns shown. To be able to do that, we'll define a range of values using the minmax() function. What will we be defining? You've probably guessed by now: The *minimum* and *maximum* values we want these columns to be able to resize to.

In the hero for our beer example above, we set our minmax() property to be 240px at its minimum size, and 1fr at its maximum size. fr units, if you've never heard of them, stand for fractional units. Nobody can explain them better than Jen Simmons on this video and Robin Rendle in this post.

Using the Firefox Grid Inspector to check the change on the track's size when resizing

That results in our tracks being 1fr when there's plenty of space on our viewport (aka desktop resolutions), and 240px when there's not enough space for both columns (like on mobile devices). That's why they nicely grow when we make our browser wider, since they're taking the remaining space and equally dividing it across the existing columns. Now, moving to the last piece of the puzzle!

The auto-fit keyword

The auto-fit keyword allows us to wrap our columns into rows when there's not enough space in our viewport to fit the 240px minimum value without overflowing the content. Sara Soueidan wrote an excellent article about auto-sizing columns using the auto-fill and auto-fit keywords, in case you want to dive a little deeper into what's going on under the hood. Now, with that last bit of code in place, we should be able to achieve this result:

The column is automatically wrapping when there's not enough space in the viewport
The article list

Now that we've thoroughly reviewed the behavior of the elements inside our hero element, it's likely that the first two lines of CSS code for the breweries list below it might already seem familiar to you:

That's right! We're using the exact same approach: On the first line we define our grid, on the second one we size our tracks using the same magic one-liner, and on the third line we set a gap for these columns. Nothing new under the sun, and what's really neat about this, is that our code is resilient enough to adjust the number of tracks and their sizes, according to the number of items we have inside our unordered list:

The grid responds to the change in the number of tracks, and adapts the layout

That's all, folks! A fully responsive website layout, using just six lines of CSS code. Not bad, huh? Make sure you check the source code and play around with this example on CodePen.

On this next example, we'll embrace the power of our newly learned combination of repeat(), auto-fit and minmax() to create this responsive image gallery. We'll also be sizing our tracks using grid-column and grid-row, and learning about the handy property:value combination of grid-auto-flow: dense; that allows us to change the default behavior of the elements that can't fit on our explicit tracks: Instead of wrapping themselves in new rows or columns, we'll make them fit into the unused spots on our grid. Let's get into the coding!

The grid setup

The grid is created using our familiar display: grid; property, where columns are defined using repeat(), auto-fit and minmax(). We also added a bunch rows with a repeat() function and defined a gap to our images, using grid-gap. But the new player here is the grid-auto-flow: dense;. We’ll get to it in a second.

We also created a repetition pattern using the nth-child() pseudo-selector to set different sizes for our tracks using grid-column and grid-row. Notice here that we’re using the span keyword to allow the selected item to occupy more than one column or row.

And finally, we'll make sure our images cover the entire area of its container, regardless if it's 1x, 2x or 3x, using object-fit: cover;. If you have never heard of object-fit, it works fairly similar to how background-image does, but with HTML <img> tags:

Now, the real deal here is grid-auto-flow: dense;. Check what happens when we take that out from our code:

Removing grid-auto-flow: dense; leads to inconsistent placement of the elements on the grid

See those holes on our beautifully crafted grid? That's because some of the elements on it are taking 2x or 3x spots, and when there isn't enough space on our tracks to fit them, they'll wrap into a new row, since that's the default behavior. By changing it from row to dense, we're telling the grid to fill any gaps we might have with elements that could fit them, regardless of their source order on the DOM.

That's why this technique might come especially handy for things like image galleries, but might not be suitable for other use cases where you might need to preserve the order of the markup. Feel free to play around with the CodePen demo to check the differences between where items are placed.

Now, on to the last demo, where we'll take advantage of the ability to nest grids to recreate this Trello Board. We'll be creating a grid to hold our four different columns, and inside of those, we'll create a child grid for our cards. Even though this example won't explore new properties or revolutionary methods, it'll help us to get a grasp on how easy it is to build complex layouts with a few lines of CSS code. This demo has a lot of extra code to achieve the styling of the Trello layout, so we’ll focus solely on the grid styles.

The columns

To create the four columns, we'll use display: grid; on the container and use our magical one-liner for our grid-template-columns. We'll also be defining a gap between them, and use align-items: flex-start; to ensure that our columns don't stretch to the bottom of the screen.

Now, the original Trello is not responsive by default: If you resize your browser on a Trello Board, you'll notice that you'll end up having a horizontal scroll on your columns, rather than wrapping them on a new row. We're not following that behavior here since we want to build responsive layouts, but in case you're curious, and want to emulate Trello's functionality, you can achieve that by adding two more lines of CSS code:

We learned about grid-auto-flow in our previous demo and discovered that it let us control how the auto-placement algorithm work, and how implicit elements should be added in the flow of the grid. The default behavior is row, meaning that any extra element that won't fit on our grid will wrap into a new line. We changed that to be dense on our previous demo, and we'll change it to be column on this one: That way, any new column added here will end up in an implicit column, and have a horizontal scroll. We'll also define a width for those auto-generated columns with the grid-auto-columns property.

Modifying the grid-auto-flow property will make this demo behave like the real-world Trello
The cards

For the cards grid, we'll use a similar approach. We'll display: grid; on the container. We won't define any columns here, since we don't want to have any, and we'll put grid-template-rows: auto; to use to avoid all cards having the same height — we want some of them to be bigger and some of them smaller, based on the type of content being added to them.

And, again, that's all folks! Two more lines to set a gap and a margin to the cards, and we're done! Everything else in the Pen is standard CSS to achieve the Trello look and feel.

So then... are media queries dead?

Back in the day, when we were building layouts using display: inline-block or floats, media queries made a lot of sense in order to change the size of our elements as the viewport got smaller. But now, with the incredibly powerful layouts that we're able to create with a couple of CSS lines, you might feel tempted to think that media queries are doomed. I strongly disagree with that: I believe that we should change the way we think about them, and therefore use them differently.

As Rachel Andrew stated about a year ago, we should use media queries to fix our layout when it breaks, rather than targeting devices: There are so many out there! With the advent of Media Queries Level 4 and 5, we're not only able to detect screen sizes now, but pointer types as well. As a result, we can dig into a user’s system preferences and adapt our code for those who prefer reduced motion or whether we should use inverted colors. That means media queries are not dead; on the flipside, I'd say it's an exciting time for using media queries, but we need to learn to use them right. In the meantime, building robust layouts using modern techniques such as Flexbox or CSS Grid, will save you a bunch of time, code, and headaches.

I am likely going to write a “CSS for JavaScripters” book, and therefore I need to figure out how to explain CSS to JavaScripters. This series of article smippets are a sort of try-out — pre-drafts I’d like to get feedback on in order to figure out if I’m on the right track.

Today we will attempt to describe the different mental models for CSS and JavaScript. Everybody agrees there is a difference, but nobody’s able to define exactly what that difference is. So let’s try.

(Also, at the last moment I switched from describing CSS as “context-based” to “state-based.” I hope that makes more sense, and it’s one of the points I’d like feedback on.)

CSS and JavaScript mental models

Programming CSS requires a different mental model than programming JavaScript. CSS is a declarative language, while JavaScript is an imperative language. (Also, it’s an open question whether CSS is a programming language at all. We’ll get back to that later, but for now we’ll pretend it is.)

Those who have experience with declarative languages such as Prolog, or even spreadsheets, will have the advantage over people who only know imperative languages, who may be confused by CSS at first, since it lacks many of the control structures they’re used to in JavaScript.

The differences go deeper, though. Fundamentally, JavaScript execution is time-based. That is, everything happens in the order prescribed by the program. There is a time, at the very start of execution, that a certain variable does not exist yet. Then it’s defined and assigned a value, and later that value is changed, and so on. An if-statement based on that variable will have different outcomes at different times.

Not so CSS. All CSS declarations get their value at the same time, and they all take effect at the same time. It is impossible for any CSS declaration to be applied earlier than any other CSS declaration. Declaration order matters, but any conflict is resolved immediately and doesn’t require (or even allow) control structures. The same CSS will always give the same result.

State-driven change

[Could I even say “state-based programming?”]

CSS does accept changes to the initial rendering of the page, but it is fundamentally state-driven. It can only react to a limited number of well-defined state changes in a web page. A good example is changing a background color on hover.
nav a:hover {
background-color: red;
}

When the link’s state changes (i.e. the mouse pointer hovers over it), CSS switches from one set of instructions to the other, and when the state changes back to no-hover, CSS switches back to the original instruction set.

First, something that’s so obvious that it’s hardly ever mentioned: JavaScript needs CSS in order to actually change the background color. It is impossible to do this in any other way. Conversely, the CSS declaration does not need JavaScript. When it comes to styling, CSS is more fundamental than JavaScript - closer to how browsers actually work, and thus much faster.

Next, JavaScript needs two statements instead of CSS’s one. It does not detect a state change automatically, as CSS does. Instead, you have to take it by the hand and guide it through all possible options, and make sure it notices not only the state change, but also the change back.

Then, JavaScript needs an extra control structure to make sure that the state change is detected on all links in the navigation instead of just one. This is not particularly difficult, but it needs to be done. Again, with its single selector CSS is more elegant.

Still, JavaScript has its advantages as well. Unlike CSS, JavaScript allows you to cancel the background change by adding an if-statement to determine whether the link background change should take place. In CSS you defined the styles to be applied in a state of hover, and those instructions are always followed. If you want more fine-grained control, JavaScript is the better solution.

Elegance vs control

More fine-grained control is not an end in itself. It all depends on the context. Sometimes, like in the background example, the simple, elegant, fast solution is better. In more advanced situations there comes a time when JavaScript, with its fine-grained control, becomes the better answer.

Keith Grant pointed out an interesting analogy. If we as humans wish to run, we just tell our body to run, and it obeys. We could deconstruct the act of running into its constituent parts like “raise left knee,” “raise left foot,” “advance left leg,” and so on, but that is much harder to do and we’d likely fall over, as this game shows.

In this analogy, the run command would be CSS, and the detailed foot-and-leg instructions would be JavaScript. The analogy is flawed, as all are, since as humans we’ll almost never operate in a context that requires us to deconstruct the act of running, while a web page might benefit from deconstructing the act of changing background colors. Still, the analogy might help you to understand the advantages of the CSS mental model better.

It doesn’t answer the most important question, though. When do we cross the line? When does JavaScript become the better option? In the end, that depends on your context, both the project you’re working on and your familiarity with CSS and JavaScript. Still, I have the feeling that JavaScripters who are unfamiliar with CSS tend to draw the line too early, and that their simpler use cases might be better served by a pure CSS solution.
The choice is yours

So the choice is yours. Elegant, but limited, state-driven simplicity versus controlled, but complicated, time-based execution. There is no right or wrong here — just a careful weighting of options and contexts.

Whatever you choose for a particular project, if you work with browsers you should have a basic understanding of both approaches. And if you want to master CSS you need to understand state-based programming and the mental model that goes with it.

Feedback

Badly formatted

https://twitter.com/ptrdo/status/1100425471802585088
This is a very good approach. Perhaps another aspect of declarative v imperative (assumed but not mentioned) is how declarative rule-setting defines characteristics which can be universal and prescribed without the elements needing to exist, while imperative expects an instance.

https://twitter.com/tabatkins/status/1100421543144841216
The bit about "needing an extra control structure" could use some slight expansion. You need a loop over all links inside of nav (itself probably obtained with a selector), then a mutation observer to *add* the listeners for new links and *remove* them if the link is moved.

State machines: https://medium.com/@DavidKPiano/css-animations-with-finite-state-machines-7d596bb2914a

https://adactio.com/links/14866
I’m not sure if I agree with describing CSS as being state-based. The example that illustrates this—a :hover style—feels like an exception rather than a typical example of CSS.

https://twitter.com/leifastrand/status/1100801652586659843
Declarative = you describe the intended outcome.
Imperative = you describe the steps to take.
JS devs often encounter something similar: use map, filter and reduce over a collection to define intended result, or imperatively define the steps to take as a for loop.

As an example, we will build a simple grid system based on flexbox. Grid systems play a vital role in responsive designs. However, building a grid system that is flexible and lightweight at the same time can be a tricky task. Let’s see what the common approaches towards grid systems are and how CSS custom properties can help us build them.

This is definitely much easier to work with. As we develop our grid further and, let’s say, would like to change it from 12 columns to 16 columns, all we have to do is to update a single variable (in comparison to dozens of classes and values). But... as long as our Sass is shorter and more maintainable now, the compiled code is identical to the first example. We are still going to end up with a massive amount of code in the final CSS file. Let’s explore what happens if we try to replace the Sass variables with CSS custom properties instead.

Building a grid system with CSS custom properties

Before we start playing with CSS custom properties, let’s start with some HTML first. Here’s the layout we’re aiming for:

It consists of three elements: a header, a content section and a sidebar. Let’s create markup for this view, giving each of the elements a unique semantic class (header, content, sidebar) and a column class which indicates that this element is a part of a grid system:

Our grid system, as before, is based on a 12-column layout. You can envision it as an overlay covering our content areas:

So .header takes all 12 columns, .content takes eight columns (66.(6)% of the total width) and .sidebar takes four columns (33.(3)% of the total width). In our CSS, we would like to be able to control the width of each section by changing a single custom property:

To make it work, all we need to do is write a rule for the .column class. Lucky for us, most of the work is already done! We can re-use the Sass from the previous chapter and replace the Sass variables with CSS custom properties:

The --columns variable is now declared inside of the .column rule. The reason is that this variable is not supposed to be used outside of the scope of this class.

The math equation we perform in the flex-basis property is now enclosed within a calc() function. Math calculations that are written in Sass are compiled by the preprocessor and don’t need additional syntax. calc(), on the other hand, lets us perform math calculations in live CSS. The equation always needs to be wrapped within a calc() function.

On a very basic level, that’s it! We’ve just built a 12-column grid system with CSS custom properties. Congratulations! We could call it a day and happily finish this article right now, but... we usually need a grid system that is a bit more sophisticated. And this is when things are getting really interesting.

Most times, we need layouts to look different on various screen sizes. Let’s say that in our case we want the layout to remain as it is on a large viewport (e.g. desktop) but have all three elements become full-width on smaller screens (e.g. mobile).

.content and .sidebar each hold two variables now. The first variable (--width-mobile) is a number of columns an element should take by default, and the second one (--width-tablet) is the number of columns an element should take on larger screens. The .header element doesn’t change; it always takes the full width. On larger screens, the header should simply inherit the width it has on mobile.

Now, let’s update our .column class.

CSS variables and fallback

To make the mobile version work as expected, we need to alter the .column class as follows:

Basically, we replace the value of the --width variable with --width-mobile. Notice that the var() function takes two arguments now. The first of them is a default value. It says: "If a --width-mobile variable exists in a given scope, assign its value to the --width variable." The second argument is a fallback. In other words: "If a --width-mobile variable is not declared in a given scope, assign this fallback value to the --width variable." We set this fallback to prepare for a scenario where some grid elements won’t have a specified width.

For example, our .header element has a declared --width-mobile variable which means the --width variable will be equal to it and the flex-basis property of this element will compute to 100%:

This works exactly as expected, but only for the content and sidebar, i.e. for the elements that have specified both --width-mobile and --width-tablet. Why?

The media query we created applies to all .column elements, even those that don’t have a --width-tablet variable declared in their scope. What happens if we use a variable that is not declared? The reference to the undeclared variable in a var() function is then considered invalid at computed-value time, i.e. invalid at the time a user agent is trying to compute it in the context of a given declaration.

Ideally, in such a case, we would like the --width: var(--width-tablet); declaration to be ignored and the previous declaration of --width: var(--width-mobile, 0); to be used instead. But this is not how custom properties work! In fact, the invalid --width-tablet variable will still be used in the flex-basis declaration. A property that contains an invalid var() function always computes to its initial value. So, as flex-basis: calc(var(--width) / var(--columns) * 100%); contains an invalid var() function the whole property will compute to auto (the initial value for flex-basis).

What else we can do then? Set a fallback! As we learned before, a var() function containing a reference to the undeclared variable, computes to its fallback value, as long as it’s specified. So, in this case, we can just set a fallback to the --width-tablet variable:

This will create a chain of fallback values, making the --width property use --width-tablet when available, then --width-mobile if --width-tablet is not declared, and eventually, 0 if neither of the variables is declared. This approach allows us to perform numerous combinations:

Now, we have a fully functional, flexible grid! How about adding some more breakpoints?

Adding more breakpoints

Our grid is already quite powerful but we often need more than one breakpoint. Fortunately, adding more breakpoints to our code couldn’t be easier. All we have to do is to re-use the code we already have and add one variable more:

One thing that doesn’t look that great in our code is that feedback chains are getting longer and longer with every breakpoint. If we’d like to tackle this issue, we can change our approach to something like this:

This code is doing exactly the same job but in a bit different way. Instead of creating a full fallback chain for each breakpoint, we set a value of each variable to the variable from the previous breakpoint as a default value.

Why so complicated?

It looks like we’ve done quite a lot of work to complete a relatively simple task. Why? The main answer is: to make the rest of our code simpler and more maintainable. In fact, we could build the same layout by using the techniques described in the previous part of this article:

In a small project, this approach could work perfectly well. For the more complex solutions, I would suggest considering a more scalable solution though.

Why should I bother anyway?

If the presented code is doing a very similar job to what we can accomplish with preprocessors such as Sass, why should we bother at all? Are custom properties any better? The answer, as usually, is: it depends. An advantage of using Sass is better browser support. However, using custom properties has a few perks too:

It’s plain CSS. In other words, it’s a more standardized, dependable solution, independent from any third parties. No compiling, no package versions, no weird issues. It just works (apart from the browsers where it just doesn’t work).

It’s easier to debug. That’s a questionable one, as one may argue that Sass provides feedback through console messages and CSS does not. However, you can’t view and debug preprocessed code directly in a browser, whilst working with CSS variables, all the code is available (and live!) directly in DevTools.

It’s more maintainable. Custom properties allow us to do things simply impossible with any preprocessor. It allows us to make our variables more contextual and, therefore, more maintainable. Plus, they are selectable by JavaScript, something Sass variables are not.

It’s more flexible. Notice, that the grid system we’ve built is extremely flexible. Would you like to use a 12-column grid on one page and a 15-column grid on another? Be my guest—it’s a matter of a single variable. The same code can be used on both pages. A preprocessor would require generating code for two separate grid systems.

It takes less space. As long as the weight of CSS files is usually not the main bottleneck of page load performance, it still goes without saying that we should aim to optimize CSS files when possible. To give a better image of how much can be saved, I made a little experiment. I took the grid system from Bootstrap and rebuilt it from scratch with custom properties. The results are as follows: the basic configuration of the Bootstrap grid generates over 54KB of CSS whilst a similar grid made with custom properties is a mere 3KB. That’s a 94% difference! What is more, adding more columns to the Bootstrap grid makes the file even bigger. With CSS variables, we can use as many columns as we want without affecting the file size at all.

The files can be compressed to minimize the difference a bit. The gzipped Bootstrap grid takes 6.4KB in comparison to 0.9KB for the custom properties grid. This is still an 86% difference!

Performance of CSS variables

Summing up, using CSS custom properties has a lot of advantages. But, if we are making the browser do all the calculations that had been done by preprocessors, are we negatively affecting the performance of our site? It’s true that using custom properties and calc() functions will use more computing power. However, in cases similar to the examples we discussed in this article, the difference will usually be unnoticeable. If you’d like to learn more about this topic, I would recommend reading this excellent article by Lisi Linhart.

Not only grid systems

After all, understanding the ins and outs of custom properties may not be as easy as it seems. It will definitely take time, but it’s worth it. CSS variables can be a huge help when working on reusable components, design systems, theming and customizable solutions. Knowing how to deal with fallback values and undeclared variables may turn out to be very handy then.

Thanks for reading and good luck on your own journey with CSS custom properties!

I have a habit of getting some hosting when I need a new WordPress site. That is, a self-installed, self-hosted WordPress.org site. That's served me well over the years. I like my control. But along with that control comes a certain level of extra responsibility that sometimes just isn't worth it.

Right from the get-go, I knew I wanted Email is Good to be as absolutely simple as could be. At the moment, I can't prioritize a fancy custom design or really any specialized functionality at all. All I want is a simple, clean blog in which to publish blog posts. And as powerful and flexible as WordPress is, it's still extra good at that use case.

Email is Good uses an untouched, stock copy of the TwentySixteen theme.

I'd like to move it over to WordPress.com, so that I don't have to deal with hosting, upgrades, backups, security... it'll just host my simple blog and I can unburden myself of that little spoonful of technical debt.

Their docs for this are there, but a little on the light side, so I'll document my process here.

There isn't really a one-click just suck everything over in one shot system. Instead, you set up the site on WordPress.com, deal with the domain, and import the content. It might feel a little weird, but this first step is just kinda re-setting up the basics:

Deal with the domain

By "domain", I mean the URL that you may already own. I own "email-is-good.com" which is what I want to continue to use.

During setup you can buy a domain (or get a free one! They'll give you a wordpress.com or .blog subdomain), but since I'm moving a site here, I'll select the option that I already own the domain.

My domain name is already registered on GoDaddy.com. I could just leave the domain name there and map the domain over to WordPress.com. I think that's generally a smart thing to do, but I wanted to try what seems to be the default which is transferring it over to WordPress.com.

Part of the beauty of transferring the domain is there is no settings to screw up, as it will be handled by WordPress.com

I went through a process of basically re-registering the domain with WordPress.com.

In order to actually transfer the domain, I had to go to GoDaddy and "unlock" the domain as well as request a transfer authorization code.

If you're transferring a domain, it can take a little while.

The note on the page above tells me it might take a full week to complete. It took me one day less. I got the success email on February 18th instead of 19th.

I did have to "flip the switch", as the email suggests, to use the WordPress nameservers.

But before I did, I made sure the new WordPress.com site had all the old content!

Exporting Content & Media

There is an export tool baked right into WordPress. Find it under Tools.

You'll get an .xml file as output. Mine was called:

emailisgood.wordpress.2019-02-12.xml

Importing Content & Media

On the WordPress.com side, there is a big Import option right in the sidebar. In those options, there is a WordPress option to choose.

Drag and drop the .xml file there.

Mine was pretty quick, but I imagine it could take a while. You'll even get an email when it's done.

All my content and media made the journey just fine!

Clean Up

I had to do a little cleanup here and there to get the site exactly as it was. My site is so basic, it was hardly any work, but it's worth knowing you might have to mop up a little. For example, the site already had a contact page, so I had to nuke the one that was imported (which was using a contact form plugin I didn't need any more anyway) and make sure it was all functional.

Another thing that didn't make the trip to the new site was the widgets. I had a sidebar with some widgets that I had to re-build, but that was no big deal. I literally copy-pasted the content from them from the old site before I flipped the switch.

So now! I've ditched a pile of technical debt. No more worrying about my SSL certifiate. No more having to manually follow up with any hosting company about downtime. Performance is largely in the hands of someone else.

I just have a simple site where I can write write write.

Video!

If it's helpful for you to watch me talk all this out, I've put it on YouTube:

Does anybody honestly like support ticketing systems? Users across the board are often united in their antipathy: from the support agent handling the ticket to the customer submitting it. After all,...

They are all stroke-based, so they can be beefed up or slimmed down as needed.

The stroke-linecap and stroke-linejoin properties can be adjusted, which presents an opportunity to make their edges sharper or more rounded. I often find icons that are close to what I want, but the weight isn't right or the edges are either too sharp or too round. This quick and easy configuration is awesome.

Any overflow value other than visible and no height is the enemy of child elements with position: sticky;. It's like that element is ready to stick when the parent scrolls, but it never does because the height is unconstrained. Adding a fixed height can solve the issue, but that's not always desirable.

Dannie Vinther digs into a way of dealing with that. The end result is avoiding that situation all together by removing the element that wants to be sticky from the element that needs an overflow. But as soon as you do that, the elements no longer scroll together since they aren't siblings. The use case here is a table with sticky headers on vertical scrolling and allowing for horizontal scrolling as well. Dannie uses a script to sync the scroll positions.

CSS custom properties (a.k.a. CSS variables) are becoming more and more popular. They finally reached decent browser support and are slowly making their way into various production environments. The popularity of custom properties shouldn’t come as a surprise, because they can be really helpful in numerous use cases, including managing color palettes, customizing components, and theming. But CSS variables can also be really helpful when it comes to responsive design.

Such an approach gives us an easy way to control CSS properties on different screen sizes. However, it may be hard to maintain as the complexity of a project grows. When using media queries, keeping code readable and DRY at the same time quite often turns out to be challenging.

The most common challenges when scaling this pattern include:

Repeated selectors: Apart from bloating code with multiple declarations, it also makes future refactoring more difficult, e.g. every time a class name changes it requires remembering to update it in multiple places.

Repeated properties: Notice that when overwriting CSS rules within media queries, it requires repeating the entire declaration (e.g. font-size: 3rem;) even though it’s just the value (3rem) that actually changes.

Repeated media queries: To keep responsive styles contextual, it’s a common practice to include the same media queries in multiple places, close to the styles they override. Unfortunately, it not only makes code heavier, but also might make breakpoints much harder to maintain. On the other hand, keeping all responsive styles in one place, away from their original declarations, may be very confusing: we end up with multiple references to the same elements sitting in completely different places.

We can argue that repeated declarations and queries shouldn’t be such a big deal with proper file compression enabled, at least as long as we’re referring to performance. We can also merge multiple queries and optimize your code with post-processing tools. But wouldn’t it be easier to avoid these issues altogether?

There’s a lot of ways to avoid the issues listed above. One of them, that we will explore in this article, is to use CSS custom properties.

Using CSS variables for property values

There are plenty of amazing articles on the web explaining the concept of CSS custom properties. If you haven’t got chance to get familiar with them yet, I would recommend starting with one of the beginner articles on this topic such as this awesome piece by Serg Hospodarets as we are not going to get into details of the basic usage in this article.

The most common way of utilizing CSS custom properties in responsive design is to use variables to store values that change inside of media queries. To accomplish this, declare a variable that holds a value that is supposed to change, and then reassign it inside of a media query:

Assigning variables to the :root selector is not always a good idea. Same as in JavaScript, having many global variables is considered a bad practice. In real life, try to declare the custom properties in the scope they will actually be used.

This way, we are avoiding multiple rules of the .foo class. We are also separating the logic (changing values) from the actual designs (CSS declarations). Adapting this approach in our example from above gives us the following CSS:

Notice that the use of variables in shorthand properties (e.g. padding, margin or font) allow some very interesting repercussions. As custom properties may hold almost any value (more on this later), even an empty string, it’s unclear how the value of a shorthand property will be separated out into longhand properties that are used in the cascade later. For example, the auto used in the margin property above may turn out to be a top-and-bottom margin, a left-and-right margin, a top margin, a right margin, a bottom margin or a left margin — it all depends on the values of the custom properties around.

It’s questionable whether the code looks cleaner than the one from the previous example, but on a larger scale, it’s definitely more maintainable. Let’s try to simplify this code a bit now.

Notice that some values are repeated here. What if we try to merge duplicate variables together? Let’s consider the following alteration:

It looks cleaner but is it actually better? Not necessarily. For the sake of flexibility and readability, this may not be the right solution in every case. We definitely shouldn’t merge some variables just because they accidentally turned out to hold the same values. Sometimes, as long as we’re doing this as a part of a well thought out system, it may help us simplify things and preserve consistency across the project. However, in other cases, such a manner may quickly prove to be confusing and problematic. Now, let’s take a look at yet another way we can approach this code.

Using CSS variables as multipliers

CSS custom properties are a fairly new feature to the modern web. One of the other awesome features that rolled out in the last years is the calc() function. It lets us perform real math operations in live CSS. In terms of the browser support, it’s supported in all browsers that support CSS custom properties.

calc() tends to play very nicely with CSS variables, making them even more powerful. This means we can both use calc() inside custom properties and custom properties inside calc()!

Why does this matter to us and our responsive designs? It means that we can use a calc() function to alter CSS custom properties inside media queries. Let’s say we have a padding that should have a value of 5px on mobile and 10px on desktop. Instead of declaring this property two times, we can assign a variable to it and multiply it by two on larger screens:

Looks fine, however all the values (--padding, calc(--padding * 2)) are away from their declaration (padding). The syntax may also be pretty confusing with two different padding variables (--padding and --foo-padding) and an unclear relationship between them.

To make things a bit clearer, let’s try to code it the other way around:

This way, we accomplished the same computed output with much cleaner code! So, instead of using a variable for an initial value of the property (1rem), a variable was used to store a multiplier (1 on small screens and 2 on larger screens). It also allows us to use the --multiplier variable in other declarations. Let’s apply this technique to paddings and margins in our previous snippet:

You may have noticed that 3 / 2 is not a valid CSS value at all. Why does it not cause an error then? The reason is that the syntax for CSS variables is extremely forgiving, which means almost anything can be assigned to a variable, even if it’s not a valid CSS value for any existing CSS property. Declared CSS custom properties are left almost entirely un-evaluated until they are computed by a user agent in certain declarations. So, once a variable is used in a value of some property, this value will turn valid or invalid at the computed-value time.

Oh, and another note about that last note: in case you’re wondering, I used a value of 3 / 2 simply to make a point. In real life, it would make more sense to write 1.5 instead to make the code more readable.

Now, let’s take a look at the finished live example combining everything that we discussed above:

Again, I would never advocate for combining calc() with custom properties to make the code more concise as a general rule. But I can definitely imagine scenarios in which it helps to keep code more organized and maintainable. This approach also allows the weight of CSS to be significantly reduced, when it’s used wisely.

In terms of readability, we can consider it more readable once the underlying rule is understood. It helps to explain the logic and relations between values. On the other hand, some may see it as less readable, because it’s tough to instantly read what a property holds as a value without first doing the math. Also, using too many variables and calc() functions at once may unnecessarily obscure code and make it harder to understand, especially for juniors and front-end developers who are not focused on CSS.

Conclusion

Summing up, there’s a lot of ways to use CSS custom properties in responsive design, definitely not limited to the examples shown above. CSS variables can be used simply to separate the values from the designs. They can also be taken a step further and be combined with some math. None of the presented approaches is better nor worse than the others. The sensibility of using them depends on the case and context.

Now that you know how CSS custom properties can be used in responsive design, I hope you will find a way to introduce them in your own workflow. Next up, we’re going to look at approaches for using them in reusable components and modules, so let's check that out.

Violet Peña has shared her recommendations for using CSS Grid. They basically boil down to these high-level points:

Use names instead of numbers for setting up our grid columns.

fr should be our flexible unit of choice.

We don’t really need a grid system anymore.

Although this is all great advice and Violet provides a few examples to support her recommendations, I particularly like what she has to say about learning CSS Grid:

“Learning” CSS Grid requires developing working knowledge of many new properties that don’t just describe one aspect of appearance or behavior, but feed into a completely new layout system. This system includes around 18 properties which use paradigms and syntax rarely (or never) seen anywhere else in the CSS spec.

This means that CSS Grid has a pretty high skill floor — a developer needs to learn and internalize lots of new information in order to be effective with it. Once you’re above that skill floor, Grid is an amazing ally in layout creation. Below that skill floor, Grid is an encumbrance. You wonder why you’re bothering to use it at all, since it seems to require lots of additional work for little reward.

In this post, I want to help you overcome that skill floor by showing you the most effective ways to leverage the Grid spec.

Also this post reminded me that, although I’m not sure why, I tend to avoid naming my grid columns up. Like in this bit of code that Violet walks us through:

Now we can use the sidebar or content names when we define our grid-column like this:

.content {
grid-column: content;
}

I really like that! It seems super easy to read and if we wanted to change the size of our .content, class then it only requires going back to where the grid is defined in the first place. Anyway, I’ll be sure to name my grid columns from here on out.

Web animation is one of the factors that can strongly enhance your website’s look and feel. Sadly, unlike mobile apps, there aren’t as many websites using animation to their benefit as you would think. We don’t want to count yours among those, so this article is for you and anyone else looking for ways to use animation for a better user experience! Specifically, we’re going to learn how to make web interactions delightful using CSS animations.

Before we move ahead, it’s worth mentioning that I’m going to assume you have at least some familiarity with modern front-end frameworks and a basic understanding of CSS animations. If you don’t, then no fear! CSS-Tricks has a great guides on React and Vue, as well as a thorough almanac post on the CSSanimation property.

Good? OK, let’s talk about why we’d want to use animation in the first place and cover some baseline information about CSS animations.

Animations enhance the way users interact with an interface. For example, smart animations can reduce cognitive load by giving users better context between page transitions.

They can provide clear cues to users, like where we want them to focus attention.

Animations serve as another design pattern in and of themselves, helping users to get emotionally attached to and engage with the interface.

Another benefit of using animations is that they can create a perception that a site or app loads faster than it actually does.

A couple of house rules with animations

Have you ever bumped into a site that animates all the things? Wow, those can be jarring. So, here’s a couple of things to avoid when working with animations so our app doesn’t fall into the same boat:

Avoid animating CSS properties other than transform and opacity. If other properties have to be animated, like width or height, then make sure there aren’t a lot of layout changes happening at the same time. There’s actually a cost to animations and you can see exactly how much by referring to CSS Triggers.

Also, just because animations can create perceived performance gains, there’s actually a point of diminishing return when it comes to using them. Animating too many elements at the same time may result in decreased performance.

Now we can get our hands dirty with some code!

Let’s build a music app

We’re going to build the music app we looked at earlier, which is inspired by Aurélien Salomon’s Dribbble shot. I chose this example so that we can focus on animations, not only within a component, but also between different routes. We’ll build this app using Vue and create animations using vanilla (i.e. no framework) CSS.

Animations should go hand-in-hand with UI development. Creating UI before defining their movement is likely to cost much more time. In this case, the Dribbble shot provides that scope for us.

Let’s start with the development.

Step 1: Spin up the app locally

First things first. We need to set up a new Vue project. Again, we’re assuming some base-level understanding of Vue here, so please check out the Learning Vue guide for more info on setting up.

We need a couple of dependencies for our work, notably vue-router for transitioning between views and sass-loader so we can write in Sass and compile to CSS. Here’s a detailed tutorial on using routes and Sass can be installed by pointing the command line at the project directory and using npm install -D sass-loader node-sass.

We have what we need!

Step 2: Setting up routes

For creating routes, we’re first going to create two bare minimum components — Artists.vue and Tracks.vue. We’ll drop a new file in the src folder called router.js and add routes for these components as:

When all is said and done, the two views will come out to something like this:

Artists.vue (left) and Tracks.vue (right)
Step 4: Animate!

Here we are, the part we’ve really wanted to get to all this time. The most important animation in the app is transitioning from Artists to Tracks when clicking on an artist. It should feel seamless where clicking on an artist image puts that image in focus while transitioning from one view into the next. This is exactly the type of animation that we rarely see in apps but can drastically reduce cognitive load for users.

To make sure we’re all on the same page, we’re going to refer to the first image in the sequence as the “previous” image and the second one as the "current" image. Getting the effect down is relatively easy as long as we know the dimensions and position of the previous image in the transition. We can animate the current image by transforming it as per previous image.

The formula that I’m using is transform: translate(x, y) scale(n), where n is equal to the size of previous image divided by the size of current image. Note that we can use a static value of n since the dimensions are fixed for all the images. For example, the image size in the Artists view is 190x190 and 240x240 in the Tracks view. Thus, we can replace n by 190/240 = 0.791. That means the transform value becomes translate(x, y) scale(0.791) in our equation.

Animating from Artists to Tracks

Next thing is to find x and y. We can get these values though click event in the Artists view as:

const {x, y} = event.target.getBoundingClientRect()

...and then send these values to the Tracks view, all while switching the route. Since we aren’t using any state management library, the two components will communicate via their parent component, which is the top level component, App.vue. In App.vue, let’s create a method that switches the route and sends the image info as params.

Since we have received the position and ID of the image in Tracks, we have all the required data to show and animate it. We’ll first fetch artist information (specifically the name and image URL) using artist ID.

To animate the image, we need to calculate the transform value from the image’s starting position. To set the transform value, I’m using CSS custom properties, which can be done with CSS-in-JS techniques as well. Note that the image’s position that we received through props will be relative to window. Therefore we’ll have to subtract some fixed offset caused by the padding of the container <div> to even out our math.

We’ll use this value to create a keyframe animation to move the image:

@keyframes move-image {
from {
transform: var(--translate);
}
}

This gets assigned to the CSS animation:

.image {
animation: move-image 0.6s;
}

...and it will animate the image from this transform value to its original position on component load.

Transitioning from Artists to Tracks

We can use the same technique when going the opposite direction, Tracks to Artists. As we already have the clicked image’s position stored in the parent component, we can pass it to props for Artists as well.

Transitioning from Tracks to Artists
Step 5: Show the tracks!

It’s great that we can now move between our two views seamlessly, but the Tracks view is pretty sparse at the moment. So let’s add the track list for the selected artist.

We’ll create an empty white box and a new keyframe to slide it upwards on page load. Then we’ll add three subsections to it: Recent Tracks, Popular Tracks, and Playlist. Again, if you want to jump ahead, feel free to either reference or copy the final code from the repo.

The Tracks view with content

Recent Tracks is the row of thumbnails just below the artist image where each thumbnail includes the track name and track length below it. Since we’re covering animations here, we’ll create a scale-up animation, where the image starts invisible (opacity: 0) and a little smaller than it’s natural size (scale(0.7)), then is revealed (opacity: 1 )and scales up to its natural size (transform: none).

The Popular Tracks list and Playlist sit side-by-side below the Recent Tracks, where Popular tracks takes up most of the space. We can slide them up a bit on initial view with another set of keyframes:

The code above is basically looking for each child element, then adding a 0.05 second delay to each element it finds. So, for example, the first child gets a 0.05 second delay, the second child gets a 0.10 second delay and so on.

Check out how nice and natural this all looks:

Bonus: micro-interactions!

One of the fun things about working with animations is thinking through the small details because they’re what tie things together and add delight to the user experience. We call these micro-interactions and they serve a good purpose by providing visual feedback when an action is performed.

Depending on the complexity of the animations, we might need a library like anime.js or GSAP. This example is pretty straightforward, so we can accomplish everything we need by writing some CSS.

First micro-interaction: The volume icon

Let’s first get a volume icon in SVG format (Noun Project and Material Design are good sources). On click, we’ll animate-in and out its path element to show the level of volume. For this, we’ll create a method which switches its CSS class according to the volume level.

Do you like it when you click on Twitter’s heart button? That’s because it feels unique and special by the way it animates on click. We’ll make something similar but real quick. For this, we first get an SVG heart icon and add it to the the markup. Then we’ll add a bouncy animation to it that’s triggered on click.

Another fun thing we can do is add other small heart icons around it with random sizes and positions. Ideally, we’d add a few absolute-positioned HTML elements that a heart as the background. Let’s Arrange each of them as below by setting their left and bottom values.

We’ll also include a fade away effect so the icons appear to dissolve as they move upward by adding a keyframe animation on the same click event.

That’s all! I hope you find all this motivating to try animations on your own websites and projects.

While writing this, I also wanted to expand on the fundamental animation principles we glossed over earlier because I believe that they help choose animation durations, and avoid non-meaningful animations. That’s important to discuss because doing animations correctly is better than doing them at all. But this sounds like a whole another topic to be covered in a future article.

I was recently a guest editor for an issue of Bizarro Devs. It's a great newsletter! Go sign up! I put in a bunch of links around blobs. Like those weird squishy random shapes that are so "in" right now. Here are those links as well. I'm always a fan of publishing stuff I write ;)

Blobs! Blobs are in! Blobs are — ahem — a bit bizarre. I'll bask in a design like this annual report cover by Matt Pamer all day. I enjoy watching a design trend like this manifest itself in design tooling and become applied in lots of creative and crafty different ways.

We could start with <svg> and draw our own blob using the Pen tool that is pretty much stock in every vector design application. I'm a cheater though, and would probably wind up checking The Noun Project for some blob examples and steal the SVG from there. But sadly, there isn't much there, at least as far as blobs go.

A library like Greensock could help moving and morphing the blobs around. Greensock even has a plugin that is probably the most powerful morphing tool out there. This Pen uses Greensock, but adds some native SVG filters so that the blobs squish into each other satisfyingly. We could call it the gooey effect: