Text, like Colors is a topic that appears simple on the surface, but once you dig down, it becomes apparent that it is anything but. Over the years we’ve learned that what designers expect from a type system does not always match how Apple and other vendors built their text layout systems.
The way that Sketch handles text is something that we had wanted to improve upon for quite a while, but as you continue to read, you’ll soon discover that undertaking these changes and improvements required us to take a deep dive into Apple’s text rendering system and make some low-level changes. We think we emerged victorious in the end, and we hope you’ll like the result.
To understand some of the problems we needed to solve, let’s first look at the vertical metrics of a text layer in Sketch:
The height of a single-line text layer is determined by the font’s line-height value for the text size. This value does not correspond to the text size and it varies widely across different fonts; sometimes it’s nearly the same as the text size, at other times its double the size. Where the font gets drawn within that space is determined by the baseline (in red) which is also specified by the typeface.
Since both vary so wildly between fonts, text layers in Sketch can change quite dramatically when you switch between fonts, and especially when you mix multiple fonts and sizes in the same paragraph. Another undesirable effect of this was that text on the canvas often shifted up or down when you switched between fonts.
A question that often appears in our support inboxes — asks why Sketch renders the seemingly blank areas (highlighted in blue), and doesn’t trim the bounding box to the edges of the ascenders and descenders in the layer. These are also determined by the font’s metrics, but to simply put it, this space is needed by some characters, particularly those who contain diacritics. The caron that can appear on an uppercase S (Š, found in Czech and other Slavic languages) and a lowercase c with a cedilla (ç, most common in Turkish and French) are two of many examples.
In Sketch 3.6 we’ve made some changes to the way we typeset text layers, particularly for paragraphs with fixed line height. To understand how it works, and what’s changed, we need to have a look at Apple’s Text System, how it lays our lines of text, and how all that applies to Sketch.
Characters and Glyphs
The first step of laying out a paragraph of text is to convert the text’s characters and font attributes into glyphs. Glyphs are the visual representation of one or more characters for a given font. The mapping between characters and glyphs isn’t 1:1. For example, a single glyph can represent more than one character—these are called ligatures. The same characters ordered differently might produce different ligatures and therefore a different number of glyphs. The most extreme ligature we’ve ever come across is “Zapfino” in the Zapfino font. The seven characters are represented by a single glyph:
Text Containers and Line Fragments
How many glyphs we can fit on a line is determined by the text container’s width. In Sketch, the size of the text container is determined by the width of the text layer. To fill the text container with glyphs, we need to split it into lines. The rectangles containing all glyphs that fit on a single line are called “line fragment rectangles”. As long as you use a single font or size in a paragraph everything looks as one would expect:
In normal typesetting, the height of the line fragment is determined by the tallest font on that line (to be precise; sum of the font’s ascent above and descent below the baseline). Mixing fonts can produce line fragments of different heights, which is where things start to get interesting:
Fixed Line Height
Paragraphs can also specify a minimum and/or maximum line height. This limits the height of the line fragment rectangles. If we use the same value for minimum and maximum, we get a fixed line height. Historically this is what setting line height in Sketch would do. It works well for paragraphs of the same font.
Paragraphs with mixed fonts often didn’t look right in Sketch. We set a fixed line height though, so what went wrong? The answer to that is finding out where the typesetter chooses to place the baseline within the line fragment rectangle.
It turns out that for each line fragment, Cocoa’s typesetter finds the tallest descender on that line and uses that as the baseline offset from the bottom of the line fragment rectangle. With mixed fonts this gives us a fixed line height, but an inconsistent baseline separation.
When designers speak of setting the line height to, say, 20pt, what they mean is they want 20pt between the baselines, and not line fragment rectangles of 20pt height. That makes sense because what determines the visual vertical rhythm of text is the baseline, which is much more ‘visible’ than these abstract rectangles. So how did we fix this?
Consistent Baselines
In Sketch 3.6 we’re introducing a new typesetter which produces consistent baseline offsets for paragraphs with a fixed line height. To make that work we’re looking at all of the line fragments in a paragraph and choosing a baseline offset which suits them all.
The consistent baseline offset is also maintained between paragraphs, even with varying fonts, as long as they have a fixed line height. When no fixed line height is set, we use the one the font indicated, which as we saw can leave us with varying results. When you set it to fixed, you get a beautiful, predictable vertical rhythm:
How does this work with existing documents? New text layers use the consistent baseline typesetter by default and text layers created in earlier versions of Sketch can adopt the new typesetting behavior by changing the line height.
Other Improvements
Our improvements to line height also positively impact editing for paragraphs with lower line heights than their font size, since the baseline is always within the line fragment rectangle. It also improves the bounding rectangle for text layers.
Finally, when changing fonts for text layers, we’ve gone to some lengths to preserve the position of the first baseline, so your text layers will no longer jump around vertically when changing between fonts.
One last note
As you may have noticed, digital typography is an extremely complex issue. We’re living in an exciting era, where we have realized that it’s almost impossible to make a design look exactly the same on every device and platform.
For us, it’s also impossible to create a system that renders type exactly like iOS, or Android, or Chrome in Windows, or Safari in Mac. The rendering differences between all of them are very complex and diverse.
We’ve listened to your feedback and tried to create a very consistent and reliable rendering system. We’re making a strong emphasis on line spacing on this update, but we’re just getting started. This is the first part in a series of type improvements we plan to release this year.