demo · v147 · CSS · computed values
Animation Pipeline Demo
Side-by-side CSS animations plus a live CSSOM probe. The left arena animates width alone; the right arena carries --edge-width into border-width and outline-width while style values flip through non-painting states. The probe below shows which values come from computedStyleMap() and which come from getComputedStyle().
border-width, outline-width, and column-rule-width from their corresponding *-style values. This page keeps the animation controls, then checks the exact CSSOM surfaces that decide whether a hidden style erased the authored width or only the used paint width.
computed-value contract probe
| surface | style read | computedStyleMap() |
getComputedStyle() |
|---|---|---|---|
border-width |
border-top-style: none |
get('border-top-width'): checking... |
borderTopWidth: checking... |
outline-width |
outline-style: none |
get('outline-width'): checking... |
outlineWidth: checking... |
column-rule-width |
column-rule-style: none |
get('column-rule-width'): checking... |
columnRuleWidth: checking... |
The hidden-style branch checks whether the authored width is retained while a non-painting style keeps the border's used paint width at zero.
what's measured
Each arena tracks how many requestAnimationFrame callbacks fire per second as a local stress signal while the controls change duration and element count. The right arena uses a registered --edge-width chain for border-width and outline-width. The normative evidence is the contract probe above: it reads the exact border-width, outline-width, and column-rule-width surfaces instead of inferring support from a generic animation result.
On fast hardware the FPS difference may be small at low box counts. Increase the slider to 50 boxes to make the style-flip branch easier to compare.
the CSS
@property --edge-width {
syntax: "<length>";
inherits: false;
initial-value: 4px;
}
/* Decoupled track: width animates independently. */
@keyframes widen-decoupled {
0% { width: 20px; }
50% { width: 200px; }
100% { width: 20px; }
}
/* Style-flip track: custom-property width survives non-painting styles. */
@keyframes widen-coupled {
0% { width: 20px; --edge-width: 4px; border-style: none; }
50% { width: 200px; --edge-width: 8px; border-style: solid; }
100% { width: 20px; --edge-width: 4px; border-style: none; }
}
.box-coupled {
border-width: var(--edge-width);
outline-width: var(--edge-width);
}
const computed = box.computedStyleMap().get('border-top-width');
const usedPaint = getComputedStyle(box).borderTopWidth;
// usedPaint may be 0px under border-style:none even when computed is 4px.
see also
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