This article is what I have claimed and translated in the translation: using CSS to achieve baseline rhythm
Using CSS to achieve baseline rhythm
Vertical rhythm is a typographic concept that is often misunderstood by front-end engineers
The designers made the work look neat and tidy by arranging the contents in a vertical grid. If the front-end engineers can accurately achieve the same vertical rhythm, it will be easier and faster to develop a consistent and beautiful page. This process does not require the participation of a designer.
This article will help you build on the basics of achieving the right vertical rhythm in CSS. First I have to clarify which issues are not intended to be discussed here.
This concept has existed for many years. It introduces a universal line height value (or multiples) that applies to all elements, including both internal and external margins, and occasionally the width of the border into the calculation range.
At this point, depending on the CSS standard, the page content is arranged in the middle of two horizontal gridlines. However, two elements of different formats appear to be very discordant when they are arranged adjacent to each other.
There is a way to make the content of different font formats produce coordinated typesetting results. That is the baseline of the set text. Using this method, all content-regardless of its size-is aligned to the same grid line.
CSS doesn't provide any handy tools for this, so we have to do some tweaks manually. Here are two points to figure out:
How much content needs to be moved;
How to move the desired distance efficiently;
Determine the offset
Razvan Onofrei wrote a great essay explaining this part.
In short, a height above the base of a capital letter is called the cap height (that is, the height at which the browser automatically centers between gridlines). All we have to do is move it away from the difference between the line height and the cap height.
The cap height is a property of the currently used font. We can determine it by trying and fine-tuning different values until the text is aligned with the grid line.
The stylesheets of this site is based on this idea, excerpts from the following paragraph as follows:
$line-Height: 24px;$font-Stacks: (S:$font-Stack-Text,M:$font-Stack-Text,L:$font-Stack-Display,Xl:$font-Stack-Display);$font-Sizes: (S: 13px,M: 15px,L: 19px,Xl: 27px);$cap-Heights: (S: 0.8,M: 0.8,L: 0.68,Xl: 0.68);Accepts ' s ', ' m ', ' l ', or ' XL '@functionRhythm-Shift($size-Name) {$font-Size:Map-Get($font-Sizes,$size-Name);$cap-Height:Map-Get($cap-Heights, $size-name); $offset: ($line-Height - $ Cap-height * $font-size) / 2; @return round($offset);}
Apply Offset
Knowing how much text should be offset, we need to decide how to apply it reliably. To recap, we have several options to implement.
Scenario 1. Using relative positioning
Use top
attributes to move content without affecting the context.
$offset: rhythm-shift(m);.rhythm-m { position: relative; top: $offset;}
View the sample.
This may be the simplest option, but you will encounter at least two questions in this way:
position:
relative
affects the stacking order of the elements. If two elements overlap, the elements that are positioned relative to each other are displayed at the top level. Sometimes this can lead to z-index
manual fine-tuning beyond expectations;
position
May be used by other needs, such as the absolute positioning of the content;
This scenario is certainly sufficient when the codebase is relatively small and simple. But when our app architecture becomes more complex and needs to be more scalable, we abandon this approach.
Scenario 2. Use positive top padding and negative bottom margin
This scenario is recommended in the previous article that was mentioned:
$offset: rhythm-shift(m);.rhythm-m { padding-top: $offset; margin-bottom: -1 * $offset;}
View the sample.
The top padding shifts the content down as needed, and the negative bottom margin is used to compensate for this offset. Pay attention to using only one direction of margin, such as bottom margin. Otherwise, margin folding will destroy the entire layout system.
The biggest drawback of this scenario is the rapid increase in code complexity. In our app, for example, the public style class pt-1
adds a 24px top padding, which pt-2
is 48px (twice times the row height), and so on. If you use these classes together, you either need to add additional HTML containers, or you will overuse the Sass feature in order to generate all possible cases. Either way, the code becomes unwieldy and it is not easy to iterate the upgrade in the future.
Scenario 3. Use positive top margin and negative bottom margin
This is the final solution we will take:
$offset: rhythm-shift(m);.rhythm-m { margin-top: $offset; margin-bottom: -1 * $offset;}
View the sample.
As in the previous scenario, the top offset-this time the margin--is compensated by a negative bottom margin.
What about margin folding?
Fortunately, we have a very neat trick to solve this problem. But first, let's review the rules that are collapsed in the case of positive and negative margin:
For two positive margin, a large value wins. For example margin-bottom:
30px
and margin-top:
20px
, the gap between the last elements is 30px;
For two negative margin, again, the small value (meaning more negative) wins;
For a positive and negative two margin, they are added. For example margin-bottom:
30px
and margin-top:
-20px
, the result is a blank of 10px;
According to the last rule, if we always let the positive and negative margin appear alternately, their values will be offset against each other, and the text content will remain aligned with the grid line.
To ensure this effect, we decided not to use margin in the app except for the prosodic system. Although this is not a big loss, the unexpected margin is not always predictable.
Resolving margin leaks
The margin in CSS also has a disgusting feature: If an element is not set border or padding, and its first child element has a margin, then the margin is leaked to the parent element. This can cause problems when the parent element is set to background. This background overrides the child element's area, not the parent element.
There are two ways to resolve this issue.
Either use overflow:
hidden
the force to constrain the margin within the parent element;
Either add padding-top:
0.1px
, which is a tiny value hack. This value is so small that the browser cannot actually render it, but it is enough to keep the child elements within the container boundary of the parent element;
View the final example.
Everything is done here. We have successfully used this system on our own app for months.
Although CSS does not provide a system that can be used immediately, baseline cadence is fully achievable after we have properly built the underlying framework.
"Translation" using CSS to achieve baseline rhythm