Typography III: Styling
Previously, I’ve chosen the fonts and set an unconventional type scale.
In this post, I’ll be going a bit beyond the letterforms and spacings, trying to make this chunk of text finally readable. I’m going to make use of OpenType features, and style the default HTML elements. It might get a bit technical, but you’ll see a few simple CSS declarations going a long way.
Table of Contents
Take a look at this text:
Now look at the one below. Which one do you prefer reading? Can you spot all of the type nuances? Hint: There are 15 of them.
If not, let me guide you:
This may be an exaggeration on a small piece of imaginary text, but little nuances like these add up to make the reading experience more pleasurable. Without further ado, first things first…
Line Length
Let’s set a proper line length! The benchmark for this kind of text should be in between 55–75 characters per line. I’ll provide some whitespace, as well:
#page {
max-width: 34.5rem;
margin: 1.5rem;
}
@media (min-width: 640px) {
#page {
margin: 4rem;
}
}
Woah. Now I can breathe.
Contrast
Going ahead of myself here by dealing with color up front, but I can’t stand looking at the same contrast levels between titles and body text against the background anymore. Let’s make it much easier on the eyes.
:root {
--color-bg: #fafafa;
--color-text-headline: #121212;
--color-text-default: #454545;
}
html,
body {
background: var(--color-bg);
color: var(--color-text-default);
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: var(--color-text-headline);
}
Font Smoothing
I’ll use custom font smoothing to make sure that the letters look as good as they can on the screen:
html,
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
Line-Height & Tracking
Line heights were already specified, but I’ll introduce a bit tighter tracking for body text. It’s by no means necessary with this font, it might even be considered a bad typography choice, since this font is optimized by default, but I just like the overall feel better when I narrow it down a bit.
p,
li {
letter-spacing: -0.01rem;
}
Kerning
I’ll use optimizeLegibility
on headings for proper kerning. With this, browser emphasizes legibility over rendering speed, so I won’t use it on body text to avoid performance issues. macOS handles this by default, but the difference will be more dramatic on other OSs.
text-wrap
is a relatively new CSS feature, and it wraps text in a way that balances the number of characters on each line, which helps to prevent orphans. Counting characters to balance them across multiple lines is computationally expensive, so this will be used on headings only, as well.
h1,
h2,
h3,
h4,
h5,
h6 {
text-rendering: optimizeLegibility;
text-wrap: balance;
}
Ligatures
Take a closer look at these: fi, fl, ff, ffi, ffl — do you see how letters are combined to form a single glyph? That’s called a ligature, and it provides a more harmonious reading experience. Let’s make sure they’re on:
p,
li {
font-feature-settings: "liga", "clig", "calt";
}
Old-Style Numerals
As opposed to lining figures (lnum
), this stylistic variation creates a more organic flow with lowercase letters, and is particularly effective in body text, providing a better rhythm and less disruptive reading experience.
Of course, they’re not to be used with, let’s say, tables — but we’ll get there.
p,
li {
font-feature-settings: "onum";
}
Small Caps
True small caps are uppercase letters designed at roughly the x-height of lowercase letters, not just scaled-down capitals. They maintain the weight and proportions appropriate to their size. Often used for acronyms and abbreviations within body text.
.small-caps {
font-variant-caps: all-small-caps;
font-feature-settings: "c2sc", "smcp";
}
Ordinals
.ordinal {
font-variant-numeric: ordinal;
font-feature-settings: "ordn";
}
Stylistic Alternates
This feature replaces default character glyphs with stylistic alternates. You’ll see an extensive use of this in the § Pre-formatted Text & Code.
For headings and texts, I mostly like the defaults. I will only use “1” without serif in titles, and a slashed “0” for body text:
h1,
h2,
h3 {
font-feature-settings: 'ss02' on;
}
p,
li {
font-variant-numeric: slashed-zero;
}
Links
I’ll set a custom underline for links. Once again, can’t really show you this on macOS, because its defaults are good, but the difference will be more visible on other OSs. Still, here’s the comparison:
a {
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 1px;
}
Bullet List Dots
An unordered (bulleted) list can have big, ugly bullet dots. Let’s fix that:
ul {
list-style-type: "\2022\a0\a0";
}
Blockquotes
Just look at this quote. It’s beautiful.
Confucius
It’s mostly styled with use of pseudo-elements:
blockquote {
position: relative;
margin: 3rem 0 2.25rem;
padding-left: 2.25rem;
}
blockquote:before {
content: "\201C";
position: absolute;
z-index: -1;
top: -1.25rem;
left: -0.25rem;
font-size: 8rem;
line-height: 1;
color: #eee;
}
blockquote p {
font-size: var(--font-size-lg);
font-style: italic;
line-height: 1.4583333333;
opacity: 0.75;
}
blockquote p:last-of-type {
margin: 0;
}
blockquote cite {
display: block;
margin-top: 0.75rem;
}
blockquote cite::before {
content: "\2014";
}
Table
Just some minimal table styling, background color for odd rows and paddings on table cells. Oh, and allowing horizontal scroll on mobile devices. Don’t forget the lining numerals, as well! Here it is:
Style | Example | Usage |
---|---|---|
Hyphen (-) | sugar-free | For compound words and syllable breaks |
En dash (–) | 9–5 workday | For ranges, scores, and relationships |
Em dash (—) | The cake—it was delicious | For breaks in thought, attribution, emphasis |
table {
width: 100%;
min-width: 34.5rem;
margin: 0 0 1.5rem;
font-size: var(--font-size-sm);
font-variant-numeric: lining-nums tabular-nums;
overflow-x: auto;
}
table tbody tr:nth-child(odd) {
background: #eee;
}
table th {
padding: 0.5rem 1rem;
color: var(--color-text-headline);
}
table td {
padding: 0.5rem 1rem;
color: var(--color-text-default);
}
Horizontal Rule
A purely stylistic choice, but I went with a dotted hr
. Here’s how I styled it:
hr {
margin: calc(2.5rem - 1px) 0 2.5rem;
background: repeating-linear-gradient(
to right,
#000 0,
#000 1px,
transparent 1px,
transparent 4px
);
}
Pre-Formatted Text & Code
I’m using hugo’s in-built support for these formats, with the github syntax theme. This post is really code-heavy, so you can’t really miss these. Still, I wanted to bring the monospaced font closer to the body font, so let me show you how I’ve made use of JetBrains Mono’s stylistic alternates:
pre,
pre code {
font-size: var(--font-size-xs);
line-height: 1.6666666667;
}
pre,
code {
font-family: var(--font-mono);
font-feature-settings:
"cv03" on, /* alternate g */
"cv11" on, /* alternate y */
"cv12" on, /* alternate u */
"cv14" on, /* alternate $ */
"cv18" on, /* alternate 2, 6, and 9 */
"cv20" on; /* alternate 5 */
font-weight: 500;
}
pre {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
margin: 0 0 1.5rem;
padding: 1.5rem;
border-radius: 8px;
}
p code {
padding: 0 0.25rem;
background: #eaeaea;
border-radius: 4px;
font-size: var(--font-size-sm);
line-height: 1.6666666667;
}
Emojis? Sure! 🤘😁
Hugo has a built-in emoji support. I don’t use them much, but hey, I’m keeping my options open. Just open a hugo.toml
config file and add:
enableEmoji = true
Fleuron
A small touch — I added a fleuron at the end of each post. Lovin’ it.
<span class="fleuron">❧</span>
With this, I think that I’ve done enough to make this site more readable. Here’s how the homepage looks like right now:
There are a few more nuances I’m thinking about, but I’ll focus on more important things next: grids, then color.
❧