Skip to content

[Feature] Compile-time CSS source generation with Bootstrap support#34357

Draft
StephaneDelcroix wants to merge 1 commit into
net11.0from
CSSSG-64ca
Draft

[Feature] Compile-time CSS source generation with Bootstrap support#34357
StephaneDelcroix wants to merge 1 commit into
net11.0from
CSSSG-64ca

Conversation

@StephaneDelcroix

@StephaneDelcroix StephaneDelcroix commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description

Adds a compile-time CSS source generator that front-loads CSS processing at build time, and extends the CSS engine with features needed for Bootstrap theme support.

Compile-Time Source Generator

The existing source generator only emitted [XamlResourceId] attributes — all CSS parsing happened at runtime. This PR adds a full compile-time pipeline:

  • CSS tokenization & comment stripping — parsed at build time
  • CSS variable resolution (var()) — resolved within single-file scope at build time
  • Shorthand expansion (borderborder-width + border-color, font → 4 longhand properties)
  • !important stripping — stripped at build time, tracked in ImportantProperties[] metadata
  • calc()/rem/em/px/vw/vh resolution — evaluated to plain numbers at build time
  • @media query parsing — media blocks parsed at build time, conditions evaluated reactively at runtime
  • Color functions (rgba, rgb, hsl) — pre-converted to hex colors at build time
  • Gradient support (linear-gradient()) — parsed and stored as MAUI gradient representation
  • Pseudo-classes (:active, :hover, :focus, :disabled, :first-child, :last-child, :not()) — compiled into selector predicates
  • Attribute selectors ([attr=value]) — compiled at build time

Generated code uses [ModuleInitializer] to register pre-parsed stylesheet factories. StyleSheet.FromResource() checks the compiled registry first, falling back to runtime parsing for dynamic stylesheets.

New CSS Features (Bootstrap Support)

Feature Status
CSS variables (:root, var(), fallbacks, recursive)
!important with specificity boost
Pseudo-classes (:first-child, :last-child, :not(), :hover, :focus, :disabled, :active)
[attr=value] attribute selectors
calc(), rem, em, px, vw, vh unit resolution
inherit, unset, initial keywords
@import (URL storage)
@media queries (min/max-width/height, orientation, prefers-color-scheme)
@charset (gracefully skipped)
Shorthand expansion (border, font)
Color functions (rgba, rgb, hsl, hsla)
Gradient support (linear-gradient())
Viewport units (vw, vh) with configurable defaults
20+ new CSS property mappings (max-height/width, rotate, scale, z-index, font-weight, gap, stroke-*, etc.)

@media Query Support

@media blocks are parsed at compile time into CompiledCssMediaGroup structs. At runtime, MediaQueryEvaluator evaluates conditions against Window.Width/Height and Application.RequestedTheme. When Window.SizeChanged fires, media conditions are re-evaluated and stylesheets re-applied if any condition changed state.

Supported conditions: min-width, max-width, min-height, max-height, orientation (portrait/landscape), prefers-color-scheme (dark/light), compound and, media type keywords (screen, all), and rem/em/px/vw/vh units in conditions.

Color Functions & Gradients

Color functions (rgba, rgb, hsl, hsla) are pre-converted to hex color strings at compile time using full RGB color space. The var() function is supported inside color functions with runtime variable resolution. Gradients (linear-gradient()) are parsed at compile time with color function resolution and stored as MAUI LinearGradientBrush representations.

Viewport Units

Viewport units (vw, vh) are resolved at compile time using configurable viewport dimensions (defaults: iPhone Xs 375×812pt). At runtime, these can be updated via CssValueResolver.SetViewport() if the actual viewport differs from defaults.

What Stays Runtime

  • Selector matching (needs live element tree)
  • inherit/unset (needs parent element values)
  • Cross-file var() resolution (needs merged stylesheet scope)
  • @import URL resolution (needs file I/O)
  • Dynamic stylesheet creation via StyleSheet.FromString()

Implementation Details

Runtime Support

  • CssValueResolver: Resolves color functions, gradients, viewport units, and unit conversions at runtime
  • Selector.Active: New pseudo-class selector mapped to VisualStateManager "Pressed" state
  • PseudoClassStyleHandler: Extended with :active → "Pressed" mapping

