Skip to content

Commit ced1b0b

Browse files
committed
add typography to guide
1 parent 802153a commit ced1b0b

1 file changed

Lines changed: 193 additions & 2 deletions

File tree

‎css/README.md‎

Lines changed: 193 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
- Prefer native CSS over preprocessors like SCSS
1414

1515
[double colon syntax]: https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements#Syntax
16-
[popover api]: https://developer.mozilla.org/en-US/docs/Web/API/Popover_API
1716

1817
## Getting started
1918

@@ -191,6 +190,198 @@ to keep track of your values here and perhaps scope it per partial.
191190

192191
[container queries]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries
193192

193+
## Typography
194+
195+
### Font loading
196+
197+
Only ship fonts in [`woff2` format] as it's supported by all modern browsers and
198+
there's no need to include `woff`, `ttf`, or other formats as fallbacks.
199+
200+
Always set [`font-display: swap`] on `@font-face` declarations to prevent
201+
invisible text while a web font is loading:
202+
203+
```css
204+
@font-face {
205+
font-display: swap;
206+
font-family: "Inter";
207+
font-style: normal;
208+
font-weight: 100 900;
209+
src: url("inter.woff2") format("woff2");
210+
}
211+
```
212+
213+
If the fallback font differs noticeably in size from the web font, use
214+
[`font-size-adjust`] to normalize the x-height across both, which reduces
215+
layout shift when the web font loads:
216+
217+
```css
218+
body {
219+
font-family: "Inter", system-ui;
220+
font-size-adjust: from-font;
221+
}
222+
```
223+
224+
For performance-sensitive projects, a system font stack can be a reasonable
225+
alternative to web fonts altogether:
226+
227+
```css
228+
body {
229+
font-family: system-ui, sans-serif;
230+
}
231+
```
232+
233+
[`woff2` format]: https://caniuse.com/woff2
234+
[`font-display: swap`]: https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display
235+
[`font-size-adjust`]: https://developer.mozilla.org/en-US/docs/Web/CSS/font-size-adjust
236+
237+
### Fluid type
238+
239+
Use [`clamp()`] for more fluid typography. This is a way to scale type
240+
smoothly between a minimum and maximum size based on viewport width,
241+
without breakpoints.
242+
243+
- You can use fluid typography for larger headings or display type
244+
- Most body and UI copy should normally default to a static size (not fluid)
245+
246+
```css
247+
:root {
248+
--font-size--heading: clamp(1.5rem, 4vw, 3rem);
249+
}
250+
251+
h2 {
252+
font-size: var(--font-size--heading);
253+
}
254+
```
255+
256+
The first value is the floor, the second is the preferred fluid value, and the
257+
third is the ceiling.
258+
259+
[`clamp()`]: https://developer.mozilla.org/en-US/docs/Web/CSS/clamp
260+
261+
### Variable fonts
262+
263+
If your project uses a variable font that varies weight, you can define a weight range in
264+
`@font-face` and let the font render any weight within that range:
265+
266+
```css
267+
@font-face {
268+
font-family: "Inter";
269+
font-weight: 100 900;
270+
src: url("inter-variable.woff2") format("woff2");
271+
}
272+
```
273+
274+
Enable [optical sizing] if the font supports an `opsz` axis. Browsers will
275+
adjust letterform details automatically based on the rendered size:
276+
277+
```css
278+
body {
279+
font-optical-sizing: auto;
280+
}
281+
```
282+
283+
For other variable axes (width, slant, etc.), use [`font-variation-settings`]
284+
when `font-weight` or `font-style` alone aren't enough:
285+
286+
```css
287+
.heading {
288+
font-variation-settings: "wdth" 110;
289+
}
290+
```
291+
292+
[optical sizing]: https://developer.mozilla.org/en-US/docs/Web/CSS/font-optical-sizing
293+
[`font-variation-settings`]: https://developer.mozilla.org/en-US/docs/Web/CSS/font-variation-settings
294+
295+
### Rendering
296+
297+
`-webkit-font-smoothing: antialiased` renders fonts thinner on macOS and iOS by
298+
using greyscale antialiasing instead of the default subpixel rendering. It can be a stylistic
299+
choice and some designers prefer the lighter appearance, while others
300+
find it reduces legibility at small sizes. If your project uses it, apply it
301+
consistently:
302+
303+
```css
304+
body {
305+
-webkit-font-smoothing: antialiased;
306+
}
307+
```
308+
309+
If your typeface has them, enable common [ligatures] for more natural text rendering:
310+
311+
```css
312+
body {
313+
font-variant-ligatures: common-ligatures;
314+
}
315+
```
316+
317+
[ligatures]: https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant-ligatures
318+
319+
### Minimum font sizes
320+
321+
- Body text should be at least `1rem` (or `16px` equivalent) at its smallest.
322+
- Avoid setting `font-size` in `px` on the `html` or `body` element as it overrides
323+
the user's browser font size preference, which is a common accessibility accommodation.
324+
- When using [`clamp()`] for fluid type, the first argument acts as the floor.
325+
- Make sure it's never smaller than `1rem` for reading-level text:
326+
327+
```css
328+
/* Good — floor is 1rem */
329+
--font-size--body: clamp(1rem, 2.5vw, 1.25rem);
330+
331+
/* Avoid — floor is below accessible threshold */
332+
--font-size--body: clamp(0.75rem, 2.5vw, 1.25rem);
333+
```
334+
335+
Supporting text like captions or labels can go smaller, but staying at or above
336+
`0.75rem` (12px equivalent) is a reasonable lower bound for anything a user is
337+
expected to read.
338+
339+
### Further readability
340+
341+
Use [`text-wrap`] to improve how text breaks across lines without manual
342+
intervention.
343+
344+
- Prefer `pretty` as a general default for headings because it prevents orphaned words
345+
at the end of a block and works well at any length.
346+
- It is still however, not fully supported as of writing this guide.
347+
- `balance` is a fine fallback for browsers that don't support `pretty`.
348+
- The spec gives browsers latitude in how they implement these algorithms, so
349+
Chrome and Safari may produce slightly different line breaks for the same text.
350+
351+
```css
352+
h1, h2, h3, h4 {
353+
text-wrap: balance;
354+
text-wrap: pretty;
355+
}
356+
```
357+
358+
Use a unitless value for [`line-height`] as it scales correctly in nested
359+
elements where `em` or `%` values can compound unexpectedly:
360+
361+
```css
362+
body {
363+
line-height: 1.5;
364+
}
365+
366+
h1 {
367+
line-height: 1.2;
368+
}
369+
```
370+
371+
The [`lh` unit] is useful for spacing that should feel proportional to the
372+
current line height. For example, paragraph margins that stay in rhythm with
373+
the text:
374+
375+
```css
376+
p {
377+
margin-block-end: 1lh;
378+
}
379+
```
380+
381+
[`text-wrap`]: https://developer.mozilla.org/en-US/docs/Web/CSS/text-wrap
382+
[`line-height`]: https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
383+
[`lh` unit]: https://developer.mozilla.org/en-US/docs/Web/CSS/length#lh
384+
194385
## Linting
195386

196387
[Stylelint] is a good option for enforcing CSS conventions. If
@@ -278,7 +469,7 @@ approach exists.
278469
### Nesting
279470

280471
Native CSS nesting is well-supported in modern browsers. It's useful for keeping
281-
component styles self-contained, though deep nesting can make specificity and
472+
component styles self-contained, though deep nesting can make specificity and
282473
readability harder to manage.
283474

284475
- Keep nesting to a maximum of 3 levels deep when possible.

0 commit comments

Comments
 (0)