Miloš Jeremić

Product Designer

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:

No Typography Styling

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.

Type nuances example, side by side

If not, let me guide you:

Type nuances description

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:

Compare: Line Length

#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.

Compare: Contrast

: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:

Compare: Font Smoothing

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.

Compare: Tracking

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.

Compare: Kerning Compare: Balance

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:

Compare: Ligatures

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.

Compare: Old-Style Numerals

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.

Compare: Small Caps

.small-caps {
  font-variant-caps: all-small-caps;
  font-feature-settings: "c2sc", "smcp";
}

Ordinals

Compare: 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:

Compare: Stylistic Alternates

h1,
h2,
h3 {
  font-feature-settings: 'ss02' on;
}
p,
li {
  font-variant-numeric: slashed-zero;
}

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:

Compare: Links

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:

Compare: Bullets

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:

Compare: Horizontal Rule

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:

Compare: Pre & Code

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">&#10087;</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:

milosjeremic.com

There are a few more nuances I’m thinking about, but I’ll focus on more important things next: grids, then color.


Caution! Work In Progress

I'm redesigning this website in the open, and documenting my thoughts and changes as I go. Here's the list:

  1. The Blank Canvas: A Website Genesis
  2. What's a Personal Website, Anyway?
  3. Choosing a Tech Stack
  4. Typography I: Typeface Selection
  5. Typography II: Type Scale Blues
  6. Typography III: Styling
  7. Constructing the Grid