CSS offers us root and relative values.
- Root values are like
remAndrlh– They are bound by the values written in the:rootselector (the most common would be thehtmlelement). - Relative values are like
em”lh”chand several others – they are bound by thefont-sizeIn that specific element.
I started to realize that we might have a unity between root and relative values. By having such a unity, we can include things without complex em or lh Calculations.
Let me give you an example: prose
Earlier this year, Jen Simmons about The use of the lh unit Style margin And padding for better Typographic vertical rhythm.
p { margin-block: 1lh; } We can expand the concept a little further to absorb all other spaces around the text. One way to do this is the “Lobotomized owl” technology That Heydon Pickering A while ago popular.
* + * {
margin-top: 1lh;
}Today we can also :not(:first-child) To achieve the same effect – and that can be a little more readable.
*:not(:first-child) {
margin-top: 1lh;
}We often have to limit these selectors so that they do not spill everywhere and break the rest of the page. A great class for this is .prose.
.prose {
*:not(:first-child) {
margin-top: 1lh;
}
}This is simple and good – but what happens if you record typography of other sizes …? You will see this breakdown incredibly fast (because 1lh of one
A way to circumvent this problem is to use Flexbox on the parent element. By doing this, we can set gap Unpleasant 1lh And we don’t have to deal with the value of 1lh change on the h2 element. (Bonus, we also do not have to deal with collapse of the margin.)
.prose {
display: flex;
flex-direction: column;
gap: 1lh;
}But we are introducing a new problem here: Proximity confusion.
Content below
. But content above the Belongs to the previous section Header. Ideally, we have to make the distance different to clarify their relationship.The easiest way is to have a small margin above the
But we can’t add a margin above
lh since the lh appreciate Will be different from those of the surrounding elements.We have to use a little CSS degrog and margin-bottom (or the logical equivalent) on the element above the
margin-bottom Unpleasant 1lh Because we use Flexbox and do not have to deal with the margin collapse. (If you were dealing with the collapse of the margin, you should set margin-bottom Unpleasant 2lh.)Is there a better way? Well, that’s what this article is about!
But before we go there, let’s look at another user interface that has similar problems, so that you can see the larger branches of this problem (and the importance of the solution).
Here is a second example: map component
Now let’s say that we have a card component that is divided into two parts, header and content.
In these types of components, the header is often styled with another font-size Then the content.
To make such a card, the simplest layout can be:
Unfortunately we can lh unity to make the filling within the map - this causes the margin on the
There are of course many ways to handle these kinds of situations.
A possible way is to change the Markup such
element. If we do this, we can apply the filling to the bypassing the enlarged 1lh problem.While changing the markup solves the problem, it’s not ideal — since we probably don’t want to create an extra header element unless it is necessary ...
Well, another possible method is to use a root value like rlh. This makes it possible
content To use the same basic unit and therefore to create the same filling.But we still come across problems when the .card must scales to different font-size Values. Imagine making a smaller card - now 1rlh Is not going well, because the filling value becomes too large in relation to the content.
What can we do?
A simple solution is to padding Value according to the supported variants of the component but this kind of thing is a bit hard coded and not very friendly ...
.card-sm { --padding: 0.75rlh; }
.card-md { --padding: 1rlh; }
.card-lg { --padding: 1.25rlh; }What is the alternative?
This is where an intermediary between root and relative units can come in handy.
The handy intermediate unit
This section is purely speculative CSS to illustrate a point. We will follow with a simple way to do this in a later part in practice, so hang tight and follow conceptually for the time being.
Let's say we have a unit that achieves its reference value of a specified element. We call this one base Unity, in the absence of a better name.
- So 1
baseFont-size unit1bem. - And 1
baseLine height unit1blh.
Pretty simple at the moment.
Imagine that we can style the cards with this basic unit. Then we can just use 1blh To quantify the filling and everything else would be made to measure in the right way:
.card {
> * { padding: 1blh; }
}
.card-sm { font-size: 0.8em; }
.card-md { font-size: 1em; }
.card-lg { font-size: 1.2em; }Hurrah?
Tie back to the .prose Example rather, it could very well solve the problem of proximity confusion without complicating our selectors:
.prose {
h2:not(:first-child) {
margin-top: 2blh;
}
}How can this work?
To easily allocate this function to modern CSS, I could think of in two possible ways:
- Attach this to containerquerys.
- Define a syntax comparable to anchor positioning.
The method for the containerquery
We already have things like cqw And cqh To indicate container width and container height. It is not too far from a call to say that we are one cqem (Container query em) unit or cqlh (Container query line height).
There are disadvantages to this approach.
Firstly, containers must be defined in a parent element. This requires more Markup and makes the code somewhat complex and not -intuitive. This code below can be a possible implementation:
.container {
container-type: inline-size;
}
.card {
> * { padding: 1cqbl; }
}Dealing with nested containers is not much a problem, because we always have the container-name We want to inherit. But there can be a collision if we want to use different container referees cqbl And cqw.
Imagine this:
A bit bad to be limited by collisions of containers.
Anchor -positioning syntaxis
In this case we first decide the basis that we want to inherit from. We can do this one base-anchorOr something similar.
Here we can explicitly set a basic name of the basic anchor - or maybe even leave behind none If we don't want to call it. Then the rest of the elements could immediately inherit from this basic value:
.card {
base-anchor: --card; /* or perhaps none */
> * { padding: 1blh; }
}If we have to refer to this anchor of a completely non -related component, we can use the anchor name and simply do this:
.far-away-comp {
base-name: --card;
/* Then use blh from here */
}Double anchor
A fascinating aspect that I can think of is a potential user facility base can be component in heirs font-size Or value of another base or the upper element.
With this flexibility we can make incredibly easy component variations based on letter sizes without having to rely on complex em Calculations.
Here is an example of what I am talking about:
.prose {
base-anchor: --prose;
font-size: 1em;
line-height: 1.5;
}
/* Inherits font-size from .prose */
/* This is automatic if base-name is not provided */
.card {
base-anchor: none;
base-name: --prose;
/* In this case, 1blh could be 1.5em */
> * { padding: 1blh; }
}
/* After inheriting the font size, since we have a base-anchor in the card, we adjust the font-size value accordingly, so:
- 1bem would mean 0.8em further in the card
- 1blh could then mean 0.8 * 1.5em = 1.2em
*/
.card.card-sm {
font-size: 0.8em;
}Fascinating, yes? This ensures a completely new possibility when creating reusable components.
Putting into practice today
Let me precede this part with the fact that bem And blh Doesn't exist today. So whatever implementation I can think of is just an imperfect stop-gap measure.
Today we are sure that we are the em unity for such a goal - But this requires a little more calculation, since then em Is a family member, not a basic unit.
The first step is to base element - and the base font size - that we can do by setting it base-size property:
.card {
--base-size: 1em;
font-size: var(--base-size);
}
.card-sm {
--base-size: 0.8em;
}We can then bem (base em) unity by sharing the intended font-size with the base-size:
.card {
h2 {
--font-size: 2em;
font-size: calc(var(--font-size) / var(--base-size));
}
}Unfortunately, the above code does not work because we do not calc() Division with a unity value. So the best we can do to remove the units from --base-size.
If we do this, we must perform a different one calc() on the basic element to make the actual font-size property:
.card {
--base-size: 1;
font-size: calc(var(--base-size) * 1em);
}Then we perform the same calc() in the
.card {
h2 {
--font-size: 2;
font-size: calc(var(--font-size) / var(--base-size) * 1em);
}
}This all starts to get a bit of "ugh".
Nobody wants all this boilerplate code. So this can best be abstracted with a Mixin, or perhaps even a function. If you use SASS, you can imagine something like that:
@mixin base-anchor() {
font-size: calc(var(--base-size) * 1em);
}If you use in the tail wind, you may be able to imagine the utility in the tail wind. After all, Togtewind tools can be seen as handy Sass Mixins.
@utility base-anchor {
font-size: calc(var(--base-size) * 1em);
}We can then apply this utility to the basic element. The code looks a bit cleaner:
.card {
@apply base-anchor;
--base-size: 1;
}
.card-sm { --base-size: 0.8; }For the
@utility text-relative {
font-size: calc(var(--text-size) / var(--base-size) * 1em);
}We can then use the utility as follows:
.card .title {
@apply text-relative;
--text-size: 2;
}Now to padding of the map for the .title element, we have to font-size around the base-size value. This can best be done with a CSS function, which is not supported on a large scale today, but hopefully soon!
@function --bem(--multiplier) {
result: calc(var(--text-size / var(--base-size) * 1em * --multiplier));
}We can then use --bem To calculate the filling on the card title:
.card .title {
/* ... */
padding-block: --bem(0.5);
padding-inline: --bem(1);
}We said above that the lh Value works better for margin and filling, because it retains vertical rhythm. So why wouldn't you --blh Also function?
In this case we can --leading Variable what the function of can inherit:
@function --blh(--multiplier, --lh-multiplier) {
result: calc(
var(
--text-size / var(--base-size) * 1em * --multiplier *
var(--lh-multiplier, var(--leading))
)
);
}Then we can use --blh like this:
.card .title {
/* ... */
padding-block: --blh(0.5);
padding-inline: --blh(1);
}In today's spirit
We can't use --bem And --blh In production because CSS functions are not all browsers available yet. In the spirit of bem work nowWe can make an utility that the --base-font-size from the --font-size.
Note that this new variable is called --base-font-sizenot --base-sizesince --base-size is already used. (We cannot overwrite the CSS variable.)
/* I multiplied the value by 1em here to make it easy for you to use the value */
@utility base-font-size {
--base-font-size: calc(var(--base-size) / var(--font-size) * 1em);
}We can also make an utility base-line-height To get the value of the line-height. If we do this, it is much easier if we also pass --leading Variable:
@utility base-line-height {
--base-leading: calc(var(--base-font-size)* var(--leading));
}Then we can use calc on --base-leading To get the values we want:
.card .title {
@apply text-relative;
@apply base-font-size;
@apply base-line-height;
--font-size: 2;
padding-inline: var(--base-line-height);
padding-block: calc(var(--base-line-height) * 0.5);
}Put all the way together
First, let's put together the necessary utilities and functions to make this happen today:
/* The necessary utilities */
@utility base-anchor {
font-size: calc(var(--base-size) * 1em);
}
@utility text-relative {
font-size: calc(var(--font-size) / var(--base-size) * 1em);
}
/* To use this today */
@utility base-font-size {
--base-font-size: calc(var(--base-size) / var(--font-size) * 1em);
}
@utility base-line-height {
--base-line-height: calc(var(--base-font-size)* var(--leading));
}
/* Easier usage when CSS Functions become available */
@function --bem(--multiplier) {
result: calc(var(--font-size / var(--base-size) * 1em * --multiplier));
}
@function --blh(--multiplier, --lh-multiplier) {
result: calc(
var(
--font-size / var(--base-size) * 1em * --multiplier *
var(--lh-multiplier, var(--leading))
)
);
}Now here is the .card Code to achieve the functionality in tail wind that we were talking about. You can see it here at work.
/* What we can actually use today */
.card {
@apply base-anchor;
--base-size: 1;
--leading: 1.5;
> * { padding: 1lh; }
.title {
@apply text-relative;
@apply base-font-size;
@apply base-line-height;
--font-size: 2;
padding-inline: var(--base-line-height);
padding-block: calc(var(--base-line-height) * 0.5);
}
}
.card-sm {
--base-size: 0.8;
.title {
--font-size: 1.2;
}
}
/* What we can use when CSS Functions are available */
.card {
@apply base-anchor;
--base-size: 1;
> * { padding: calc(--blh(1)); }
.title {
@apply text-relative;
--text-size: 2;
padding-block: calc(--blh(0.5));
}
}It is still not as beautiful as the bem And blh Versions that I showed you above, but at least we achieve some kind of functionality, yes? And it doesn't look half bad!
Use this with Splendid Labz today
Beautiful styles - The branch of Splendid Labz That treats design and styles - contains the code that you can use today.
We also have the --bem And --blh Versions if you also want to play with them.
To use beautiful styles, just download the library base-font-size File and do what you have just seen the above!
npm i @splendidlabz/styles@import '@splendidlabz/styles/typography/base-font-size.css'That's it!
Now, if you are interested in all the tools that I have achieved to make web development easier, you can grab an early bird discount The beautiful Pro package Today-this is available for all CSS tricks readers!
(I could add a lifelong option to the Styles package as it evolves sufficiently. But it can be a year or so before that happens.)
Okay, enough promotion. Let's come back here.
What do you think of this unit between root and relative values?
I hesitate to call it "basic" em Because "basic" can mean so many things. But it also sounds at the same time.
- Do
bemAndblhLogical for you? - Do you think I think a bit too much for this design aspect?
- Maybe you have a better name for this?
I would like to hear from you, so don't hesitate to share your thoughts below!
#root #relative #CSS #units #basic #elements #CSS #tricks


