skills/modern-css/SKILL.md
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.
npx skillsauth add ccheney/robust-skills modern-cssInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Pure native CSS for building interfaces — no preprocessors, no frameworks.
| 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 animations | Grid 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 | |
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.
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
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()
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)
| JavaScript Pattern | CSS Replacement |
|---|---|
| Scroll position listeners | Scroll-driven animations |
| IntersectionObserver for reveal | animation-timeline: view() |
| Sticky header shadow toggle | scroll-state(stuck: top) |
| Floating UI / Popper.js | Anchor 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/hide | Popover API + invoker commands |
| Color manipulation functions | color-mix(), relative color syntax |
For non-Baseline features, always feature-detect with
@supportsor use progressive enhancement. Check MDN or Baseline for current browser support.
| Anti-Pattern | Problem | Fix |
|---|---|---|
| Overusing !important | Specificity arms race | Use @layer for cascade control |
| Deep nesting (.a .b .c .d) | Fragile, DOM-coupled | Flat selectors, @scope |
| IDs for styling (#header) | Too specific to override | Classes (.header) |
| @media for component layout | Viewport-coupled, not reusable | Container queries |
| JS scroll listeners for effects | Janky, expensive | Scroll-driven animations |
| JS for tooltip positioning | Floating UI dependency | Anchor positioning |
| JS for carousel controls | Fragile, a11y issues | ::scroll-button, ::scroll-marker |
| JS for auto-expanding textarea | Unnecessary complexity | field-sizing: content |
| max-height: 9999px for animation | Wrong duration, janky | interpolate-size: allow-keywords |
| margin-left / padding-right | Breaks in RTL/vertical | Logical 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 variables | Can't change at runtime | CSS custom properties |
| Preprocessor-only nesting | Extra build step dependency | Native CSS nesting |
| Preprocessor color functions | Can't respond to context | color-mix(), relative colors |
| text-wrap: balance on paragraphs | Performance-heavy | Only headings/short text |
| content-visibility above fold | Delays LCP rendering | Only off-screen sections |
| Overusing will-change | Wastes GPU memory | Apply only to animating elements |
| File | Purpose |
|------|---------|
| references/CASCADE.md | Nesting, @layer, @scope, cascade control, and CSS architecture |
| references/LAYOUT.md | Grid, Subgrid, Flexbox, Container Queries, and intrinsic sizing |
| references/SELECTORS.md | :has(), :is(), :where(), pseudo-elements, and state-based selection |
| references/COLOR.md | OKLCH, 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.md | Scroll-driven animations, scroll-state queries, native carousels |
| references/COMPONENTS.md | Customizable <select>, popover, anchor positioning, field-sizing |
| references/PERFORMANCE.md | content-visibility, typography, logical properties, accessibility |
| references/CHEATSHEET.md | Quick reference: browser support, legacy→modern patterns, units |
if(), random(), sibling-index/count()@function, @mixindevelopment
Proactively apply when generating any Slack text content, chat.postMessage text fields, or text objects with type "mrkdwn". Triggers on mrkdwn, Slack formatting, Slack markdown, Slack bold, Slack italic, Slack link syntax, Slack mentions, Slack date formatting, Slack escaping, Slack text object, verbatim, plain_text, Slack mrkdwn vs markdown, Slack blockquote, Slack code block, Slack strikethrough, Slack user mention, Slack channel mention, Slack emoji, link_names, auto-parsing. Use when formatting Slack message text, writing mrkdwn strings, constructing text objects, escaping user content for Slack, adding mentions or date formatting to messages, or debugging text rendering issues. Slack mrkdwn text formatting syntax for messages, text objects, and attachments.
development
Proactively apply when generating Slack API payloads with blocks, chat.postMessage calls with structured content, streaming AI responses, or views.open/views.publish calls. Triggers on Block Kit, Slack blocks, section block, actions block, header block, divider block, context block, alert block, card block, carousel block, table block, markdown block, rich text block, image block, input block, video block, context_actions block, plan block, task_card block, chat.startStream, chat.appendStream, chat.stopStream, Slack modal, Slack App Home, Slack surfaces, Slack interactive elements, Slack button, Slack select menu, Slack overflow, Slack datepicker, Slack checkboxes, Slack radio buttons, Work Objects, Slack link unfurl, chat.postMessage blocks, views.open, views.update, views.push, views.publish, Slack composition objects. Use when building Block Kit payloads, constructing blocks arrays, creating modals or App Home views, adding interactive elements, implementing link unfurling with Work Objects, streaming agent output, or designing rich message layouts. Slack Block Kit UI framework for building rich message layouts, modals, App Home views, and AI agent responses.
development
Proactively apply when creating APIs, backends, or data models. Triggers on PostgreSQL, Postgres, Drizzle, database, schema, tables, columns, indexes, queries, migrations, ORM, relations, joins, transactions, SQL, drizzle-kit, connection pooling, N+1, JSONB, RLS. Use when writing database schemas, queries, migrations, or any database-related code. PostgreSQL and Drizzle ORM best practices.
development
Proactively apply when creating web applications, Node.js services, or any JavaScript project. Triggers on JavaScript, ES6, ES2020, ES2022, ES2024, modern JS, refactor legacy, array methods, async/await, optional chaining, nullish coalescing, destructuring, spread, rest, template literals, arrow functions, toSorted, toReversed, at, groupBy, Promise, functional programming. Use when writing new JavaScript code, refactoring legacy code, modernizing codebases, implementing functional patterns, or reviewing JS for performance and readability. Modern JavaScript (ES6-ES2025) patterns and best practices.