Clagnut https://clagnut.com/ A blog by Richard Rutter. Root through a heap of web design and development stuff and a few other tasty morsels. (latest 5 posts in full) en-gb Copyright 2003-2024, Richard Rutter rich@clagnut.com (Richard Rutter) rich@clagnut.com (Richard Rutter) https://clagnut.com/images/clagnut_rss.png https://clagnut.com/ Clagnut 88 31 Fri, 01 Mar 2024 20:38:31 PST Retrofitting fluid typography https://clagnut.com/blog/2428/ https://clagnut.com/blog/2428/

Back in December 2023, Creative Boom launched a refreshed identity and a redesigned website. It’s a terrific magazine and the redesign does a great job of bringing impactful imagery to the fore, with restrained typography supporting the writing really effectively.

Like any modern website, it is responsive and so adapts well to different screen sizes. However it does so using five breakpoints, resulting in six different designs, all of which are fixed width except the smallest.

A row of 6 screenshots showing the Creative Boom website as it looks at each breakpoint

I thought this was a missed opportunity, so as part of my forthcoming Patterns Day talk I decided to rebuild the article page using Utopian fluid typography: one adaptive design with no media queries, less compromise across viewports, and far less design and development debt.

Fluid typography means thinking in terms of type scales and flexible spacing across your defined design space. This means deciding upon the size of the smallest screen and the largest screen (viewport) that you want to concern yourself with. These form the boundaries of your design space. Thereafter you’re just designing at the extremes – design for the smallest screen and the largest viewport, and let maths fill in the gap. This is declarative design in action, rather than the more imperative approach that Creative Boom has taken.

There’s much more detail about this on the Utopia blog, but for now I’ll take you through my process of converting Creative Boom to fluid typography. The general approach is:

  1. Define a type scale and set the spacing for a small screen (@min).
  2. Define a type scale and set the spacing for a large viewport (@max).
  3. Tell the browser to interpolate between the two scales and spacing systems, based on the current viewport width (the Utopia calculator tools do this for you).

Type scales

My first job was to define the body text size for my two extreme viewport sizes. Creative Boom’s biggest media query happens at 1536px so I used that as my @max screen size. At this viewport the text is 20px (assuming no change to the default browser text size).

At Clearleft our design spaces tend to start with a minimum screen size of 320px, so I used that as my @min. Creative Boom uses 20px for its body text regardless of viewport size – I think this impairs the reading experience on a small screen, so I chose a more appropriate 17px.

I could now plug these numbers into Utopia’s type calculator and start playing around to identify the two type scales that work best for @min and @max viewports. In order to determine each type scale I needed to look at the main heading sizes used by Creative Boom: the biggest size of h1 is 60px, the smallest is 40px. Through a quick bit of experimentation I found that setting a type scale increment of 1.2 for my @min viewport, and 1.25 for the @max viewport size gave me type sizes of 42px and 61px respectively at step 5, which are close enough – remember the typography is fluid, so by definition it’s never going to match a fixed design exactly.

Screenshot of Utopia's type tool
Utopia’s type tool calculates the text sizes for you, and also generates the necessary CSS

Choosing step 5 on the type scale to represent h1 headings left plenty of smaller steps in the scale to apply to subheadings and other significant text sizes. The type scales also provided sensible smaller text sizes for step -1 and step -2 which I could use for ancillary text elements such as tags and meta data.

Once I’d pasted in Utopia’s generated CSS to make the fluid type scales work, I was able to use the following simple CSS to set type sizes:

h1    { font-size: var(-step-5); }
h2    { font-size: var(-step-1); }
body  { font-size: var(-step-0); }
.nav  { font-size: var(-step-1); }
.tags { font-size: var(-step-2); }

Here’s where they were applied:

Screenshot: type steps start with 5 on the <abbr class='c2sc'>H1</abbr>, go through to 0 on the paragraphs and -2 on the tags
Type steps applied to all text elements of the design

I also used a type step token to constrain the overall page width for very large viewports. This was in order to keep the line-length comfortable and the layout in line with the Creative Boom design. I went for 77ems based on the body size (this width also accommodates the sidebar):

.masthead, .article-header, .article-body {
    max-width: calc(var(-step-0) * 77);
}

Fluid spacing

With the type scales defined and applied, I could now turn my attention to the spacing. The Utopia spacing tool sets up simple t-shirt sizes for spacing, giving you tokens related to multiples of your body text size. In other words, as the body text varies with viewport size, so do the spacing tokens. Following a simple reset, I first set about spacing the typography, going down the ‘page’. Using the Creative Boom design as a guide, I just had to ask myself “on a scale of XS to XL, how big is that space?”. That gave me declarations like these:

