Relative units in CSS are measurements calculated from the environment, such as the size of the container, the browser window, or the user’s base typography.
So far we have used many pixels (px) because they are easy to understand. We tell a box width: 300px and it measures 300 pixels. Very convenient. The problem appears when that box lives on a screen that doesn’t have enough space, because pixels obey without thinking.
If your box measures 800px and the mobile phone has 390px width, the browser won’t say “oops, maybe I’ll adapt this a bit.” No. It draws it, it goes off to the right, horizontal scroll appears, and it looks terrible.
Designing responsive isn’t just about writing media queries. It’s about using measurements that can adapt before the page breaks.
Absolute vs. Relative
In CSS we have absolute units and relative units. Absolute units have a fixed size. The most common case is the pixel.
.caja {
width: 400px;
padding: 24px;
}
This can be perfectly fine for an icon, a border, a shadow, or a very specific detail. The pixel is not the enemy.
The problem is using it to define the entire architecture of a page, as if all users had the same screen, the same zoom, and the same eyesight.
Relative units, on the other hand, are calculated from another reference.
.caja {
width: 80%;
padding: 1rem;
}
Here the width depends on the container, and the padding depends on the root font size. In other words, the measurement adapts to the context.
Percentages (%)
The percentage is the most classic relative unit. When we use %, the browser calculates the value taking as reference usually the size of the parent container.
.contenedor {
width: 800px;
}
.columna {
width: 50%;
}
In this example, .columna measures 400px, because it is 50% of 800px. If the container drops to 500px, the column automatically drops to 250px.
Viewport Units (vw, vh, vmin, vmax)
The viewport is the visible area of the browser. It’s not the entire page, but the window through which the user is looking.
Viewport units are calculated by taking that visible window as reference.
1vwequals 1% of the viewport width.1vhequals 1% of the viewport height.1vminequals 1% of the smaller dimension between width and height.1vmaxequals 1% of the larger dimension between width and height.
.hero {
min-height: 100vh;
}
This rule says that the section must measure, at minimum, the full height of the visible window.
This is very useful for covers, welcome screens, full-screen panels, or areas where we want the first block to have presence.
.portada {
min-height: 100vh;
display: grid;
place-items: center;
}
Notice we use min-height, not height. If the content needs more space, the box can grow. Using height: 100vh without qualification can result in cutting off content on small screens.
Typographic Units: em and rem
Now let’s talk about relative units for text and spacing. Here we have em and rem.
Both are based on font size, but they don’t take the same reference.
The em unit depends on the font size of the element itself or the inherited context.
.caja {
font-size: 20px;
padding: 1em;
}
Here 1em equals 20px, because the box has font-size: 20px.
This can be very useful. For example, if a button has larger text, its padding can grow proportionally.
.boton {
font-size: 1rem;
padding: 0.75em 1.25em;
}
.boton.grande {
font-size: 1.25rem;
}
The large button not only increases the font. It also increases its padding, because the padding is in em. The component scales with itself.
The problem with em appears when we use it for font-size in nested structures.
ul {
font-size: 1.2em;
}
If you put a list inside another list, the calculation accumulates. The first list grows by 20%. The list inside it grows another 20% on top of the previous result. And so on, until the third level looks like it was written to be read from the other end of the room.
That’s why em is useful, but you need to know where to use it.
The rem unit stands for Root EM. It is always calculated relative to the font size of the root element (<html>).
By default, most browsers use 16px as the base size. Therefore:
1remusually equals16px.1.5remusually equals24px.2remusually equals32px.
p {
font-size: 1rem;
}
h1 {
font-size: 2.5rem;
}
The advantage of rem is that it doesn’t accumulate with nesting. It doesn’t matter if a paragraph is inside a card, inside a column, inside a layout. 1rem always looks at the root.
min(), max(), and clamp()
Modern CSS allows combining units with mathematical functions. They are tremendously useful for responsive design.
Selects the smallest value.
.contenedor {
width: min(90%, 1100px);
}
The box measures 90% of the available space, unless that exceeds 1100px. In that case it stays at 1100px.
Selects the largest value.
.seccion {
padding: max(1rem, 4vw);
}
The padding will never be less than 1rem, but it can grow with the viewport.
clamp() defines a minimum, an ideal value, and a maximum.
h1 {
font-size: clamp(2rem, 5vw, 4rem);
}
This means:
- Minimum:
2rem. - Ideal:
5vw. - Maximum:
4rem.
The title grows with the screen, but doesn’t become tiny on mobile or gigantic on desktop. It is a very elegant way to create fluid typography with sensible limits.
When to Use Each Unit
There is no universal answer, but there is a practical guide to avoid choosing units randomly.
| Unit | Use it for |
|---|---|
% | Container-dependent widths |
rem | Typography, spacing, and general sizes |
em | When something should scale with the size of the component itself |
vh / dvh | Height related to the window |
vw | Values tied to screen width |
px | Small, specific details: borders, fine shadows, or very precise adjustments |
