Expose ordered engine support CSS as its own asset - #877
Merged
Conversation
Split generated support rules into before-author and after-author assets, preserve placement through compiler plans, neutralize CSS-owned constrained layouts, and make rich-text markers self-sufficient.
borkweb
marked this pull request as draft
August 14, 2026 20:25
Remove the aggressive css-owned-layout neutralizer and restore marker-only background and color guards so engine defaults no longer outrank authored declarations.
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.
Why
HtmlTransformer::materializeAuthorStylesheet()concatenated two different things into onegenerated asset (
source: 'author-css'): the engine support CSS the transformer generates soits own output works, and the rewritten author stylesheet. A consumer that writes its own
author CSS cannot take the second, and had no reliable way to extract the first.
The real consumer —
automattic/site-build— was reduced to grepping the asset for/\.(be-inline-geometry-[a-z0-9-]+)\{[^{}]*\}/and discarding everything else. Measured across sixgenerated sites, every engine marker class appeared in the block markup with zero matching CSS
in the theme:
<mark>richtext carriers rendered with the browser default yellow highlight on headlines andbrand text — 15–42 unstyled marks per site, an accessibility regression.
<p>wrappers kept UAmargin:1em 0, so header/nav lockups sat misaligned.blocks-engine-control-*button rules were dropped — 10 occurrences in one site's markup, 22 inanother, 0 matching rules in either theme. Transformed buttons rendered unstyled.
A shape-based regex in the consumer was considered and rejected: the generated rules already use four
distinct selector shapes (
:where(.blocks-engine-*),:where(mark)[style*=…],.blocks-engine-control-X.blocks-engine-control-X>.wp-block-button__link,.wp-block-navigation…),so any regex under-carries. The boundary is knowledge only the transformer has.
What changed
1. The generated stylesheet is split by ownership.
author-cssnow holds only the rewrittenauthor stylesheet plus its own leading at-rule preamble. Engine-generated rules move to
source: 'engine-support'assets.2. Cascade order is preserved and expressible. Some support rules deliberately preceded the
author CSS (carrier rules keeping inline precedence) and others deliberately followed it
(list-navigation
display:flex!important, mobile overlay, button rules). A single support assetwould have lost that, so assets carry
stylesheet_placement:before-author|author|after-author. A consumer that never takes the author CSS at all still knows which side each rulebelongs on.
ArtifactCompilerorders thembeforeAuthor → manifest → other → afterAuthor.3. New
blocks-engine-css-owned-layoutneutralizer. Rules already existed forcss-owned-flow,css-owned-gridandcss-owned-layout-item, but nothing forcss-owned-layout.In a real WordPress theme a
layout:constrainedblock gets core CSS applyingmax-width: <contentSize>; margin-inline: autoto its non-aligned children — which collapses aCSS-owned flex container toward the centre. Observed downstream: a primary nav rendering ~860px wide
and centred inside a header the author CSS sized at 1280px. The static-site output never sees core
layout CSS, so the gap was invisible there.
4. The richtext-marker
<mark>is now self-sufficient. It carries inlinebackground-color:transparent;color:inherit, matching what the styled-inline path already did — thedivergence between the two paths was itself the bug. The
:where()stylesheet reset is retained,not replaced: zero specificity means it never fights the inline value, and it still covers consumers
whose sanitizers strip inline styles.
Verification
composer testtests/unit/engine-support-css-asset.phpThe 11 modified parity fixtures are legitimate expected-output changes: marks gain inline
background-color:transparent, and one asset count goes 1 → 2 where the new css-owned-layoutneutralizer applies.
VERSION → 0.4.17; CHANGELOG names the new asset
source, the placement enum, and the neutralizer.