Smarter Responsive Calculations With CSS round()
A responsive width sometimes needs to grow in steps rather than change with every pixel of viewport width. CSS round() rounds a calculated value to a chosen interval, such as the nearest 50 pixels.
Functions such as calc(), min(), max(), and clamp() handle calculations and limits. round() adds control over the increments between values.
CSS round() with a responsive width
.box {
width: round(47vw, 50px);
}
The browser calculates 47vw, then rounds that length to the nearest multiple of 50px. A calculated width of 623px becomes 600px; 628px becomes 650px.
The width stays at one step until the calculation crosses the next rounding threshold. That makes the change deliberately visible, which can suit a component with fixed size steps.
A stepped width will feel different from a fully fluid one. Use it when those jumps serve the design, rather than adding rounding to every responsive value.
Choose which way the value rounds
The default strategy is nearest. The CSS rounding rules also define up, down, and to-zero.
.round-up {
width: round(up, 621px, 50px);
}
.round-down {
width: round(down, 621px, 50px);
}
.toward-zero {
margin-left: round(to-zero, -105px, 10px);
}
The widths become 650px and 600px. The negative margin becomes -100px.
For negative inputs, down moves toward a more negative value, while to-zero moves toward zero. With -105px and a 10px interval, down would produce -110px.
An exact halfway value rounds toward positive infinity with nearest. For example, 625px rounds to 650px when the interval is 50px.
Keep responsive spacing on a scale
A gap can grow with the viewport while staying on a four-pixel scale:
.grid {
display: grid;
gap: round(2vw, 4px);
}
Calculated gaps of 19.36px, 22.71px, and 27.18px become 20px, 24px, and 28px. The same rounding rule applies as in the width example.
Rounding alone does not set a minimum or maximum. If the spacing needs limits, use a bounded input, as in the button example below.
Count how many columns fit
Suppose cards should be about 250px wide, with a 16px gap. Dividing the available width plus one gap by the card width plus one gap gives a column count.
A wrapper provides the width used in the calculation:
<div class="cards-wrapper">
<div class="cards">
<article>First card</article>
<article>Second card</article>
<article>Third card</article>
</div>
</div>
.cards-wrapper {
container-type: inline-size;
}
.cards {
--card: 250px;
--gap: 16px;
display: grid;
gap: var(--gap);
}
@supports (width: calc(1px / 1px * 1px)) {
.cards {
--columns: max(1, round(down,
(100cqw + var(--gap)) / (var(--card) + var(--gap))
));
grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
}
}
At a container width of 800px, the calculation gives three columns. The max() call keeps the count from reaching zero in a narrow container.
Container query units use an eligible ancestor container. Setting container-type on the wrapper lets 100cqw measure that wrapper from inside .cards.
Dividing two lengths also requires support for CSS typed arithmetic. The feature query checks that extra requirement; without it, the grid keeps a single column.
CSS Tip extends this idea to grid information such as row counts. Those examples combine several features, so support for round() alone does not establish support for the whole technique.
Fixed values rarely need rounding
A declaration such as width: round(623px, 50px) can simply be written as width: 600px. The function adds little when both inputs are already known.
The useful cases involve a changing input: a viewport length or a custom property, for example. Keep the calculation when it describes a rule the design actually needs.
Bound a button width before rounding
.button {
width: round(clamp(160px, 30vw, 320px), 20px);
}
The button changes in 20px steps between 160px and 320px. Both limits are multiples of the interval, so rounding keeps the result within those bounds.
That detail matters: rounding an already clamped value can move it beyond a limit that falls between steps. Choose aligned limits, or apply the final bounds outside round().
Keep a fallback for older browsers
MDN lists round() as Baseline 2024. Older browser versions may still need a fallback.
.card {
width: 60%;
}
@supports (width: round(60%, 10px)) {
.card {
width: round(60%, 10px);
}
}
The base declaration gives the card a fluid width. Supporting browsers apply the stepped version, while browsers without support keep the percentage width.
Let Grid handle ordinary card layouts
An explicit column count is useful when another part of a component needs that number. For a grid that only needs to fit cards into rows, Grid’s auto-placement pattern is usually easier to maintain:
.simple-cards {
display: grid;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
The 16rem minimum still needs to fit the available space. Check the narrowest container where the component will appear.
Keep the explicit maths for cases where the calculated number has a purpose. A spacing scale or stepped control width makes the rule easy to see; an ordinary card grid rarely needs its column count calculated twice.
Enjoyed reading this?
If you found this article helpful, consider supporting my writing. Every little bit helps keep this blog going.
Related articles
- Better Line Breaks With CSS balance and pretty
Use text-wrap balance for short headings and text-wrap pretty selectively for longer copy without hard-coded line breaks.
- Why 100vh Doesn’t Always Fit a Mobile Screen
Why 100vh can exceed the visible mobile screen. Choose svh, lvh, or dvh, let content grow, and put older Safari workarounds in their historical context.
- Making Links Easy to Recognize
Make links recognisable with underlines, clear focus states, useful text, and behaviour that does not surprise the reader.