Skip to content

css: getComputedStyle drops CSS custom properties from every source (stylesheet, inline, inherited) #3199

Description

@ManuzimFerreira

Summary

getComputedStyle().getPropertyValue('--x') returns the empty string for CSS custom properties declared in any source: stylesheet rules, inline style= declarations, and inherited values. After #2836, known CSS properties declared inline resolve correctly, but custom properties are excluded even on that path.

Reproduction

<!DOCTYPE html>
<html>
<head>
  <style>
    :root { --brand-color: #336699; }
    .card { --card-pad: 16px; }
  </style>
</head>
<body>
  <div class="card" id="card" style="--inline-var: 4px"></div>
  <script>
    const root = getComputedStyle(document.documentElement);
    const card = getComputedStyle(document.getElementById('card'));
    console.log('ROOT_VAR=[' + root.getPropertyValue('--brand-color') + ']');
    console.log('CLASS_VAR=[' + card.getPropertyValue('--card-pad') + ']');
    console.log('INLINE_VAR=[' + card.getPropertyValue('--inline-var') + ']');
    console.log('INHERITED_VAR=[' + card.getPropertyValue('--brand-color') + ']');
  </script>
</body>
</html>

Observed (nightly 1.0.0-nightly.8643+fb7123cf, macOS aarch64, lightpanda fetch <url> --log_level debug):

ROOT_VAR=[]
CLASS_VAR=[]
INLINE_VAR=[]
INHERITED_VAR=[]

Chrome returns #336699, 16px, 4px, #336699.

Why it matters

Design-system-driven SPAs commonly build their theme at boot by reading design tokens through getComputedStyle (MUI themes built from CSS tokens, Tailwind v4 CSS-first tokens, most in-house design systems). When every --var resolves to "", the theme factory throws, React unmounts the tree, and the page renders empty - even though the JS itself runs fine in Lightpanda. Resolving custom properties would unblock this whole class of apps.

Proposed scope (following the direction in #2733)

#2733 deliberately left stylesheet-cascade resolution out of #2836, with a suggestion of making computation opt-in. Custom properties are a much smaller, self-contained slice of that problem:

  • Per css-variables-1 §3.1 the computed value of a custom property is the declared token stream - no unit resolution, no layout, none of the resolved-value complexity that kept the full cascade out of scope.
  • Resolution order: element inline style, then matching author rules by specificity/order, then inherit up the parent chain to :root.
  • Could sit behind an opt-in consistent with --enable-external-stylesheets if the default-path cost is a concern.
  • var() substitution inside returned longhand values could be a separate follow-up.

Happy to work on a PR for this if the direction sounds right - from an initial read of StyleManager/CSSStyleProperties, the rule parsing and selector matching this needs are already in place.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions