Print, in the past forty years, has gone almost completely digital. While most of us still sit down with a pen and paper to sketch our ideas and flesh out layout mechanics, we design our spreads and set our type on the computer. Through tools such as InDesign and (once upon a time) Quark, layout, kerning, color – everything, really – has been made incredibly easy once you understand the tools.
Yet, little by the way of setting print-quality type is discussed on the web. While our toolset is still very young and, dare I say, immature, there is a lot we can do to create delectable, readable typography with just HTML, CSS, and perhaps a little JavaScript.
The Key Parts
While it’s possible to write an entire book on print typography and how it can be brought to the web (in fact, it has been done, in part), there are a few select parts we will focus on in this article:
- Typesetting: what do we have to work with?
- Sticking to a baseline to achieve vertical rhythm.
- Kerning.
What do We Have to Work With?
Let’s work from what we know is possible in print. Above is the majority of typesetting tools provided to us in Adobe InDesign CS4; a vast array of things to tweak and (carefully) adjust.
Below, each feature from the InDesign palettes has been mapped to a feature of CSS (or an augment in JavaScript).
Feature | CSS-equivalent Rule(s) | Browser Support | Notes and Exceptions |
---|---|---|---|
Type family |
|
All | |
Font |
|
All | |
Font size | font-size: n[px|em|ex|rem|…]; |
All | |
Leading | line-height: [n|n[px|em|ex|rem|…]] |
All | |
Kerning | No CSS equivalent; augment with Kerning.js or Lettering.js | Both Kerning.js and Lettering.js work in all modern browsers. | These libraries should not be used on body copy. |
Tracking | letter-spacing: n[px|em|ex|rem|…]; |
All | |
Vertical scale | -[webkit|moz|o|ms]-transform: scaleY(n[px|em|ex|rem|…]);
| Chrome, Safari, Firefox, IE10 | Scaling type is generally not recommended. Use scale3d for hardware acceleration (not yet available in Firefox). |
Horizontal scale | -[webkit|moz|o|ms]-transform: scaleX(n[px|em|ex|rem|…]);
| Chrome, Safari, Firefox, IE10 | Scaling type is generally not recommended. Use scale3d for hardware acceleration (not yet available in Firefox). |
Baseline shift | No CSS equivalent; Wrap text in <span></span> and apply margin-top: -n[px|em|ex|rem|…]; |
All | Alternatively, Kerning.js or Lettering.js can handle this in headers. |
Skew (false italic) | -[webkit|moz|o|ms]-transform: skewX(ndeg); |
Chrome, Safari, Firefox, IE10 | Generally not recommended. Use real italics. |
Alignment | text-align: [left|center|right]; |
All | |
Justification |
|
text-align : All; text-justify : IE only. |
There is no way to do “[left|center|right] justify,” except in IE. |
Paragraph indent | padding-left: n[px|em|ex|rem|…]; |
All | |
First-line indent | text-indent: n[px|em|ex|rem|…]; |
All | |
Space before/after | [padding|margin]-[top|bottom]: n[px|em|ex|rem|…]; | All | |
Drop cap | *:first-letter pseudo selector |
Chrome, Safari, Firefox, Opera, IE8+ | This only works for the first letter of the paragraph. |
Drop cap (number of characters) | No CSS equivalent for 2+ characters; augment with <span></span> and apply float: left; |
All | |
Text wrapping |
No current CSS-only solution for complex shapes; augment with CSS Text Wrapper. |
float : All; white-space : Chrome, Safari, Firefox, Opera, IE8+ |
Multiple rules required for white-space . |
Optical margins | No CSS equivalent; no augment; hang opening quotes with text-indent |
None | Alternatively, Kerning.js or Lettering.js can handle this in (very) short copy or headers. |
Ligatures | text-rendering: optimizeLegibility;
| Firefox, Safari, Chrome | This is a non-standard rule and has a few “gotchas,” such as automatically being applied on copy larger than 20px in Firefox, doing nothing at all on OS X, breaking small-caps, and causing weird rendering issues on Linux. |
Underline | text-decoration: underline; |
All | |
Strikethrough | text-decoration: line-through; |
All | |
Hyphenation |
|
white-space : Chrome, Safari, Firefox, Opera, IE8+; word-wrap : IE only. |
There is no way to automatically control where hyphens appear, though those features will be available in the future. |
Orphans and widows | No CSS equivalent; augment with a jQuery “widon’t” snippet. | None | |
Other notes:
|
Not bad! We can do most of what InDesign offers print designers, and while we lack some of the more fine-grained control, we can augment it to an extent.
However, having the tools to set the type itself is only one part of the story. What about aligning the content on a consistent baseline grid?
Vertical Rhythm
“Space in typography is like time in music. It is infinitely divisible, but a few proportional intervals can be much more useful than a limitless choice of arbitrary quantities.” — The Elements of Typographic Style (3.1), p36
And with that, Robert Bringhurst sets the tone for finding a vertical rhythm. In print, this is easy, as you just set your baseline grid and follow that with your leading throughout. If you set 11/13 (11pt type with a 13pt leading), then everything must be set in proportion to the 13pts. If you have a 26pt header, you may use a 26pt (2 x 13pt) or 39pt (3 x 13pt) leading to keep the baseline steady.
While this is more difficult on the web given dynamic images and content, browser sizes, and rendering differences, we can come pretty close to a consistent baseline grid.
I highly recommend using a JavaScript baseline grid tool, such as the handy Heads-Up Grid. The Heads-Up Grid overlays an easily configured grid over your page, which you can toggle on and off as you work. It’s unobtrusive and allows you to easily set margins, a baseline grid, and columns.
pageUnits = 'px'; colUnits = 'px'; pagewidth = 600; columns = 3; columnwidth = 180; gutterwidth = 20; pagetopmargin = 20; rowheight = 22; // This is our baseline grid height, in px
Once we have established a baseline grid, we want every element on our page to follow this grid. That means all paragraphs, images, and headers should fit into the grid proportionally.
Let’s say we have a header, two paragraphs, and an image:
Right now, we haven’t styled the content and don’t conform to the 22px baseline grid we defined. To do this, we’ll need to use a combination of line-height and margins.
h1 { font-size: 32px; line-height: 44px; /* 44px = 22px x 2 */ padding: 0; margin: 0; } p { font-size: 14px; line-height: 22px; margin: 0; } img { height: 398px; /* Since our image is only 398px tall, but 398 isn’t a multiple of 22, * we need to add margins to conform to the baseline. 22 * 19 = 418, so we’ll * add 10px to the top and bottom. It doesn’t matter whether we split the * margins on top/bottom, as long as it adds up to 8px. */ margin: 10px 0; }
That will give us a nice, clean result with the content residing within our baseline grid. (It’s easiest to aim to be within, not on, the baseline grid. You can aim to perfect this, but it isn’t necessarily worth the time.)
The trick is to maintain padding, line-heights, and margins in a proportion of 22px (our baseline grid height) everywhere in the document. However, it doesn’t necessarily need to be the case on every single element, as long as adjacent elements, together, fit the grid.
Kerning
It’s been possible to track type in CSS for ages using the “letter-spacing” rule. Unfortunately, there has been no way to tweak the spacing just between pairs of letters, also known as “kerning,” in CSS.
While good fonts often contain their own kerning rules, many fonts are poorly kerned and many display (headline) faces do not contain any rules. This leaves it up to the designer to modify the spacing to his/her liking and to create an evenness between the letters. It is, essentially, a vital detail of design that has long been overlooked on the web.
On the upside, some JavaScript libraries have been created to help augment the lack of word- and letter-level typographic control: Kerning.js
and Lettering.js
(disclosure: I created Kerning.js). Both of these tools are incredibly easy to apply to your own content and are completely unobtrusive (so if they fail to work or load, your content will be okay).
On the downside, these libraries can really only be used on ‘large’ type: headers and short blurbs. Using them on body copy would be absolutely disastrous, as they break letters and words down into individual DOM elements to allow styling.
First up is Lettering.js, which gives you letter-level control through CSS selectors.
It’s very easy to apply:
$(document).ready(function() { $(".some_headline").lettering(); });
This code will break your content down into individual span elements, with classes applied to each, allowing you to style each letter individually:
<h1 class="some_headline"> <span class="char1">Y</span> <span class="char2">o</span> <span class="char3">u</span> <span class="char4">r</span> <span class="char5"></span> <span class="char6">T</span> <span class="char7">e</span> <span class="char8">x</span> <span class="char9">t</span> </h1>
To kern text, you then simply adjust the margins:
.some_headline .char1 { margin-right: -2px; } .some_headline .char3 { margin-right: -1px; }
This is great, especially if you intend on applying a number of different styles and transforms to each individual letter.
On the downside, you can end up with a lot of extra CSS, especially if you intend on kerning each letter. Additionally, this only works well if you know your content; you cannot apply general rules (like always kerning certain letter pairs) to Lettering.js-ed
content.
That is where the most powerful (and slightly more complex) library, Kerning.js
, comes in.
Kerning.js creates several all new CSS rules that allow you to style content automatically and dynamically.
If we take the same .some_headline example we used with Lettering.js
, we can kern the type in two ways.
The first method is very similar to Lettering.js
‘ style:
.some_headline { -letter-kern: -2px _ -1px; }
Here, we use just one rule to specify that we would like to kern the first and third character (as in the original example). The JavaScript library will automatically read this rule and apply it to your content.
Alternatively, if we would always like to kern the “Yo” and “ur” letter pairs, we can create a rule for that:
.some_headline { -letter-kern: -letter-pairs( 'Yo': -2px, 'ur': -1px ); }
Now every time we use the .some_headline selector in our page, ‘Yo’ and ‘ur’ will automatically be kerned, whether the text is “Your Text,” “Oh, You Sure?” or anything else.
Other Type Assistants
It doesn’t fit into any of the sections mentioned above, but I also wanted to mention FitText.js, another JavaScript library that allows for automatic, responsive text resizing.
This means that your font-size will be automatically adjusted as you resize your browser (or view your site on a different device).
To use FitText.js
, all you need to do is apply it to the content you would like automatically resized:
<script src="jquery.fittext.js"></script> <script> $("#responsive_headline").fitText(); </script>
As you resize the browser, your content’s font-size will be automatically adjusted. There are also more options, available in the documentation, that let you control how aggressively the content is adjusted.
Conclusion
While far from complete, there is a vast typesetting toolset available for us in CSS. With some extra effort and a few JavaScript-based fixes, there is no excuse to not create print-quality typography on the web.
CSS will eventually be at parity with print; but right now, we’re pretty close.