|
13 | 13 | - Prefer native CSS over preprocessors like SCSS |
14 | 14 |
|
15 | 15 | [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 |
17 | 16 |
|
18 | 17 | ## Getting started |
19 | 18 |
|
@@ -191,6 +190,198 @@ to keep track of your values here and perhaps scope it per partial. |
191 | 190 |
|
192 | 191 | [container queries]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries |
193 | 192 |
|
| 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 | + |
194 | 385 | ## Linting |
195 | 386 |
|
196 | 387 | [Stylelint] is a good option for enforcing CSS conventions. If |
@@ -278,7 +469,7 @@ approach exists. |
278 | 469 | ### Nesting |
279 | 470 |
|
280 | 471 | 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 |
282 | 473 | readability harder to manage. |
283 | 474 |
|
284 | 475 | - Keep nesting to a maximum of 3 levels deep when possible. |
|
0 commit comments