Repository navigation
Block styles registered in theme.json generate unnecessary repetitive CSS #81583
Copy link
Copy link
Open
Copy link
Labels
CSS StylingRelated to editor and front end styles, CSS-specific issues.Related to editor and front end styles, CSS-specific issues.Global StylesAnything related to the broader Global Styles efforts, including Styles Engine and theme.jsonAnything related to the broader Global Styles efforts, including Styles Engine and theme.json[Feature] Block Style VariationsIssues or PRs that are related to the style variations for blocksIssues or PRs that are related to the style variations for blocks[Feature] Theme Style VariationsRelated to style variations provided by block themesRelated to style variations provided by block themes[Status] In ProgressTracking issues with work in progressTracking issues with work in progress[Type] BugAn existing feature does not function as intendedAn existing feature does not function as intended
Description
Description
Selecting block styles adds a class with a suffix like --1, and the exact same CSS is then injected along with it. This is most noticeable with the button outline style.
A single copy of the styles should be output instead of multiple copies.
Step-by-step reproduction instructions
On a block with block styles registered, add multiple copies of the block with that style selected, like so:
<!-- wp:buttons -->
<div class="wp-block-buttons"><!-- wp:button {"className":"is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button">Button 1</a></div>
<!-- /wp:button -->
<!-- wp:button {"className":"is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button">Button 2</a></div>
<!-- /wp:button -->
<!-- wp:button {"className":"is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button">Button 3</a></div>
<!-- /wp:button --></div>
<!-- /wp:buttons -->On the rendered page you will find the following in a style tag:
:root :where(.wp-block-button.is-style-outline--2 .wp-block-button__link) {
background: transparent none;
border-color: currentColor;
border-width: 2px;
border-style: solid;
color: currentColor;
padding-top: 0.667em;
padding-right: 1.33em;
padding-bottom: 0.667em;
padding-left: 1.33em;
}
:root :where(.wp-block-button.is-style-outline--3 .wp-block-button__link) {
background: transparent none;
border-color: currentColor;
border-width: 2px;
border-style: solid;
color: currentColor;
padding-top: 0.667em;
padding-right: 1.33em;
padding-bottom: 0.667em;
padding-left: 1.33em;
}
:root :where(.wp-block-button.is-style-outline--4 .wp-block-button__link) {
background: transparent none;
border-color: currentColor;
border-width: 2px;
border-style: solid;
color: currentColor;
padding-top: 0.667em;
padding-right: 1.33em;
padding-bottom: 0.667em;
padding-left: 1.33em;
}Environment info
- Wordpress 7.0.4, tested with both the Twenty Twenty (hybrid) and Twenty Twenty-Five (block) themes
Please confirm that you have searched existing issues in the repo.
- Yes
Please confirm that you have tested with all plugins deactivated except Gutenberg.
- Yes
Please confirm which theme type you used for testing.
- Block
- Classic
- Hybrid (e.g. classic with theme.json)
- Not sure
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
CSS StylingRelated to editor and front end styles, CSS-specific issues.Related to editor and front end styles, CSS-specific issues.Global StylesAnything related to the broader Global Styles efforts, including Styles Engine and theme.jsonAnything related to the broader Global Styles efforts, including Styles Engine and theme.json[Feature] Block Style VariationsIssues or PRs that are related to the style variations for blocksIssues or PRs that are related to the style variations for blocks[Feature] Theme Style VariationsRelated to style variations provided by block themesRelated to style variations provided by block themes[Status] In ProgressTracking issues with work in progressTracking issues with work in progress[Type] BugAn existing feature does not function as intendedAn existing feature does not function as intended
Activity
sanketio commentedon Aug 14, 2026
I can reproduce this. Some notes on the cause, and a warning about the obvious fix.
Tested on Gutenberg trunk
dbe1c1ccab1(23.8.0-rc.1), WordPress 7.0.4, Twenty Twenty-Five 1.5, using the exact markup from the report.Reproduction
block-style-variation-stylesinline CSSGrowth is linear and unbounded — each instance adds a full copy. Normalising the instance number (
--2,--3,--4→--N) collapses all of it to the same two rules.Worth noting there is no rendering difference: computed border colour, width, background and padding are identical no matter how many copies are emitted. This is purely wasted payload.
It also reproduces with the Gutenberg plugin deactivated on WordPress 7.0.4, so it affects core as well as the plugin.
Cause
gutenberg_render_block_style_variation_support_styles()inlib/block-supports/block-style-variations.php(andwp_render_block_style_variation_support_styles()in core) mints a fresh instance for every block onrender_block_data:The variation data feeding the stylesheet is read from the merged theme.json, and its
refvalues are resolved against that same tree. Nothing block-specific is involved, so for a given block type and variation the generated CSS is identical every time apart from the scope class.Why caching by variation slug is not safe
This looks like a one-line cache, so it seems worth writing up why it isn't. I tried it, and it silently breaks the cascade.
Every variation rule is wrapped in
:where():so every variation rule has the same specificity and source order alone decides which one wins. The per-instance class is what places a nested variation's styles after its ancestor's.
Test case — two group variations that style paragraphs differently,
demo-ared anddemo-bblue:demo-a--2 -> demo-b--3 -> demo-a--4demo-a--2 -> demo-b--3With the slug cache the nested
demo-areuses the class emitted beforedemo-b, sodemo-bwins and the paragraph changes colour.One thing that makes this easy to miss: Twenty Twenty-Five's own section styles set descendant colours with
currentColor, so nestingsection-1insidesection-2produces byte-identical descendant rules and shows no visible change even when the ordering is broken. Verifying against the bundled section styles alone would suggest the slug cache is fine.Suggested approach
Reuse the previous instance only when the immediately preceding variation instance is the same one. Nothing else was emitted in between, so re-emitting would be a no-op in cascade terms and the class can safely be shared. Anything interleaved forces a fresh instance, so today's ordering is preserved exactly.
demo-a/demo-bTrade-off worth weighing: this collapses runs of the same variation, which covers the reported case and the common ones (repeated blocks in a Query Loop, sibling buttons), but an alternating
A B A Bsequence still emits a copy per instance. Fully deduplicating would mean collecting variations during render and emitting them ordered by nesting depth instead of document order — a considerably larger change to how this filter works, and it would need care around blocks rendered outside the main content. Happy to go that route instead if that is preferred.Heads-up that #80718 touches the same function, so there may be a small conflict depending on merge order.
I'll open a PR with this shortly. It includes PHPUnit coverage — one test for the reuse, and one guarding that an interrupting variation still gets a fresh instance; the first fails on trunk without the change.