One Equation To Rule Them All

CSS has evolved to the point where we can control fluid values directly with the clamp() function, eliminating the need for multiple media queries that simply adjust font-size, padding, or margin. You write one rule with a preferred value and min/max bounds, and the browser handles everything in between. That said, media queries are still essential for changing colors, borders, shadows, and other styles that don't scale linearly.

The key trade-off is that while a simple fluid adjustment is trivial with clamp(), many developers still write several breakpoints for what is essentially the same underlying problem: a value that must change linearly within a specified viewport range, but stay constant outside of it. Consider this typical pattern:

.block{
 font-size: 2rem;
}
@media (max-width: 1200px) {
 .block{
   font-size: calc(-1rem + 4vw);
 }
}
@media (max-width: 800px) {
 .block{
   font-size: 1rem;
 }
}

…which can be replaced by the single clamp() expression below:

.block{
 font-size: clamp(1rem, -1rem + 4vw, 2rem);
}

But real layouts often have more nuanced behavior, with different rates of change across different screen widths. That’s when a more complex set of rules appears:

.block{
 font-size: calc(-4rem + 8vw);
}
@media (max-width: 1200px) {
 .block{
   font-size: calc(-1rem + 4vw);
 }
}
@media (max-width: 800px) {
 .block{
   font-size: calc(0.5rem + 0.8vw);
 }
}

The question is whether clamp() can also handle these piecewise-linear cases without piling on breakpoints.

Calculating The Interpolation

The answer lies in a small piece of math: there is exactly one straight line that passes through any two given points. Standard line notation y = y0 + k*x describes where that line crosses the Y-axis (y0) and how steeply it rises or falls (k). For our purposes, a “point” is a (viewport width, property value) pair, and we need to express both in units CSS understands.

Pixels are the natural unit for defining the two points, because that’s how design specs typically communicate breakpoints and values. However, the final CSS margin, padding, or font size should ideally be declared in relative units like rem so that user preferences and zoom settings are respected. And because the viewport width in CSS is always 100vw, the line equation becomes:

y = y0 + k*100vw
A graph with a straight line
A straight line drawn through two points with coordinates (x1, y1) and (x2, y2). (Large preview)

That is why you constantly see expressions such as 1rem + 2.5vw inside clamp() or calc(). The first term is the Y-axis intercept y0 expressed in rem, and the second term is the slope k multiplied by 100vw. Choosing rem for the output and vw for the viewport input keeps the result both accessible and responsive.

So with a simple formula connecting the slope and intercept to the coordinates of the two given points, you can compute the exact clamp() argument for any fluid property that changes linearly between two viewport widths. The same calculation scales to multi-range layouts: instead of four media queries, you derive a piecewise definition from several line segments, each clamped to its own min and max.

Deriving the General Formula

Let’s derive a general equation for a function F(x) that reproduces a piecewise-linear property behavior. The property is defined by N points (xi, yi), with straight lines fi(x) drawn through consecutive points, giving (N-1) line segments. The goal is a single function equal to fi(x) on each interval [xi, xi+1].

An example of behavior of the values for some CSS property
Fig.2. An example of behavior of the values for some CSS property. (Large preview)

Define each segment function gi(x) using the clamp function:

gi(x) = clamp(yi, fi(x), yi+1)

By the definition of clamp, this equals yi when x < xi, equals fi(x) when xi ≤ x < xi+1, and equals yi+1 when x ≥ xi+1.

Now sum all gi(x) functions. Call the result G(x). Evaluating G(x) on the interval [xi, xi+1] gives fi(x) plus a constant term equal to the sum of all yj values except y1 and yN. Subtracting that constant yields the final formula:

F(x) = Σi=1N-1 clamp(yi, fi(x), yi+1) − Σi=2N-1 yi

This is equation (3), the complete solution.

Notes and Edge Cases

  • If yi = yi+1, the segment is flat and clamp(yi, yi, yi) = yi, which simplifies the expression.
  • For a segment where yi > yi+1, the gi(x) function must be written in a different order due to the definition of clamp:
function
(Large preview)
  • Outside the defined range, equation (3) produces constant values y1 for x < x1 and yN for x > xN. To let the property continue changing beyond the endpoints, replace g1(x) with a min or max function (depending on the slope direction), and likewise for gN-1(x):
function
(Large preview)
function
(Large preview)
  • An abrupt change can be represented by setting the interval width to 1px or less.
  • The more segments the behavior has, the longer the resulting function becomes.
  • Due to its possible complexity, the function from equation (3) must be used inside a CSS calc() expression.
