- commit
- 6a25589c7bea444479c681342c16823ead913f2c
- parent
- edbcc04e269fdd37dca8e9ef2473dfae79f1b00a
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2024-03-15 13:12
add post on fluid typography
Diffstat
| A | _content/posts/2024-03-15-fluid-typography/demo/index.html | 55 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | _content/posts/2024-03-15-fluid-typography/demo/polyfill.js | 11 | +++++++++++ |
| A | _content/posts/2024-03-15-fluid-typography/demo/style.css | 41 | +++++++++++++++++++++++++++++++++++++++++ |
| A | _content/posts/2024-03-15-fluid-typography/index.md | 227 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 334 insertions, 0 deletions
diff --git a/_content/posts/2024-03-15-fluid-typography/demo/index.html b/_content/posts/2024-03-15-fluid-typography/demo/index.html
@@ -0,0 +1,55 @@ -1 1 <!DOCTYPE html> -1 2 <html> -1 3 <head> -1 4 <meta charset="utf-8"> -1 5 <meta name="viewport" content="width=device-width, initial-scale=1"> -1 6 <title>Fluid Typography Demo</title> -1 7 <link rel="stylesheet" href="style.css"> -1 8 </head> -1 9 <body> -1 10 <header> -1 11 <h1>This is <em>still</em> a motherfucking website.</h1> -1 12 <aside>And it's more fucking perfect than the last guy's.</aside> -1 13 </header> -1 14 -1 15 <h2>Seriously, it takes minimal fucking effort to improve this shit.</h2> -1 16 <p><strong>7 fucking declarations.</strong></p> -1 17 <p>That's how much CSS it took to turn that <a href="http://motherfuckingwebsite.com/">grotesque pile of shit</a> into this easy-to-read masterpiece. It's so fucking simple and it <em>still</em> has all the glory of the original perfect-ass website:</p> -1 18 <ul> -1 19 <li>Shit's <em>still</em> lightweight and loads fast</li> -1 20 <li><em>Still</em> fits on all your shitty screens</li> -1 21 <li><em>Still</em> looks the same in all your shitty browsers</li> -1 22 <li>The motherfucker's <em>still</em> accessible to every asshole that visits your site</li> -1 23 <li>Shit's <em>still</em> legible and gets your fucking point across</li> -1 24 </ul> -1 25 -1 26 <h3>And guess what, motherfucker:</h3> -1 27 <p>You never knew it, but it's easy to improve readability on your site. Here's how.</p> -1 28 -1 29 <h2>Let it breathe</h2> -1 30 <p>Look at lines 1 and 2 of some shitty website you're building. Assuming they're not married they probably shouldn't be humping. The defaults are trash -- pick a minimum <code>line-height: 1.4</code> for body copy. Headings should be tighter. If you can't see that...piss off.</p> -1 31 <p>If your text hits the side of the browser, fuck off forever. You ever see a book like that? Yes? What a shitty book.</p> -1 32 -1 33 <h2>A little less contrast</h2> -1 34 <p>Black on white? How often do you see that kind of contrast in real life? Tone it down a bit, asshole. I would've even made this site's background a nice <code>#EEEEEE</code> if I wasn't so focused on keeping declarations to a lean 7 fucking lines.</p> -1 35 -1 36 <h2>Size Matters</h2> -1 37 <p>I know your partner says otherwise, but it's true. Bump that body copy to render close to 16px or more. Smaller type works well for print, not the screen.</p> -1 38 -1 39 <h2>Line-width, motherfucker</h2> -1 40 <p>Looking at an LCD screen is strainful enough. Don't make me read a line of text that's 200 fucking characters long. Keep it to a nice 60-80 and users might actually read more than one sentence of your worthless dribble.</p> -1 41 -1 42 <h3>Yes, this is <em>also</em> fucking satire, you fuck</h3> -1 43 <p>I love what the creator of <a href="http://motherfuckingwebsite.com/">this site's inspiration</a> did. What I'm saying is that it's so, so simple to make sites easier to read. Websites are broken by default, they are functional, high-performing, and accessible, but they're also fucking ugly. You and all the other web designers out there need to make them not total shit.</p> -1 44 <blockquote> -1 45 "You're a fucking moron if you use default browser styles." -1 46 <br> - Eleanor Roosevelt -1 47 </blockquote> -1 48 <hr> -1 49 -1 50 <h2>Epilogue</h2> -1 51 <p>Inspired by the geniuses behind <a href="http://motherfuckingwebsite.com/">motherfuckingwebsite.com</a> and <a href="http://txti.es">txti</a>.</p> -1 52 <p>This page—that isn't a total fucking eyesore—was created by <a href="https://twitter.com/drew_mc">me</a> with help from <a href="https://twitter.com/gabehammersmith">him</a>. -1 53 -1 54 <script src="polyfill.js" type="module"></script> -1 55 </html>
diff --git a/_content/posts/2024-03-15-fluid-typography/demo/polyfill.js b/_content/posts/2024-03-15-fluid-typography/demo/polyfill.js
@@ -0,0 +1,11 @@
-1 1 var root = document.documentElement;
-1 2 var styles = getComputedStyle(root);
-1 3
-1 4 var setFactor = function() {
-1 5 var inlineSize = parseFloat(styles.inlineSize);
-1 6 var fontSize = parseFloat(styles.fontSize);
-1 7 root.style.setProperty('--screen-size', inlineSize / fontSize);
-1 8 };
-1 9
-1 10 window.addEventListener('resize', setFactor);
-1 11 window.addEventListener('load', setFactor);
diff --git a/_content/posts/2024-03-15-fluid-typography/demo/style.css b/_content/posts/2024-03-15-fluid-typography/demo/style.css
@@ -0,0 +1,41 @@
-1 1 :root {
-1 2 --max-inline-size: 40;
-1 3 --min-font-size: 0.8;
-1 4 --max-font-size: 1.2;
-1 5 --min-line-height: 1;
-1 6 --max-line-height: 1.6;
-1 7 --min-scale: 1;
-1 8 --max-scale: 1.6;
-1 9
-1 10 --screen-size: calc(100vi / 1rem);
-1 11 --factor: min(var(--screen-size) / var(--max-inline-size) / var(--max-font-size), 1);
-1 12 --font-size: 1;
-1 13
-1 14 --scale: calc(var(--min-scale) + (var(--max-scale) - var(--min-scale)) * var(--factor));
-1 15 --base-font-size: calc(var(--min-font-size) + (var(--max-font-size) - var(--min-font-size)) * var(--factor));
-1 16 }
-1 17
-1 18 body {
-1 19 max-inline-size: calc(var(--max-inline-size) * 1em);
-1 20 margin: 2.5em auto;
-1 21 padding: 0 1em;
-1 22 }
-1 23
-1 24 :root * {
-1 25 font-size: calc(var(--base-font-size) * var(--font-size) * 1rem);
-1 26 line-height: calc(var(--min-line-height) + (var(--max-line-height) - var(--min-line-height)) * var(--factor) / var(--font-size));
-1 27 }
-1 28
-1 29 h1 {
-1 30 --font-size: calc(var(--scale) * var(--scale));
-1 31 }
-1 32
-1 33 h2 {
-1 34 --font-size: var(--scale);
-1 35 }
-1 36
-1 37 @media (prefers-color-scheme: dark) {
-1 38 :root {
-1 39 color-scheme: dark;
-1 40 }
-1 41 }
diff --git a/_content/posts/2024-03-15-fluid-typography/index.md b/_content/posts/2024-03-15-fluid-typography/index.md
@@ -0,0 +1,227 @@
-1 1 ---
-1 2 title: Fluid typography in 2024
-1 3 date: 2024-03-15
-1 4 tags: [design, css]
-1 5 ---
-1 6
-1 7 The basics of typography are quickly explained: Body text should have 60-80
-1 8 characters per line, and line-height should be bigger if there are more
-1 9 characters on a line.
-1 10
-1 11 Usually in web design, font and font size is defined by user preferences (and
-1 12 we should respect that!), so we are left with picking a line width and line
-1 13 height, for example like this:
-1 14
-1 15 ```css
-1 16 body {
-1 17 max-inline-size: 40em;
-1 18 line-height: 1.6;
-1 19 }
-1 20 h1, h2 {
-1 21 line-height: 1.2;
-1 22 }
-1 23 ```
-1 24
-1 25 However, the line width you choose is only a maximum value. If the screen is to
-1 26 small, lines can end up significantly shorter than you expected, and that can
-1 27 throw off your composition.
-1 28
-1 29 A simple approach would be to choose values that work reasonably well on both
-1 30 small and large screens. But what fun would that be? No, let's go down this
-1 31 rabbit hole!
-1 32
-1 33 ## Fluid font size
-1 34
-1 35 The first thing we could try is to shrink the font size so that the number of
-1 36 characters per line does not decrease, or at least not as much. For example, we
-1 37 could add something like this:
-1 38
-1 39 ```css
-1 40 body {
-1 41 font-size: clamp(0.8em, 0.5em + 1vi, 1.2em);
-1 42 }
-1 43 ```
-1 44
-1 45 *Note: If you use `em` in a font-size definition, it refers to the font-size of
-1 46 the parent element.*
-1 47
-1 48 This approach does of course have its limits, we cannot shrink the font
-1 49 indefinitely. But it can provide some breathing room.
-1 50
-1 51 However, we immediately are faced with a challenge: With the example above,
-1 52 there are no guarantees that the font actually needs resizing. Maybe the users
-1 53 already configured their font settings to match the screen, so we make it worse
-1 54 for them instead of better.
-1 55
-1 56 Imagine we had a custom property `--factor` that told us how much space we
-1 57 have, going from `0` for no space at all to `1` for when we hit
-1 58 `max-inline-size`. That would allow us to only scale the font size if needed:
-1 59
-1 60 ```css
-1 61 body {
-1 62 font-size: calc(0.8em + 0.4em * var(--factor));
-1 63 }
-1 64 ```
-1 65
-1 66 ## Fluid line height
-1 67
-1 68 Long lines are hard to read because it is easy to jump to the previous line by
-1 69 accident, reading the same text again and again. Increasing the line height can
-1 70 help in those cases. [Tim Brown][molten-leading] already wrote about this idea
-1 71 in 2012, but CSS has come a long way since:
-1 72
-1 73 ```css
-1 74 body {
-1 75 line-height: calc(1 + var(--factor) * 0.6);
-1 76 }
-1 77 ```
-1 78
-1 79 However, the line height should not so much depend on the line width in pixels,
-1 80 but on the number of characters per line. That is why in the beginning I used a
-1 81 smaller line-height for headings. So we have to throw the font-size into the
-1 82 mix:
-1 83
-1 84 ```css
-1 85 body {
-1 86 line-height: calc(1 + var(--factor) / 1em * 0.6);
-1 87 }
-1 88 ```
-1 89
-1 90 Unfortunately, it's not that simple though. For one, it is currently not
-1 91 possible to divide by values with units (more on that later). But even if that
-1 92 were possible, that wouldn't help because the `em` would be evaluated on the
-1 93 body element, not on the element where it is applied. So instead, we will add
-1 94 yet another custom property:
-1 95
-1 96 ```css
-1 97 :root {
-1 98 --font-size: 1;
-1 99 }
-1 100 :root * {
-1 101 font-size: calc(var(--font-size) * 1rem);
-1 102 line-height: calc(1 + var(--factor) / var(--font-size) * 0.6);
-1 103 }
-1 104 h1 {
-1 105 --font-size: 2;
-1 106 }
-1 107 ```
-1 108
-1 109 ## Fluid modular scale
-1 110
-1 111 The relations between line length, font size, and line height we discussed so
-1 112 far were all linear. However, some designers like to work with [modular
-1 113 scales][modular-scale], i.e. power relations. For example:
-1 114
-1 115 ```css
-1 116 :root {
-1 117 --scale: 1.5;
-1 118 }
-1 119 h2 {
-1 120 --font-size: var(--scale);
-1 121 }
-1 122 h1 {
-1 123 --font-size: calc(var(--scale) * var(--scale));
-1 124
-1 125 /* see https://caniuse.com/mdn-css_types_pow */
-1 126 --font-size: pow(var(--scale), 2);
-1 127 }
-1 128 ```
-1 129
-1 130 Comig back to fluid typography, the people at [utopia][utopia] propose to also
-1 131 adapt that base scale (they say this is what they do, but actually the do
-1 132 linear interpolation between the powers):
-1 133
-1 134 ```css
-1 135 :root {
-1 136 --scale: calc(1 + var(--factor) * 0.5);
-1 137 }
-1 138 ```
-1 139
-1 140 ## The catch: calculating `--factor`
-1 141
-1 142 So far we looked at relations between different typographic measurements. The
-1 143 exact formulas and constants can be modified to match your personal taste.
-1 144 However, one puzzle piece is still missing: the `--factor` property. And
-1 145 unfortunately, that is not easy to come by. Spoilers: I don't have a perfect
-1 146 solution for this yet.
-1 147
-1 148 Ideally, we want something like this:
-1 149
-1 150 ```css
-1 151 :root {
-1 152 --factor: min(100vi / 40em, 1);
-1 153 }
-1 154 ```
-1 155
-1 156 As I mentioned before, [CSS Values and Units Module Level 3][css-values-3] does
-1 157 not allow to multiply or divide by values with units. [Level 4][css-values-4]
-1 158 will change that, but it is not yet implemented anywhere ([Firefox
-1 159 ticket][bugzilla]).
-1 160
-1 161 In the meantime, we can use JavaScript:
-1 162
-1 163 ```js
-1 164 var setFactor = function() {
-1 165 var style = getComputedStyle(document.body);
-1 166 var factor = parseFloat(style.inlineSize) / parseFloat(style.maxInlineSize);
-1 167 document.documentElement.style.setProperty('--factor', factor);
-1 168 };
-1 169
-1 170 window.addEventListener('resize', setFactor);
-1 171 window.addEventListener('load', setFactor);
-1 172 ```
-1 173
-1 174 But there is another issue: The maximum line width is defined as `40em`, which
-1 175 depends on the current font size. The font size in turn depends on `--factor`,
-1 176 which depends on the maximum line width. So there is a circular dependency.
-1 177
-1 178 In practice, this circle can be broken because there is an absolute maximum
-1 179 font size. In our case, that is `1.2 * 40 * 1rem`, were `rem` refers to the
-1 180 user defined font size. In case you had wondered: That is why I never set
-1 181 `font-size` on `:root`, because then it would have no longer been possible to
-1 182 get that value.
-1 183
-1 184 The rest is left as an exercise to the reader. If you are interested, I have
-1 185 prepared a [complete demo](./demo/).
-1 186
-1 187 ## Conclusion
-1 188
-1 189 Fluid typography is an old idea, but still surprisingly hard to do. [CSS Values
-1 190 and Units Level 4][css-values-4] will provide many improvements in this area,
-1 191 some of which are already widely available (`min()`/`max()`/`clamp()`).
-1 192
-1 193 Still, for everyday use these techniques are still too out-there. Using
-1 194 JavaScript to tweak typography is a clear no-go for me. And the risk of having
-1 195 weird cyclic dependencies is just too high.
-1 196
-1 197 ## Bonus: some more ideas
-1 198
-1 199 - It could also make sense to adapt line-height to the x-height of the font.
-1 200 This could be achieved by combining the `em`, `ch`, and `ex` units. But it
-1 201 would again require division be values with units.
-1 202
-1 203 - [Container queries][container-queries] and the `cqi` unit could be useful to
-1 204 apply these techniques to individual components.
-1 205
-1 206 - Vertical rhythm is a very different approach to typography then what I
-1 207 described here: Instead of adjusting the line height to the font size, you
-1 208 start with a fixed line grid and fit the elements in there. That is
-1 209 especially useful for newspaper-style layouts where you want the lines in
-1 210 neighboring columns to match. I rarely see this on the web, but it could be
-1 211 interesting to bring these ideas together.
-1 212
-1 213 - I tried to use [static interpolation][static-interpolation] (using paused
-1 214 animations to interpolate between values) for this, but found `calc()` easier
-1 215 to work with. Still, this is an interesting technique that could provide some
-1 216 benefits. [Scott Kellum][intrinsic-styles] has use this approach with some
-1 217 success.
-1 218
-1 219 [molten-leading]: https://tbrown.org/notes/2012/02/03/molten-leading-or-fluid-line-height/
-1 220 [modular-scale]: https://www.modularscale.com/
-1 221 [utopia]: https://utopia.fyi/blog/css-modular-scales/
-1 222 [css-values-3]: https://www.w3.org/TR/css-values-3/#calc-type-checking
-1 223 [css-values-4]: https://www.w3.org/TR/css-values-3/#calc-type-checking
-1 224 [bugzilla]: https://bugzilla.mozilla.org/show_bug.cgi?id=1827404
-1 225 [container-queries]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries
-1 226 [static-interpolation]: https://youtu.be/I_fBM1cEc_8?t=1383
-1 227 [intrinsic-styles]: https://css-tricks.com/intrinsic-typography-is-the-future-of-styling-text-on-the-web/