-
Notifications
You must be signed in to change notification settings - Fork 0
Vertical Rhythm
Vertical Rhythm is the idea that reading text should be as rhythmic as listening to music. There’s a steady beat that keeps time, and you could “feel it” if a beat were skipped, shortened, or lengthened. As elements are laid out vertically on a page, the line height (leading) serves as the beat.
Every line of text on the page is exactly the same height (the line height) regardless of font size, and typographical block elements (headings, paragraphs, figures, block quotes, lists, tables, etc.) are separated by integer multiples or fractions of that height.
Xmeter uses the following conventions to preserve vertical rhythm.
To define our vertical rhythm unit, or “beat”, we use the calculated line height of the root element.
(This makes more sense than arbitrarily picking 10px.)
The root line-height is equivalent to the lh
unit, but
since that’s not supported by any browser yet (as of 2017-11-19), we create an --lh
custom property.
html {
--line-height: 1.5;
--lh: calc(var(--line-height) * 1rem); /* equivalent to `1lh` */
line-height: var(--line-height);
}
Not everyone wants to use a line-height of 1.5, so you may override the
--line-height
custom property in your own project as needed. For example
you could set html { --line-height: 1.25; }
in your stylesheet, and all calculations
using that variable, including --lh
, would update immediately.
To vertically space typographical blocks such as headings and paragraphs, we must push subsequent elements down the page. In this project we’ll use the convention of adding margin to the block-end side (bottom, in left-to-right-top-to-bottom writing modes).
h1, h2, h3, h4, h5, h6,
p, pre, figure, blockquote,
ol, ul, dl,
table,
form, fieldset, textarea,
details {
margin-bottom: var(--lh);
margin-block-end: 1lh; /* for browsers that support it */
}
To push an element itself down the page, we add block-start padding.
h1 {
padding-top: var(--lh);
padding-block-start: 1lh; /* for browsers that support it */
}
Sometimes, we overshoot and the element pushes its siblings too far down. In that case, we compensate by pulling the element up by removing block-start margin. This is useful for an element with borders, which can unintentionally contribute to vertical layout.
blockquote {
border: dotted gray;
border-width: 2px 0; /* oops, now the blockquote is 4px too tall */
margin-top: -4px;
margin-block-start: -4px; /* for browsers that support it */
}
Use the handy border tools to achieve this automatically. Note you can also use the box-shadow hack to give the appearance of borders, but it only works for borders on 1 side or 4 sides.
Design Components are self-contained modules that are used for a specific purpose.
They should be able to be moved around the page without changing their appearance.
Therefore, to keep the vertical typography independent, we use rem
s.
When the font size of a component changes, the line height
should remain unchanged, so that the component is scalable.
.c-ComponentName {
font-size: 0.75rem;
}
.c-ComponentName > * {
--lh : calc(0.75 * var(--line-height) * 1rem);
}
All the elements within .c-ComponentName
must update their lh
unit.
Normally this would be automatic, but, again, no browsers support it,
so we have to re-calculate --lh
.
The
.font-size-mod()
mixin makes this easy.
Within components, font size of a sub-component
should be set in em
s, so that its vertical typography scales with
its parent component’s font size.
.c-ComponentName > h1 {
font-size: 1.5em;
line-height: calc(var(--line-height) / 1.5);
}
In addition to font-size, line-height should be adjusted to maintain vertical rhythm. For example, if font-size is doubled (x2.0), the line-height should be halved (÷2.0) so that the final height of each text line is unchanged.
The exception comes when the new calculated line-height is smaller than the calculated font-size. This happens any time you use a ratio greater than the root line-height (in Xmeter, that’s 1.5). If you multiply the font-size by, say, 6, then instead of dividing the line-height by 6, you can divide by 3 (an integral factor of 6). That way, the resulting line height will be doubled, leaving room for the text when it wraps.
.c-ComponentName > h1 {
font-size: 6em;
line-height: calc(var(--line-height) / 3);
}
Use
.font-size-mod()
to do this automatically.
All line-height values are unitless. Line-height for all inline (text-level) elements is 0. This preserves vertical rhythm within a block.
span, br,
em, strong, i, mark, u, small, s,
dfn, b, abbr, var, q, cite, sup, sub,
data, time, code, kbd, samp,
label {
line-height: 0;
}
For more information on vertical rhythm, read these articles in 24ways and Smashing Magazine.