h1      { margin-block-start:var(-space-m); }
h2      { margin-block:var(-space-s); }
h3      { margin-block-end: var(-space-m); }
h4      { margin-block: var(-space-xs); }
p       { margin-block-end: var(-space-s); }
figure  { margin-block: var(-space-xl); }
.byline { margin-block-end: var(-space-xs); }
date    { margin-block-end: var(-space-xs); }

Which were applied wherever space was required in the vertical plane:

Screenshot
Space tokens applied in the vertical plane

Fluid spacing in the vertical plane is relatively straight forward as scrolling means there is not so much of a limitation to a small viewport. Laying things out and spacing them apart in the horizontal place is a different ballgame. By definition small screens have very little width to play with, whereas large viewports have lots. Defining a fluid spacing scheme that works across both extremes is therefore more challenging.

Fortunately Utopia again comes to the rescue with its space value pairs. These enable you to specify much more dramatic space variance between different viewport sizes. One of the most obvious uses is the padding between the article and the viewport edge. At the @min viewport, I’ve set it to XS – just enough to provide breathing room to the viewport boundary. For the @max I was able to set a suitably generous 2XL amount of spacing. I made these decisions through quick experimentation using variations of a single spacing token:

.masthead, .article-header, .article-body {
  padding-inline: var(-space-xs-2xl);
}

Another bit of spacing of note is the gutter between the article text and the Editor’s Picks sidebar. I used flexbox to provide media-query-free responsive layout (see Every Layout) so I was able to simply set the gap property. Again in keeping with the design, I’m increasing the spacing significantly for wider viewports:

.article-body {
  display: flex;
  gap: var(-space-s-xl);
} 

To ensure a fully flexible design, I’ve used Utopian spacing tokens almost everywhere a space is required in the horizontal plane:

Screenshot, indicating an <abbr class='c2sc'>XS</abbr> to 2XL space value pair padding the page
Space value pairs applied in the horizontal plane

The final result

And here’s the final result in all its fluid glory:

The rebuilt Creative Boom article page fluidly resizing from 320px to 1600px

Feel free to play with the rebuild, although please remember this is just a prototype, so some aspects are missing and the underlying HTML in particular is far from production ready.

In my experience it’s easier to design using Utopian principles first rather than retrospectively. That said, although I rebuilt this page from scratch, it does show you can retrospectively apply fluid typography to a design, although it’s definitely better to think in those terms from the start.

Read or add comments

]]>
Typography CSS techniques Conferences
Wed, 10 Jan 2024 09:31:31 PST Responsive typography and its role in design systems https://clagnut.com/blog/2427/ https://clagnut.com/blog/2427/

Later this year – 7 March 2024 to be precise – I’ll be talking at Patterns Day, the one-day conference for designers and developers focused on design systems, pattern libraries, style guides, and components. Jeremy asked me to weave responsive typography into his narrative of the day. It’s a tricky challenge, but one I’m excited to take on – how to explain something as all-encompassing as typography in the context of something so potentially granular as a design system?

Before I show you what I’ve come up with, know that you can get 10% off Patterns Day using the code JOINRICHARD. Right, here’s my approach:

Typography is what comes between the author and the reader. This is as true on the web as it is in any other medium. If text has anything at all significant to say, it needs a typographer’s care. This will in turn be repaid by the reader’s attention, whether they are immersing themselves in great writing, or getting through a complex task.

Exceptional typography on the web emerges only when designers and developers share a systematic approach to fluidity in responsive design. This talk will provide designers with a rigorous way of working with responsive typography, and developers with that same knowledge, coupled with fundamental (yet underused) techniques and CSS. Above all it will provide designers and developers with a common understanding, and a way of working closely together starting in software and ending in the browser. You will learn how to:

  • Ensure visual harmony with type at its heart
  • Design a system within which elements scale proportionally and fluidly, instead of implementing x number of arbitrary and fragile breakpoints
  • Think about typography in ‘declarative’ terms (by setting durable rules the browser can follow based on context, rather than fragile ‘imperative’ pixel-by-pixel specifications)
  • Successfully set fluid type globally, but apply at a local, component-level
  • Design and code a typographic system minimally and elegantly
  • Streamline collaboration between design and development roles

Each step in the talk will give a brief theoretical setting with examples, backed up by the practical application to take away. Finally I’ll tie it all together by looking at how responsive typography has been implemented successfully into real world design systems.

It sounds like a lot to cover in 30 minutes, but the concepts are fundamentally simple. That said, thinking fluidly can require a bit of a shift in mindset – and that’s ultimately what I hope to achieve with the audience. I can’t wait – hopefully see you there!

Read or add comments

]]>
Typography CSS techniques Conferences
Sun, 15 Oct 2023 15:50:05 PST Pagination widows, or, Why I’m embarrassed about my ebook https://clagnut.com/blog/2426/ https://clagnut.com/blog/2426/

