Robust-skills modern-css

Proactively apply when creating design systems, component libraries, or any frontend application. Triggers on CSS Grid, Subgrid, Flexbox, Container Queries, :has(), @layer, @scope, CSS nesting, @property, @function, if(), oklch, color-mix, light-dark, relative color, @starting-style, scroll-driven animations, view transitions, anchor positioning, popover, customizable select, content-visibility, logical properties, text-wrap, interpolate-size, clamp, field-sizing, modern CSS, CSS architecture, responsive design, dark mode, theming, design tokens, cascade layers. Use when writing CSS for any web project, choosing layout approaches, building responsive components, implementing dark mode or theming, creating animations or transitions, styling form elements, or modernizing legacy stylesheets. Modern CSS features and best practices for building interfaces with pure native CSS.

install
source · Clone the upstream repo
git clone https://github.com/ccheney/robust-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ccheney/robust-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/modern-css" ~/.claude/skills/ccheney-robust-skills-modern-css && rm -rf "$T"
manifest: skills/modern-css/SKILL.md
source content

Modern CSS

Pure native CSS for building interfaces — no preprocessors, no frameworks.

When to Use (and When NOT to)

Use Freely (Baseline)Feature-Detect First
CSS Grid, Subgrid, Flexbox
@function
,
if()
(Chrome-only)
Container Queries (size + style)Customizable
<select>
(Chrome-only)
:has()
,
:is()
,
:where()
Scroll-state queries (Chrome-only)
CSS Nesting,
@layer
,
@scope
sibling-index()
,
sibling-count()
@property
(typed custom props)
::scroll-button()
,
::scroll-marker
oklch()
,
color-mix()
,
light-dark()
Typed
attr()
beyond
content
Relative color syntax
field-sizing: content
@starting-style
,
transition-behavior
interpolate-size
(Chrome-only)
Scroll-driven animationsGrid Lanes / masonry (experimental)
Anchor positioning, Popover API
random()
(Safari TP only)
text-wrap: balance
,
linear()
easing
@mixin
/
@apply
(no browser yet)
View Transitions, logical properties

CRITICAL: The Modern Cascade

Understanding how styles resolve is the single most important concept in CSS. The additions of

@layer
and
@scope
fundamentally changed the cascade algorithm.

Style Resolution Order (highest priority wins):
┌─────────────────────────────────────────────────┐
│ 1. Transitions (active transition wins)         │
│ 2. !important (user-agent > user > author)      │
│ 3. @layer order (later layer > earlier layer)   │
│ 4. Unlayered styles (beat ALL layers)           │
│ 5. Specificity (ID > class > element)           │
│ 6. @scope proximity (closer root wins)      NEW │
│ 7. Source order (later > earlier)               │
└─────────────────────────────────────────────────┘

Unlayered > Last layer > ... > First layer
           (utilities)        (reset)

Cascade layers (

@layer
) and scope proximity (
@scope
) are now more powerful than selector specificity. Define your layer order once (
@layer reset, base, components, utilities;
) and specificity wars disappear. Unlayered styles always beat layered styles — use this for overrides.

Quick Decision Trees

"How do I lay this out?"

Layout approach?
├─ 2D grid (rows + columns)         → CSS Grid
│  ├─ Children must align across    → Grid + Subgrid
│  └─ Waterfall / masonry           → grid-lanes (experimental)
├─ 1D row OR column                 → Flexbox
├─ Component adapts to container    → Container Query + Grid/Flex
├─ Viewport-based responsiveness    → @media range syntax
└─ Element sized to content         → fit-content / min-content / stretch

"How do I style this state?"

Style based on what?
├─ Child/descendant presence        → :has()
├─ Container size                   → @container (inline-size)
├─ Container custom property        → @container style()
├─ Scroll position (stuck/snapped)  → scroll-state() query
├─ Element's own custom property    → if(style(...))
├─ Browser feature support          → @supports
├─ User preference (motion/color)   → @media (prefers-*)
└─ Multiple selectors efficiently   → :is() / :where()