Abrupt change of values of some property
Fig. 3. Abrupt change of values of some property. (Large preview)

Worked Example: Responsive Font Size

Consider a typical responsive design scenario. Menu item font size is 18px at a viewport of 1920px, decreasing to 12px at 768px. Between 320px and 767.98px, the font size is fixed at 20px. This behavior has three linear segments and can be encoded using equation (3).

The example of a font size (a) and a margin (b) values dependence on viewport width
Fig.4. The example of a font size (a) and a margin (b) values dependence on viewport width. (Large preview)

1. Calculate line parameters. Each segment fi(x) is defined by its endpoints. For the first line between (768, 12) and (1920, 18):

function
(Large preview)

Expressed in the slope-intercept form:

function
(Large preview)

Repeating for the second and third line segments gives:

function
(Large preview)
function
(Large preview)
function
(Large preview)

2. Construct segment functions gi using equation (2):

functions
(Large preview)

3. Determine the constant term in equation (3):

function
(Large preview)

4. Assemble the final expression from equation (3):

function
(Large preview)
function
(Large preview)

5. Write the CSS, wrapping the result in calc():

.block{
 font-size: calc(clamp(0.75rem, 19200.75rem – 40000vw, 1.25rem) + max(0.75rem, 0.5rem + 0.5208333vw) – 0.75rem); 
}

This is fully equivalent to the traditional media-query-based approach:

.block{
 font-size: calc(0.5rem + 0.5208333333vw);
}
@media (max-width: 767px) {
 .block {
  font-size: 1.25rem;
 }
}

Applying the same procedure to model responsive right margin behavior produces:

function
(Large preview)

A live demo is available:

See the Pen [Header [forked]](https://codepen.io/smashingmag/pen/qBxdpqx) by Ruslan.

See the Pen Header [forked] by Ruslan.

Practical Considerations

Equation (3) can describe any arbitrary property behavior as a function of viewport width without a single media query. However, its use is currently limited to properties whose values are lengths, because CSS does not yet support mathematical operations on dimensioned values (e.g., (2px*6px)/4px is not possible).

For simpler cases, more direct approaches are preferable:

  1. A continuous monotonic change defined by two points uses a simple calc(f(x)). This covers typical fluid typography.
  2. With three points where the slope decreases (k1 > k2), use min(f1, f2).
  3. With three points where the slope increases (k1 < k2), use max(f1, f2).
The elemental behaviors of the values of some CSS property
Fig.5. The elemental behaviors of the values of some CSS property. (Large preview)

See the Pen [Quick CSS example [forked]](https://codepen.io/smashingmag/pen/qBxdpKy) by Ruslan.

See the Pen Quick CSS example [forked] by Ruslan.

Prebuilt implementations are available, such as CSS functions on GitHub that handle both the full equation and the primitive edge cases.

A working flexbox example demonstrates the technique. Four flex items initially take 25% width each, then transition to 50% and finally 100% as the viewport narrows. However, this example breaks when vertical scrollbars appear, since vw units do not account for the scrollbar width. Replacing vw with % would solve that problem, but CSS cannot apply equation (3) to percentage values yet, so the approach remains limited to length-based properties.

Trade-Offs Worth Weighing

The core purpose of this exercise is to demonstrate that fluid sizing without a pile of media queries is technically possible. Whether you adopt it in production is a separate call. The most obvious drawback is readability: the resulting CSS is denser and harder to scan at a glance. What you gain is a cleaner separation of concerns. Media queries stay focused on structural and adaptive layout changes, uncluttered by repetitive lines that adjust font sizes, paddings, or margins for each breakpoint.

A practical next step would be a small utility that lets developers define value changes and generates these intricate queries automatically. The maintenance burden, however, could quickly become significant unless wrapped in a Sass mixin. Either way, the experiment shows that the boundaries of CSS custom properties and clamp() are broader than they first appear.

Credits and Further Reading

Thanks go to Evgeniy Andrikanich and his YouTube channel “FreelancerStyle” for producing free, high-quality educational content on HTML, CSS, and JS.

For deeper context, the approach builds on prior work around one-line responsive properties and modern fluid typography. The original Russian article on Habr explores the “responsible property” technique, while Adrian Bece’s piece on Smashing Magazine covers clamp()-based typography in detail. Both are useful references if you want to push the idea further.