Add custom properties and var()#211
Open
jhaygood86 wants to merge 1 commit into
Open
Conversation
jhaygood86
marked this pull request as ready for review
July 22, 2026 23:16
Custom properties and var() references (CSS Variables 1) had no support: "--foo" lexed as a '-' delimiter plus "-foo", custom-property declarations were dropped, and any value containing var() was rejected against the property's own grammar. - Lexer: a second '-' also begins an ident, so "--foo" is one ident (both the top-level '-' dispatch and IdentStart). "-->" still closes an HTML-style comment. - CustomProperty, created for any "--*" name via PropertyFactory.IsCustomPropertyName; its value is kept verbatim (Converters.Any). "-" and "--" alone are not custom properties. - Property.TrySetValue routes a value containing var() through Converters.Any instead of the property grammar - the reference is only resolvable per-element at cascade time. - A shorthand whose value contains var() is kept whole rather than sliced into longhands (both StyleDeclaration.SetShorthand and the StylesheetComposer declaration path), since it can only be split after substitution. - ValueExtensions.ContainsFunction detects a function call anywhere, including nested (var() inside calc()).
jhaygood86
force-pushed
the
feature/custom-properties-and-var
branch
from
July 23, 2026 22:29
0fa3a4f to
abb5272
Compare
Contributor
Author
|
Rebased onto current The The "Dependency" section of the description above is therefore obsolete — there's nothing left to rebase around. The scope note still stands: this is the object model only, no |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Feature
Custom properties and
var()references (CSS Custom Properties for Cascading Variables 1):On
master:--foolexes as a-delimiter plus-foo, custom-property declarations are dropped, and any value containingvar()is rejected against the property's own grammar.Changes
-also begins an ident, so--foois one ident (fixed in both the top-level-dispatch andIdentStart).-->still closes an HTML-style comment.CustomProperty— created for any--*name viaPropertyFactory.IsCustomPropertyName, with its value kept verbatim (Converters.Any).-and--alone are reserved, not custom properties.var()on any property —Property.TrySetValueroutes a value containingvar()throughConverters.Anyrather than the property grammar, since the referenced value is only known per-element at cascade time (§3).var()in a shorthand — kept whole rather than sliced into longhands (bothStyleDeclaration.SetShorthandand theStylesheetComposerdeclaration path), because it can only be split after substitution (§3.2).margin: var(--gap) 5pxstays a singlemargindeclaration.ValueExtensions.ContainsFunction— detects a function call anywhere, including nested (var()insidecalc()).Scope: object model only, no substitution
This adds the object model for custom properties and
var()— parsing, storage, and serialization — so a stylesheet round-trips faithfully and the declarations are queryable. It does not include avar()substitution layer: a property that referencesvar()keeps its value verbatim (e.g.colorreportsvar(--c)), it is not resolved to the referenced custom property's computed value.Fully resolving a stylesheet — walking the cascade per element, substituting each
var()reference (honouring fallbacks and the guaranteed-invalid / cyclic-reference rules of CSS Variables 1 §3), then re-expanding any shorthand that contained one — is a separate cascade/computed-value layer that would have to be built on top of this. That layer is out of scope here; this PR is only the parser/object-model foundation it would consume.If a substitution layer would be useful upstream, I'm happy to contribute one as a follow-up: this object model was extracted from a downstream renderer that already implements var() substitution on top of exactly these types, so a version that builds on this framework already exists and could be adapted.
Tests
19 cases in
PropertyTests/CustomPropertyTests.cs: custom properties stored verbatim (including odd values), theCustomPropertytype,IsCustomPropertyName(rejecting-/--),var()accepted on longhands and insidecalc(), var()-bearing shorthands kept whole with longhands unpopulated, and the--foo-is-one-ident lexer regression.The full suite (1263 existing tests) stays green — the
--lexer change and var() routing disturb nothing — and all seven target frameworks build with no new warnings.