fix(styles): inline establishing cascade-layer order for Vuetify 4 (#381)#382
Open
AndreyYolkin wants to merge 1 commit into
Open
fix(styles): inline establishing cascade-layer order for Vuetify 4 (#381)#382AndreyYolkin wants to merge 1 commit into
AndreyYolkin wants to merge 1 commit into
Conversation
) In styles treeshaking modes, Vuetify 4 component styles are injected on demand, each carrying its own `@layer vuetify-components { … }` block. With no establishing statement parsed first, layer priority is decided by injection order (non-deterministic in dev, chunk order in prod), so `vuetify-core.reset` can outrank component rules — e.g. a real `<button>` `<v-btn size="small">` renders at the inherited font size, not its token. Inline the establishing `@layer` order into the SSR'd <head> (tagPriority -100), so it is parsed before any runtime-injected or critical-inlined component style. Vuetify 4 only (v3 layers are opt-in and differently named); skipped for `styles: 'none'`. Add a `cascadeLayers` option to customise the order (e.g. to interleave a custom layer between Vuetify's) or disable injection with `false`. Closes #381
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.
Summary
Fixes #381 — on Vuetify 4,
<v-btn size="small">(and other size/density tokens) intermittently render at the wrong size because the CSS cascade-layer order is non-deterministic.Root cause
In styles treeshaking modes, Vuetify 4 component styles are injected on demand by
@vuetify/unplugin-styles, each carrying its own@layer vuetify-components { … }block. Per CSS Cascade 5, layer priority is fixed by the order layer names are first declared. With no establishing statement guaranteed to be parsed first, first-declaration = injection order, which is:nuxt dev(Vite injects each style module at runtime), andWhen
vuetify-componentsis declared beforevuetify-core,vuetify-core.reset(button { font: inherit }) outranks.v-btn--size-*→ the button renders at the inherited body size.Vuetify ships the order in
generic/_layers.scss, but it's just one more racer — andnuxt.options.cssordering can't fix it because the racing component styles are injected outside the css graph entirely (the reporter confirmed acss: ['~/layers.css']file still raced).The fix
Inline the establishing
@layerstatement into the SSR'd<head>(tagPriority: -100) so it's parsed before any runtime-injected or critical-inlined component style. One mechanism covers dev, prod, SSR and SPA.Scope / guards
vuetifylayer (no top-level race).styles: 'none'.New option:
cascadeLayersA flat
@layerstatement freezes the named layers contiguously, so a later-declared layer can only append. To keep custom interleaving possible, the injected order is configurable:VuetifyCascadeLayeroffers the known Vuetify layer names as autocomplete while still allowing arbitrary custom names.Upgrade note for existing workarounds
css:/SCSS file should move tocascadeLayers(or setcascadeLayers: false), otherwise the default statement parsed first would push the custom layer to the end. Documented in the styling guide.Tests
test/cascade-layers-head.test.ts— 13 pure-helper cases (default / custom array / empty /false/'none'/ v3 / core-before-components).test/sass.test.ts— v4configFilefixture: the SSR head contains the statement.test/basic-vuetify3.test.ts— v3 fixture: the SSR head does not contain it.Full suite 72 passing; lint clean on changed source;
prepackbuild green with the type shipped intodist/module.d.mts.Closes #381