This article is published in English.
From 66% to 185px: How Browsers Resolve CSS Values Before Layout
Follow a CSS value through the declared, cascaded, specified, computed, used and actual stages, and see why relative units and the rem-conversion trick behave as they do.
Winning the cascade is not the end of a CSS declaration's journey. If width: 50% beats every competing rule, the browser still cannot hand 50% to its layout engine; it has to work out fifty percent of what, in the current context, and turn that into a concrete size. This guide follows a single value through each processing stage the specification defines, shows where relative units such as rem and percentages get resolved, and explains the popular px-to-rem conversion trick along with its accessibility caveat.
The value you write is not the value that gets used
Much of what you type in a stylesheet is a relationship rather than a measurement. A width can be a share of the parent:
width: 50%;
or, in another rule, a different share:
width: 66%;
A font size can be relative to the root element's font size:
font-size: 2rem;
and a height can be a fraction of the viewport:
height: 50vh;
None of these is written in pixels, yet layout ultimately needs real dimensions to decide where every box goes. To bridge that gap, each value is carried through a fixed series of stages:
Declared Value
↓
Cascaded Value
↓
Specified Value
↓
Computed Value
↓
Used Value
↓
Actual Value
The names look like jargon at first, but each stage answers one specific question. The sections below walk through them in order using a single running example.
Declared value: what you asked for
The declared value is simply the value as it appears in a declaration. Given:
width: 66%;
the declared value for width is 66%. It is a request, nothing more. An element can easily have several declared values for the same property coming from different rules, so the first job is to pick one.
Cascaded value: the declaration that survived
Imagine two rules that both set a paragraph's width. One uses a type selector:
p {
width: 100px;
}
and the other uses a class:
.amazing {
width: 66%;
}
If a paragraph carries the amazing class, both rules match it. The class selector is more specific than the bare element selector, so the cascade chooses:
width: 66%;
That surviving 66% is the cascaded value. This step matters because every later stage works only on the single winner; losing declarations are discarded rather than processed.
Specified value: making sure every property has one
The specified value is the result of guaranteeing that each property on each element has some value. The rule is short:
- if there is a cascaded value, it becomes the specified value;
- otherwise, for an inherited property, the specified value is the parent's computed value;
- otherwise, it is the property's initial value, the default from the specification.
In our example there is a cascaded value, so the specified value is still 66% and this stage appears to do nothing. It becomes important for properties no rule mentioned at all, which is exactly where inheritance comes in. That mechanism is covered in the final section.
Computed value: resolving what can be resolved without layout
The computed value is where the browser resolves everything it can work out without actually laying out the page. Relative lengths based on font sizes become absolute lengths, and keywords are turned into concrete values. Consider:
font-size: 2rem;
The unit here:
2rem
describes a relationship, "twice the root element's font size", rather than a fixed measurement. At the computed stage, the browser looks up the root font size and turns the value into pixels. If the root font size is 16px, the computed font size is 32px.
One reason this conversion happens at this stage is inheritance: the computed value is what children inherit, so they receive a concrete length instead of a relationship they would reinterpret in their own context. That is why nested em font sizes compound the way they do, and why percentage line heights sometimes produce cramped text in children with larger fonts.
Some values cannot be resolved yet. A percentage width depends on the size of the containing block, which is not known until layout, so 66% generally remains a percentage in the computed value and is only settled in the next stage.
Used value: bringing in layout information
The used value is the result once layout information is available. Return to:
width: 66%;
On its own, a percentage is incomplete until you know what it is a share of. For width, that reference is the width of the containing block. Suppose the parent section is:
280px
wide. The browser can now compute:
66% of 280px
which comes out to:
184.8px
That figure is the used value. This is the turning point in the process: the browser is no longer holding the percentage you wrote but a real dimension derived from the page's actual geometry. The same is true of values like auto widths, which are only meaningful once the surrounding layout is known. If you query an element in JavaScript with getComputedStyle, many layout-dependent properties such as width return this resolved pixel value rather than the percentage, which is a handy way to observe the stage in practice.
Actual value: fitting the device's constraints
The last stage accounts for the limits of the rendering environment. A device cannot necessarily draw a value with arbitrary precision, so a used value like:
184.8px
may end up being rendered as roughly:
185px
That adjusted figure is the actual value. In practice, modern browsers lay out with sub-pixel precision and apply rounding or snapping at different points depending on the property and the engine, so do not rely on a specific rounding rule. The important idea is simply that there can be a final adjustment between the calculated value and what reaches the screen.
Stepping back, the whole sequence boils down to one sentence: what you write in a stylesheet is not necessarily what the browser ends up using, and there are well-defined steps in between.
Why relative units become less mysterious
This model explains why relative units are so valuable and so often misunderstood. Units like these:
%
rem
em
vh
vw
let you describe sizes in terms of something else (the parent, the root font size, the element's own font size, the viewport) instead of hard-coding pixels. That is what makes layouts adapt to different screens and user settings.
Each of them, however, must be resolved against its reference before layout can use it, and they are resolved at different stages: font-relative units at the computed stage, percentages against the containing block at the used stage. With the pipeline in mind, you can replace the vague idea that "the browser figures it out" with a sharper question during debugging: what does this value depend on, and what is that reference right now? When a responsive layout misbehaves, the culprit is very often a reference that is different from what you assumed, such as a percentage resolving against an unexpected containing block, or an em compounding through several nested elements.
Converting px to rem with a 10px root
Understanding value processing also clarifies a common sizing workflow: converting pixel values from a design into rem. Suppose a design specifies:
padding: 30px;
and you would rather express it as:
padding: 3rem;
A popular approach is to set the root font size to a round number:
html {
font-size: 10px;
}
With that in place:
1rem = 10px
and conversions become mental arithmetic:
30px → 3rem
40px → 4rem
20px → 2rem
In general:
rem = pixels / 10
The benefit is not just tidier numbers. Because every rem resolves against the root font size at the computed stage, changing that one root value rescales every rem-based measurement on the page at once, which gives you a single global control over the sizing system.
There is an important caveat. Setting the root to a fixed 10px overrides the default font size a user may have chosen in their browser settings, which undermines one of the main accessibility reasons for using rem in the first place. A widely used alternative is html { font-size: 62.5%; }: with the default 16px browser setting, that still yields 10px, but it scales proportionally when a user raises their preferred size. If you adopt this pattern, also remember to set a readable font size on body (for example 1.6rem), since text would otherwise default to the reduced root size.
When nothing was declared at all
One question remains unanswered by the stages above. Take this markup:
<div class="parent">
<p>Hello World</p>
</div>
and a rule on the wrapper:
.parent {
color: red;
}
Nowhere is there a rule like:
p {
color: red;
}
Yet the paragraph's text is red. The paragraph has no cascaded color, so its specified value has to come from somewhere else. Because color is an inherited property, the browser uses the parent's computed colour. This is inheritance, and it plugs directly into the specified-value stage described earlier. For a detailed look at which properties inherit, why children receive computed rather than declared values, and how inherit and initial override the defaults, inheritance deserves a dedicated treatment of its own.
Key takeaways
- A CSS value passes through six stages: declared, cascaded, specified, computed, used and actual.
- The cascade reduces many declared values to a single cascaded value; only that winner is processed further.
- The specified value falls back to inheritance or the initial value when nothing was declared.
- Font-relative units such as
remandembecome absolute lengths at the computed stage; percentage widths wait for layout and are resolved at the used stage. - The actual value may be adjusted for device limits, so avoid depending on exact rounding behaviour.
- The 10px-root trick makes rem conversion easy, but
62.5%respects user font preferences better than a fixed10px.