Cascade Layers
Rely on layers to eliminate style overrides and conflicts.
Overview
Master CSS analyzes the syntax and inserts it into the appropriate layer, allowing you to focus on the UI without worrying about style precedence.
Layer | Description | Entity |
---|---|---|
Base | Where the styles with @base are generated. | @layer base { … } |
Theme | Where the used variables are generated. | @layer theme { … } |
Preset | Where the styles with @preset are generated. | @layer preset { … } |
Styles | Where the used styles are generated. | @layer styles { … } |
General | Where the general styles are generated. | @layer general { … } |
Here is an example that covers all layers:
export default { variables: { primary: { '@light': '#000000', '@dark': '#ffffff' } }, styles: { btn: 'inline-flex bg:primary' }}
<body class="list-style:none_ul@base"> <button class="btn flex">Submit</button> <ul class="@fade|1s">…</ul> <article class="text:16_p@preset"> <p>…</p> </article></body>
Generated CSS:
@layer base, theme, preset, styles, general; @layer base { .list-style\:none_ul\@base ul { list-style: none }} @layer theme { .light, :root { --primary: 0 0 0 } .dark { --primary: 255 255 255 }} @layer preset { .text\:16_p\@preset p { font-size: 1rem; line-height: calc(1rem + 0.875em) }} @layer styles { .btn { display: inline-flex; background-color: rgb(var(--primary)) }} @layer general { .flex { display: flex } .\@fade\|1s { animation: fade 1s }} @keyframes fade { 0% { opacity: 0 } to { opacity: 1 }}
@layer base, theme, preset, styles, general;
declares the order of the style layers. The cascade priority follows this order, where layers declared later override earlier ones if there are conflicting styles.@layer base { … }
generates rules based on the syntax with@base
(list-style:none_ul@base
).@layer theme { … }
generates rules based on used variable values (primary
) andconfig.variables
.@layer preset { … }
generates rules based on the syntax with@preset
(text:16_p@preset
).@layer styles { … }
generates rules based on used abstract styles (btn
) andconfig.styles
.@layer general { … }
generates rules based on used general styles (flex
,@fade|1s
).- All keyframes rules are generated into the top-level.
Adding base styles
To normalize browser and preset global styles for more concise-style programming, add CSS rules in the base layer.
Add a CSS rule for base styles in your global CSS file
@layer base { ul { list-style: none; }}
Or you can add base styles with @base
in the HTML:
<body class="list-style:none_ul@base">…</body>
Generated CSS:
@layer base, theme, preset, styles, general; @layer base { .list-style\:none_ul\@base ul { list-style: none }}
In most cases, the official package, @master/normal.css
, can help you normalize browser styles.
Adding preset styles
To preset fonts, foreground colors, etc. based on your brand, use @preset
to define these styles in elements.
Use selectors and @preset
to preset styles for elements and states.
<body class="font:mono_:is(code,pre)@preset">…</body>
Generated CSS:
@layer base, theme, preset, styles, general; @layer preset { .font\:mono_\:is\(code\,pre\)\@preset :is(code, pre) { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace }}
Without @preset
, you would have to always add !important
whenever you customize the same CSS property for the selected element.
Don't add brand-related preset styles to the base layer.
<body class="font:mono_:is(code,pre)@base">…</body>
The preset layer styles should be built on top of the base layer.
Overriding component styles
You can override the component styles by adding general syntax, without having to prioritize rules.
For example, add flex
to override the display declaration inline-flex
of the button.
<button class="btn flex">Submit</button>
Generated CSS:
@layer base, theme, preset, styles, general; @layer styles { .btn { display: inline-flex; … }} @layer general { .flex { display: flex; }}
Overriding preset styles
You can select descendants with @preset
to preset styles, preventing component and general styles from being overwritten.
For example, set the default paragraph text size to 16
and change the text size of a specific paragraph to 24
.
<article class="text:16_p@preset"> <p class="text:24">24</p> <p>16</p></article>
Generated CSS:
@layer base, theme, preset, styles, general; @layer preset { .text\:16_p\@preset p { font-size: 1rem; line-height: calc(1rem + 0.875em) }} @layer general { .text\:24 { font-size: 1.5rem; line-height: calc(1.5rem + 0.875em) }}
This way, you can set preset styles for multiple targets at once while still being able to modify specific elements' styles as needed.
Summary
By leveraging CSS cascade layers, you can structure your styles for better maintainability and prevent unwanted overrides.
If styles conflict, the order of priority is: General > Styles > Theme > Preset > Base.
Responsibilities
- Use
@layer base {}
or@base
for global resets and normalization. - Use
@layer preset {}
or@preset
for brand-specific defaults. - Other layers are automatically generated based on your syntax and configuration.
Principles
- Create base styles via CSS files and packages instead of defining a lot of
@base
syntax. - Create preset styles based on base styles.
- Create component styles based on base and preset styles.