Compile-Time Support (SourceGen)

  • CssParser: Extended with color function, gradient, and viewport unit parsing
  • Code generation: Pre-parsed rules, color conversions, gradient definitions emitted as C# classes
  • Zero-overhead parsing: All supported CSS features compiled away at build time

Tests

  • 130 stylesheet tests + 69 selector tests + 99 style application tests + 14 source gen tests = 312 total (all passing)
  • New tests cover: CSS variables, !important, calc/rem/em/vw/vh, selector pseudo-classes, attribute selectors, shorthand expansion, @import, inherit/unset, @media queries (evaluator + runtime parsing + activation), color functions, gradients, viewport units, compile-time verification (shorthand/!important/calc/colors/gradients in generated code)

@github-actions

github-actions Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34357

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34357"

@StephaneDelcroix StephaneDelcroix force-pushed the CSSSG-64ca branch 2 times, most recently from a82196a to 1f2b4e8 Compare March 6, 2026 12:32
Add a compile-time CSS source generator that front-loads CSS processing
at build time, and extend the CSS engine with features needed for
Bootstrap theme support.

Compile-time pipeline:
- CSS tokenization, variable resolution, shorthand expansion
- @media block parsing into CompiledCssMediaGroup structs
- Generated [ModuleInitializer] factories registered on StyleSheet

New CSS features:
- CSS variables (:root, var(), fallbacks, recursive resolution)
- :first-child, :last-child, :not() pseudo-classes
- [attr=value] attribute selectors
- calc(), rem, em, px unit resolution
- inherit, unset, initial keywords
- @import, @charset, @media queries
- :hover, :focus, :disabled pseudo-classes (map to VisualStateManager)
- border/font shorthand expansion
- 20+ new CSS property mappings

Pseudo-class support:
- Parse :hover, :focus, :disabled selectors
- Create VisualStateManager states (PointerOver, Focused, Disabled)
- Apply pseudo-class styles as VSM state setters instead of direct props
- Enables Bootstrap's extensive interactive state styles

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kubaflo

kubaflo commented May 24, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/refactor-copilot-yml

@MauiBot

MauiBot commented May 24, 2026

Copy link
Copy Markdown
Collaborator

⚠️ Merge Conflict Detected — This PR has merge conflicts with its target branch. Please rebase onto the target branch and resolve the conflicts.

@kubaflo

kubaflo commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

AI code review for net11.0 target

Verdict: Needs discussion (draft/WIP; non-approval automated review, no human approval implied)

Large feature PR (compile-time CSS source generation + Bootstrap-oriented CSS engine features) by the XAML/SourceGen area owner. Given the size (~35 files, full new SourceGen pipeline + runtime StyleSheets additions), this is a high-level pass, not an exhaustive line-by-line audit of the generator.

Observations:

  • Design is reasonable: build-time tokenization/var()/shorthand/calc/color resolution with a [ModuleInitializer]-registered compiled registry, and StyleSheet.FromResource() falling back to runtime parsing for dynamic stylesheets. @media evaluated reactively against Window size/theme.
  • (API-review flag) New public surface for generator plumbing. CompiledCssMediaGroup and CompiledCssRule are added as public types (structs with ctors/operators) across every platform's PublicAPI.Unshipped.txt. If these only need to be reachable from generated [ModuleInitializer] code in the same assembly, prefer internal (or internal + InternalsVisibleTo/EditorBrowsable(Never)); generated code emitted into the user assembly would justify public. Worth an explicit API-review decision before this ships, since public structs are hard to evolve.
  • Reactive @media re-application hooked to Window.SizeChanged: please verify unsubscription/lifetime so stylesheet re-application doesn't pin pages/windows or fire after teardown (couldn't fully trace in this pass).
  • Test coverage (SourceGenCssTests, StyleSheets unit tests) is present — good.

CI: required pipelines red (some Build/Run legs failing). Expected for a WIP draft; not assessed as merge-ready.

Confidence: medium and intentionally high-level — flagging the public-API question as the main pre-merge discussion item rather than asserting specific defects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants