Cascade Layers
How Shift CSS uses @layer for predictable specificity
The Specificity Problem
Traditional CSS frameworks suffer from specificity wars:
/* Framework defines */
.btn { background: blue; }
/* You want to override */
.btn { background: purple; } /* Works... sometimes */
/* But then the framework has */
.btn.btn-primary { background: blue; } /* Higher specificity wins */
/* So you resort to */
.btn { background: purple !important; } /* The nuclear option */
The Cascade Layers Solution
CSS Cascade Layers (@layer) provide explicit control over which styles take precedence, regardless of specificity:
/* Framework in a layer */
@layer framework {
.btn { background: blue; }
.btn.btn-primary { background: blue; }
}
/* Your CSS (unlayered) ALWAYS wins */
.btn { background: purple; } /* Always applies! */
Shift CSS Layer Hierarchy
@layer shift.reset, shift.tokens, shift.core, shift.utils;
Order (lowest to highest priority):
shift.reset- Browser reset, fluid typographyshift.tokens- CSS custom propertiesshift.core- Components (buttons, cards, inputs)shift.utils- Utility classes
Your CSS (unlayered) automatically has the highest priority.
Practical Example
<style>
/* Shift CSS is in @layer shift.* */
/* Your styles override without !important */
.btn {
background: var(--color-accent-500);
border-radius: 9999px;
}
</style>
<button class="btn">Custom Styled</button>
Working With Layers
You can also create your own layers that sit between Shift CSS and your custom styles:
@layer shift.reset, shift.tokens, shift.core, shift.utils, app.components, app.utilities;
@layer app.components {
.my-button { /* Your component styles */ }
}
Integrating With Existing CSS
Need to use Shift CSS alongside existing styles or another CSS framework? Wrap the existing CSS in a lower-priority layer:
/* 1. Define the layer hierarchy first */
/* The last layer in this list is the strongest */
@layer legacy, shift.reset, shift.tokens, shift.core, shift.utils;
/* 2. Wrap the existing CSS */
/* This "demotes" it so it can be easily overridden */
@layer legacy {
@import url("existing-styles.css");
/* Any other existing styles go here */
}
/* 3. Shift CSS components now take priority */
@layer shift.core {
[s-btn="primary"] {
/* This will now win over any .btn styles in legacy */
background: var(--s-primary-500);
}
}
This approach lets you:
- Gradually migrate from existing CSS to Shift CSS
- Use both side-by-side during transition
- Override legacy styles without
!importanthacks - Maintain predictable specificity across your entire codebase