The physical copies of my book on Web Typography sold out quickly. I self-published, and print runs are expensive when you’re funding them yourself, so numbers were limited. However it was always my plan to publish an ebook at the same time, and that has out-sold the hard copy by an order of magnitude.

I set myself some pretty stiff criteria for the ebook – it needed to replicate the design of print edition as far as possible, adapting to the medium when required. To this day I’m proud of the result. I completely hand-coded the ePub (meaning it’s mostly HTML and CSS under the hood), and I believe the effort paid off. If you’ll forgive the rather un-British boasting, I still think it’s one of the more advanced ebooks out there: with embedded fonts, SVG images, alt text, bold typographic heirarchy, Javascript-driven syntax highlighting and what I hope is a nuanced, highly readable overall design. Not bad for an ebook anyway, although I’ll grant you the bar is not set high (notable exceptions include A Book Apart publications).

All hubris aside, I am still frequently embarrassed by how the ebook renders, particularly in Apple Books. Like a well structured webpage, my book uses a lot of headings and subheadings – I wrote it to be referenced as much as to be read, so this helps the scanability of the text. However Apple Books, and other WebKit, Gecko, or old Blink-powered ebook readers will happily do this to headings:

Screen shot of Apple Books rendering an ePub

Notice the orphaned heading “Lean on six centuries of typesetting experience” with its following paragraph out of sight on the next page. This is a typographic no-no, and has been for – um – six centuries. Far better for the reader to have the heading attached to its paragraph on the next page, even if that means leaving some redundant whitespace in its place.

Since 1997(!) and the early drafts of CSS2, there has been an easy way to tell browsers not insert a page break directly after, or in the middle of, a heading:

h2 {
    page-break-after: avoid;
    page-break-inside: avoid;
}

Nowadays the modern way to do that is defined in the CSS Fragmentation Module Level 3 even more simply as:

h2 {
    break-after: avoid;
    break-inside: avoid;
}

However 26 years later, break-after:avoid is still not supported by either Safari or Firefox, and was only introduced to Chrome 108 in December 2022. I’ve put together a test for support of break-after and break-inside in multi-column layout. Have a play with it in Chrome – try removing break-inside:avoid and then break-after:avoid from the h2 rule in the CSS and you should see how the subheadings end up at the bottom of a column, or worse still, split over two columns.

Browser support for CSS properties tends to follow demand from web developers. Unlike in 1997 – or indeed 2017 – there is now an annual Interop arrangement between browser rendering engine makers in which they agree a common list of priorities for CSS and other web technologies. Interop 2024 has just closed for new proposals. Unfortunately I didn’t manage to submit a request in time for breaking controls to be universally implemented. Thankfully Scott Kellum of Typetura did put in a proposal for advanced multi-column layouts to be improved, and this included support for break- properties. Sadly there’s little to no clamour for it from other developers – the blog post you’re reading probably doubles the published demand, and that’s just for within columns.

Update: Annoyingly the proposal was not selected for Interop 2024. I’ll just have to keep prodding the bug reports and keep my fingers crossed they are fixed soon – these bugs are older than some of my colleagues!

Paged media is very much a forgotten aspect, and it’s probably true that web pages are rarely printed in the grand scheme of things, however ebooks are definitely a popular form of paged media and deserve attention. I’d certainly like to read ebooks without failed typographic fundamentals.

Read or add comments

]]>
Browsers Typography CSS techniques Apple
Mon, 20 Mar 2023 17:04:09 PST Preventing too-short final lines of text blocks https://clagnut.com/blog/2425/ https://clagnut.com/blog/2425/

At the end of my previous post heralding an end to typographic widows on the web I wrote that I’d settle for direct control over widows and orphans in text blocks. It turns out not to be quite as a simple as one might think. Over the years, there’s been multiple discussions on the topic within the CSS Working Group (CSSWG). Following my post, I talked at length with other designers at Clearleft – in particular James Gilyead of Utopia.fyi fame – and it was surprisingly difficult to come to a definitive conclusion, particularly around the exceptions.

Put simply, one doesn’t want a solitary word (a widow) on the final line of a block. But the tricky thing to answer is: what’s the effect of bringing down a word from the previous line in order to address that? If you were fixing this manually there might be a ripple effect back up the paragraph until the best overall text shape is achieved. I doubt that’s something a browser could afford to do, given the (understandable) reluctance to implement any justification routines beyond the crudest greedy method.

Bit by bit, the CSSWG seems to have been converging on a potential solution. In the current draft of the CSS Text Module Level 4, there is mention of Last Line Minimum Length, which raises an Issue as follows:

Issue is about requiring a minimum length for lines. Common measures seem to be: at least as long as the text-indent; at least X characters; percentage-based. […] People have requested word-based limits, but since this is really dependent on the length of the word, character-based is better.

Amelia Bellamy-Royds took the Last Line Minimum Length idea and proposed a solution with a new min-last-line property. Her proposed property would specify a minimum length for the final line, and a minimum length for the penultimate line once you’d dropped a word or more down to address the short final line.

This seemed like a pretty smart approach. Inspired by Amelia’s idea and my conversation with James, the proposal I’ve come to is conceptually similar to the hyphenate-char-limits property. Set a minimum character length for the final line along with a maximum number of characters to bring down from the previous line:

min-last-line: 12 6

Where 12 is the minimum line length in characters, and 6 is the maximum number of characters that can be brought down from the previous line to make that so. If the 6 is omitted, it would assumed to be equal to the 12.

It might be useful to some people for the same approach to be expressed as percentages of box width instead:

min-last-line: 20% 10%

Where 20% is the minimum length of the final line in terms of percentage of box width, and 10% is the maximum length that can be removed from the previous line.

There’s no reason I can think of why these values couldn’t be mixed:

min-last-line: 20% 8

Meaning the last line shouldn’t be shorter than 20% of the block width, but you shouldn’t bring down more than 8 characters to achieve that.

I’ve put together a very rough-and-ready proof of concept here.

The idea is to have something to test out the concept of a minimum final line length and maximum amount of text that can be brought down from the line above to address that. Please feel free to have a play, copy, adapt and generally improve. Your comments are very welcome, preferably in the CSSWG issue thread.

Read or add comments

]]>
Web standards Typography CSS techniques
Tue, 07 Mar 2023 09:58:18 PST An end to typographic widows on the web https://clagnut.com/blog/2424/ https://clagnut.com/blog/2424/

Currently shipping in Chrome Canary, and thus soon to be in Blink-based browsers including Edge, is a relatively new CSS declaration which promises to virtually end typographic widows.

The text-wrap:balance declaration in CSS Text Module Level 4 says that line breaks should be chosen to balance out the line lengths in a block of text. How exactly that is done is ‘UA-defined’, in other words it’s determined by the rendering engine rather than any specific rules or guidelines set in the CSS specifications. This is how today’s version of Chrome Canary balances out one of the longer headings in this blog:

A screenshot showing a long heading with the final word dropped to the sewcond line as a widow
Default text wrapping
A screenshot showing the same long heading with the text split evenly over two lines
‘Balanced’ text wrapping

What this is not is control over widows and orphans. My previous examples show how the text balancing algorithm in Chrome Canary does indeed prevent a widow (the single word dropped down), and that’s a highly likely outcome. But you have to remember that the balancing job shortens the lines, so this isn’t an approach you would take to prevent widows at the end of paragraphs. In fact Canary limits balancing to 4 lines (the spec itself recommends 10 or fewer). The CSS spec itself makes the application clear:

the balance value is intended for titles and captions, where equal length lines of text tend to be preferred

With that in mind, this is the rule I’ve applied to this blog, and I’d say could end up in most people’s default reset:

h1, h2, h3, h4, h5, h6, caption, figcaption {
    text-wrap:balance;
}

Balancing left-aligned headings is not always preferable. I would love to have a value for text-wrap whose sole purpose is to prevent widows, without any other formatting involved. One could borrow from the widows property of the Fragmentation Module:

text-wrap: 2 widows  /* maybe one day */

Where 2 in this case specifies the minimum number of words allowed on the final line of a text block. There would have to be slightly more to it than this, in particular a single word should be allowed if the final two words together would be too long to fit inside the text block.

Another value in the specification is text-wrap:pretty. If it’s ever implemented, this might – as an outcome – reduce widows and orphans in running text. For decades there have been sophisticated algorithms for wrapping text across multiple lines. For performance purposes, browsers use the most basic approach, the so-called first-fit/greedy algorithm, which takes one line at a time, wrapping if it’s too long, and moving on to the next. In typographers’ eyes this gives sub-optimal results, and is one of the reasons text justification is so awful on the web.

Better algorithms, such as Knuth-Plass, take into account entire paragraphs and achieve a more nuanced approach to text wrapping by reducing and increasing spacing between words. The spec says that as optimal results often take more time, pretty is offered as an opt-in to take more time for better results. The pretty value is intended for body text, where the last line is expected to be a bit shorter than the average line. [… The browser] should bias for better layout over speed, and is expected to consider multiple lines, when making break decisions.

Algorithms such as Knuth-Plass won’t necessarily eliminate widows and orphans, but might go some way to doing so. The reluctance to using such approaches is understandable, however, as they can be extremely demanding: the processing requirements increase quadratically with the paragraph length. That said, a value such as pretty gives the option to choose different text wrapping procedures depending on conditions (resident processing power, length of text, etc). One day perhaps. Meanwhile I’d settle for direct control over widows and orphans in text blocks.

Read or add comments

]]>
Browsers Typography CSS techniques