"How do I animate this?"

Animation type?
├─ Enter/appear on DOM              → @starting-style + transition
├─ Exit/disappear (display:none)    → transition-behavior: allow-discrete
├─ Animate to/from auto height      → interpolate-size: allow-keywords
├─ Scroll-linked (parallax/reveal)  → animation-timeline: scroll()/view()
├─ Page/view navigation             → View Transitions API
├─ Custom easing (bounce/spring)    → linear() function
└─ Always: respect user preference  → @media (prefers-reduced-motion)

What CSS Replaced JavaScript For

JavaScript PatternCSS Replacement
Scroll position listenersScroll-driven animations
IntersectionObserver for reveal
animation-timeline: view()
Sticky header shadow toggle
scroll-state(stuck: top)
Floating UI / Popper.jsAnchor positioning
Carousel prev/next/dots
::scroll-button()
,
::scroll-marker
Auto-expanding textarea
field-sizing: content
Staggered animation delays
sibling-index()
max-height: 9999px
hack
interpolate-size: allow-keywords
Parent element selection
:has()
Theme toggle logic
light-dark()
+
color-scheme
Tooltip/popover show/hidePopover API + invoker commands
Color manipulation functions
color-mix()
, relative color syntax

For non-Baseline features, always feature-detect with

@supports
or use progressive enhancement. Check MDN or Baseline for current browser support.

Anti-Patterns (CRITICAL)

Anti-PatternProblemFix
Overusing
!important
Specificity arms raceUse
@layer
for cascade control
Deep nesting (
.a .b .c .d
)
Fragile, DOM-coupledFlat selectors,
@scope
IDs for styling (
#header
)
Too specific to overrideClasses (
.header
)
@media
for component layout
Viewport-coupled, not reusableContainer queries
JS scroll listeners for effectsJanky, expensiveScroll-driven animations
JS for tooltip positioningFloating UI dependencyAnchor positioning
JS for carousel controlsFragile, a11y issues
::scroll-button
,
::scroll-marker
JS for auto-expanding textareaUnnecessary complexity
field-sizing: content
max-height: 9999px
for animation
Wrong duration, janky
interpolate-size: allow-keywords
margin-left
/
padding-right
Breaks in RTL/verticalLogical properties (
margin-inline-start
)
rgba()
with commas
Legacy syntax
rgb(r g b / a)
space-separated
appearance: none
on selects
Removes ALL functionality
appearance: base-select
Preprocessor-only variablesCan't change at runtimeCSS custom properties
Preprocessor-only nestingExtra build step dependencyNative CSS nesting
Preprocessor color functionsCan't respond to context
color-mix()
, relative colors
text-wrap: balance
on paragraphs
Performance-heavyOnly headings/short text
content-visibility
above fold
Delays LCP renderingOnly off-screen sections
Overusing
will-change
Wastes GPU memoryApply only to animating elements

Reference Documentation

FilePurpose
references/CASCADE.mdNesting,
@layer
,
@scope
, cascade control, and CSS architecture
references/LAYOUT.mdGrid, Subgrid, Flexbox, Container Queries, and intrinsic sizing
references/SELECTORS.md
:has()
,
:is()
,
:where()
, pseudo-elements, and state-based selection
references/COLOR.mdOKLCH,
color-mix()
, relative colors,
light-dark()
, and theming
references/TOKENS.md
@property
,
@function
,
if()
, math functions, and design tokens
references/ANIMATION.md
@starting-style
,
interpolate-size
,
linear()
, view transitions
references/SCROLL.mdScroll-driven animations, scroll-state queries, native carousels
references/COMPONENTS.mdCustomizable
<select>
, popover, anchor positioning,
field-sizing
references/PERFORMANCE.md
content-visibility
, typography, logical properties, accessibility
references/CHEATSHEET.mdQuick reference: browser support, legacy→modern patterns, units

Sources

Official Specifications

Browser Vendor Blogs

Reference