| name | css-shared-first |
| description | Apply the Shared First CSS methodology when writing responsive styles. Use this skill whenever writing or reviewing CSS that involves media queries, responsive layouts, viewport-specific overrides, or breakpoint-driven design. Trigger when the user asks to write responsive CSS, refactor mobile-first CSS, or when any component or layout has viewport-specific styles. This skill replaces mobile-first pattern guidance — always prefer Shared First unless the user explicitly requests mobile-first.
|
CSS Shared First
Core Philosophy
Shared First is a CSS authoring methodology that eliminates cascade bleed
between breakpoints. The rule is simple:
Only write CSS outside of media queries if it applies to all viewport
sizes. Everything else belongs inside a bounded media query that targets
exactly the viewport range it is meant for.
This is in contrast to the traditional Mobile First approach, which writes
base styles for small viewports and progressively overrides them for larger
ones — a pattern that is error-prone and produces noisy DevTools output full of
struck-through declarations.
The Two Downsides of Mobile First
-
Error prone — styles bleed upward. Any CSS written outside a media query
or inside an open-ended min-width query will affect all larger viewports
too. Forgetting to undo a change for larger sizes introduces regressions.
-
Hard to inspect. DevTools shows a cascade of overridden (struck-through)
properties, making it difficult to understand what is actually in effect at
any given viewport.
The Shared First Rules
Rule 1 — Shared styles go outside all media queries
Only styles that are literally identical across every breakpoint live at the
top level. If a property value changes at any breakpoint, it does not belong
outside a media query.
.card-grid {
display: flex;
flex-wrap: wrap;
}
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
Rule 2 — Use bounded media queries for viewport-specific styles
Every media query that is not an open-ended upper-bound query must target
exactly one range. Use the CSS Media Queries Level 4 range syntax with
comparison operators (<, <=, >, >=). It reads naturally, is more
concise than min-width/max-width, and — crucially — < is exclusive so
boundaries never overlap. No more −0.03125em offset hacks.
@media (width < 40em) { … }
@media (40em <= width < 60em) { … }
@media (width >= 60em) { … }
Range syntax is Baseline 2023 — supported in all modern browsers (Chrome 113+,
Firefox 63+, Safari 16.4+).
Rule 3 — Repeat, don't inherit
Define each viewport-specific value explicitly in its own media query rather
than relying on cascade inheritance from a smaller breakpoint. Redundancy here
is intentional and is a maintenance feature, not a bug.
@media (width < 40em) {
.card-grid {
gap: 1rem;
}
}
@media (40em <= width < 60em) {
.card-grid {
gap: 2rem;
}
}
@media (width >= 60em) {
.card-grid {
gap: 3rem;
}
}
Full Layout Example
HTML:
<body>
<main></main>
<aside></aside>
</body>
Mobile First (avoid)
body {
display: flex;
flex-direction: column;
gap: 1rem;
}
@media (width >= 40em) {
body {
gap: 2rem;
}
}
@media (width >= 60em) {
body {
flex-direction: row;
gap: 3rem;
}
main {
flex: 3;
}
aside {
flex: 1;
}
}
Shared First (prefer)
body {
display: flex;
}
@media (width < 60em) {
body {
flex-direction: column;
}
}
@media (width < 40em) {
body {
gap: 1rem;
}
}
@media (40em <= width < 60em) {
body {
gap: 2rem;
}
}
@media (width >= 60em) {
body {
gap: 3rem;
}
main {
flex: 3;
}
aside {
flex: 1;
}
}
No overrides. No struck-through properties. Each breakpoint is self-contained
and safe to modify independently.
Refactoring Mobile First to Shared First
When asked to refactor existing CSS:
-
Audit shared properties. Identify which properties have the same value
at every breakpoint. These are the only candidates for top-level declarations.
-
Map each breakpoint's unique values. For every property that changes,
collect the value needed at each size. Each value belongs in its own bounded
media query.
-
Replace open-ended queries. Convert @media (width >= X) queries
(other than the largest breakpoint) into bounded range queries:
@media (X <= width < Y).
-
Remove cascade-dependent overrides. If a mobile-first file only changed
a property to undo a previous value, eliminate the original declaration
instead of keeping the override.
Applies to Container Queries Too
The same principle applies to @container queries. Only write container-level
styles outside a @container rule if they truly apply at every container size.
Use bounded size conditions otherwise:
.card {
display: grid;
}
@container (width < 30em) {
.card {
grid-template-columns: 1fr;
}
}
@container (width >= 30em) {
.card {
grid-template-columns: 2fr 1fr;
}
}
Quick Reference
| Scenario | Where it goes |
|---|
| Same value at all sizes | Outside all queries (shared) |
| Value unique to small only | @media (width < <sm-upper>) |
| Value unique to medium only | @media (<md-lower> <= width < <md-upper>) |
| Value for large and up | @media (width >= <lg-lower>) |
| Shared across small + medium | @media (width < <md-upper>) |
| Shared across medium + large | @media (width >= <md-lower>) |
Further Reading