skills/more-css/SKILL.md
Write scalable, well-architected CSS using design tokens, cascade layers, and modern organization patterns. Use this skill as the default for any real project — if it has more than a handful of CSS files, multiple components, a team, a design system, or any kind of token or theming setup, this is the right skill.
npx skillsauth add mikemai2awesome/agent-skills more-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.
Make intentional decisions about structure, tokens, and tooling so CSS scales across components, themes, teams, and time.
No frameworks. Do not use TailwindCSS, UnoCSS, Bootstrap, or any other CSS framework. Write vanilla CSS only. If a utility layer is needed, build it — don't import it.
@layer to make specificity predictable and override-safeborder-width and outline-width; px anywhere else overrides user preferencesAlways declare layers upfront to make load-order explicit:
@layer config, resets, components, utilities, overrides;
u-visuallyhidden, u-truncate)Organize files to mirror the layer order:
styles/
├── config/
│ ├── color.css # Color custom properties
│ ├── spacing.css # Spacing scale
│ ├── typography.css # Font sizes, weights, families
│ └── index.css # Imports all config files
├── resets.css
├── components/
│ ├── button.css
│ └── card.css
├── utilities.css
└── main.css # @import or @layer everything
Use custom properties as your single source of truth. Define them in the config layer so every other layer can reference them.
Define all color tokens in OKLCH. It has a wider gamut than sRGB, perceptually uniform lightness (so oklch(40% ...) is always visibly darker than oklch(60% ...)), and makes generating hover/muted variants predictable — just adjust the L value.
/* Don't do this — hex values aren't perceptually predictable */
--color-bg-primary: #0066cc;
--color-bg-primary-hover: #0052a3; /* how much darker is this? */
/* Do this — lightness is explicit and adjustable */
--color-bg-primary: oklch(50% 0.2 260);
--color-bg-primary-hover: oklch(43% 0.2 260); /* clearly 7% darker */
This also makes dark mode token overrides straightforward — flip lightness, keep chroma and hue.
Use a --[category]-[variant]-[modifier] pattern. For color tokens, use text, bg, or border as the variant — no other color groupings:
@layer config {
:root {
color-scheme: light dark;
/* Color — text */
--color-text-default: light-dark(oklch(15% 0 0), oklch(92% 0 0));
--color-text-muted: light-dark(oklch(45% 0 0), oklch(65% 0 0));
--color-text-on-primary: oklch(99% 0 0);
--color-text-primary: oklch(50% 0.2 260);
/* Color — bg */
--color-bg-default: light-dark(oklch(98% 0 0), oklch(15% 0 0));
--color-bg-subtle: light-dark(oklch(95% 0 0), oklch(20% 0 0));
--color-bg-primary: oklch(50% 0.2 260);
--color-bg-primary-hover: oklch(43% 0.2 260);
/* Color — border */
--color-border-default: light-dark(oklch(80% 0 0), oklch(35% 0 0));
--color-border-primary: oklch(50% 0.2 260);
/* Spacing */
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
--space-12: 3rem;
--space-16: 4rem;
/* Typography */
--font-family: system-ui, sans-serif;
--font-family-code: ui-monospace, monospace;
--font-size-sm: 0.875rem;
--font-size-md: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-bold: 700;
--line-height-tight: 1.25;
--line-height-base: 1.5;
/* Border */
--border-radius-sm: 0.25rem;
--border-radius-md: 0.5rem;
--border-radius-lg: 0.75rem;
--border-width: 1px;
/* Shadow */
--shadow-sm: 0 0.0625rem 0.125rem oklch(0% 0 0 / 0.08);
--shadow-md: 0 0.25rem 0.5rem oklch(0% 0 0 / 0.1);
--shadow-lg: 0 0.5rem 1.5rem oklch(0% 0 0 / 0.12);
/* Motion */
--duration-fast: 150ms;
--duration-base: 250ms;
--duration-slow: 400ms;
--easing-default: ease;
--easing-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
}
Define each theme-aware token once using light-dark() and let the browser switch automatically based on color-scheme. For user-togglable themes, just flip color-scheme — no token values need to be repeated:
@layer config {
/* User-toggled theme — light-dark() reads color-scheme automatically */
[data-theme="light"] {
color-scheme: light;
}
[data-theme="dark"] {
color-scheme: dark;
}
}
rem, Not pxrem scales with the user's browser default font size and system text-size preferences. px ignores both — a user who sets their browser to 20px large text gets no benefit from your font-size: 16px declaration.
/* Don't do this — px overrides the user's preferences */
--font-size-md: 16px;
.c-heading { font-size: 24px; }
/* Do this — rem respects the browser default */
--font-size-md: 1rem;
--font-size-2xl: 1.5rem;
All font-size tokens must be in rem. Never override them with px in components.
clamp() and Container Query UnitsFor headings and display text that should scale with available space, use clamp() with a container query unit (cqi) as the ideal value. cqi is 1% of the container's inline size — it responds to the element's actual container, not the viewport, so type in a narrow card column scales correctly even when the viewport is wide.
rem must remain the anchor for the minimum value so the type hierarchy still works when a user zooms to 200%+.
/* Fluid heading: scales between 1.25rem and 3rem based on container width */
h1 {
font-size: clamp(1.25rem, 5cqi, 3rem);
}
cqi requires the parent to establish a containment context:
.c-card {
container-type: inline-size;
}
Use vb as the fluid value only when no containment context exists and the type genuinely scales with the viewport block axis. For most UI components, cqi is the right choice.
Fluid layouts adapt to available space without hard-coded breakpoints. Prefer intrinsic sizing over media queries — let the content and container determine when things wrap or resize.
Preferred units for layout:
% and fr — proportional sizing within grid and flex containersvi / vb / dvi / dvb — logical viewport units (inline and block axis); prefer these over vw/vh so layouts work across writing modes and directionsch — character-width unit; ideal for setting minimum column widths based on readable content widthmin(), max(), clamp() — responsive sizing in a single declaration without a breakpointrem — spacing tokens are already in rem; use them for gaps and paddingborder-width and outline-width are the only px exceptions — hairline borders and focus rings should stay crisp at a fixed thickness regardless of zoom. Everything else (shadows, spacing, radii) uses relative units.
auto-fit + minmax()repeat(auto-fit, minmax()) creates a self-wrapping column grid with no media queries. Columns expand to fill space (auto-fit) and wrap when they'd drop below the minimum (minmax()).
.c-grid {
display: grid;
gap: var(--space-4);
grid-template-columns: repeat(auto-fit, minmax(20ch, 1fr));
}
Use ch for the minimum — it ties the breakpoint to readable content width rather than an arbitrary pixel value. Use a component-scoped custom property to make it overridable per instance:
.c-grid {
--c-grid-col-min: 20ch;
grid-template-columns: repeat(auto-fit, minmax(var(--c-grid-col-min), 1fr));
}
Use auto-fill instead of auto-fit when you want empty columns to preserve their space (e.g. keeping a grid locked to N columns even when fewer items are present).
For flex layouts where items should wrap independently at their own threshold, use flex: 1 1 <min>. Each item grows and shrinks freely but won't collapse below the minimum before wrapping.
.c-list {
display: flex;
flex-wrap: wrap;
gap: var(--space-4);
}
.c-list > * {
flex: 1 1 20ch;
}
This allows ch units (unlike the flex albatross calc() trick) and lets each item wrap independently rather than all items breaking at once.
Use BEM (Block, Element, Modifier) for components — it's verbose but unambiguous at scale:
/* Block */
.c-card {
}
/* Element (part of the block) */
.c-card__header {
}
.c-card__body {
}
.c-card__footer {
}
/* Modifier (variant of block or element) */
.c-card--featured {
}
.c-card__header--compact {
}
Use the c- prefix for components, u- for utilities, and js- for JavaScript hooks (never styled).
State classes use is- / has- (e.g. .is-loading, .has-error), but prefer ARIA attribute selectors where possible (e.g. [aria-expanded="true"], [aria-disabled="true"]).
<div class="c-card c-card--featured js-expandable">
<div class="c-card__header">...</div>
</div>
Each component file should follow a consistent internal structure:
@layer components {
/* 1. Block */
.c-button {
/* Layout */
display: inline-flex;
align-items: center;
gap: var(--space-2);
padding-block: var(--space-2);
padding-inline: var(--space-4);
/* Typography */
font-family: var(--font-family);
font-size: var(--font-size-md);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-tight);
/* Visual */
background-color: var(--color-bg-primary);
color: var(--color-text-on-primary);
border: var(--border-width) solid transparent;
border-radius: var(--border-radius-md);
/* Interaction */
cursor: pointer;
transition: background-color var(--duration-fast) var(--easing-default);
}
/* 2. States */
.c-button:hover {
background-color: var(--color-bg-primary-hover);
}
.c-button:focus-visible {
outline: 2px solid var(--color-border-primary);
outline-offset: 0.125rem;
}
[aria-disabled="true"].c-button,
.c-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* 3. Modifiers */
.c-button--ghost {
background-color: transparent;
border-color: var(--color-border-primary);
color: var(--color-text-primary);
}
.c-button--sm {
padding-block: var(--space-1);
padding-inline: var(--space-3);
font-size: var(--font-size-sm);
}
}
Components reference tokens — they never hardcode values. If you find yourself writing a raw color or a raw value inside a component, define a token for it first. This applies to focus styles too — always reference a token for the outline color so it stays on-brand and themeable.
Use :focus-visible (not :focus) for keyboard-only focus rings.
| Situation | Pattern |
| ----------------------- | -------------------------------------------------- |
| Defining a color value | Token in @layer config |
| Building a UI component | .c- class in @layer components |
| One-off helper | .u- class in @layer utilities |
| JS needs a hook | .js- class, never styled |
| Component state | ARIA attribute selector, then .is-/.has- |
| Theming / dark mode | light-dark() in tokens; color-scheme to toggle |
| Font sizes | rem tokens only — never px |
| Layout sizing | %, fr, vi/vb/dvi/dvb, min()/clamp(), rem — px only for border-width and outline-width |
Read these when you need more detail than the guidelines above:
development
Implement accessibility in iOS apps using Swift, UIKit, and SwiftUI. Use this skill whenever working on any iOS development task that involves: making UI elements accessible to VoiceOver or other assistive technologies, adding or reviewing accessibility labels/hints/traits/actions/values, supporting Dynamic Type or text scaling, respecting Reduce Motion or reduced transparency preferences, adapting to Dark Mode or increased contrast, building accessible forms and inputs, announcing dynamic content changes, managing focus programmatically, customizing accessibility focus order, supporting external keyboard navigation, or auditing iOS code for accessibility issues. Trigger even when the user only says "SwiftUI" or "UIKit" without mentioning "accessibility" explicitly — if they're building custom controls, modals, forms, lists, or animated views, this skill applies.
development
Write minimal, efficient CSS for small or minimalist projects by trusting the browser instead of fighting it. Only use this skill for personal sites, prototypes, simple landing pages, or projects intentionally kept lean — if the project has multiple developers, a component library, a design token system, or more than a handful of CSS files, a more comprehensive CSS approach is needed. If you're about to write a CSS reset, declare a base font-size on :root, set default colors on body, use px for spacing, or reach for physical margin/padding properties, this skill will stop you.
development
Create web interfaces with an authentic early-2010s aesthetic. Use this skill when the user wants a 2010s-era, Web 2.0, or retro corporate web look — gradient headers, glossy buttons, skeuomorphic icons, horizontal band layouts, and drop shadows from circa 2010–2014.
development
Define and enforce consistent coding standards across HTML, CSS, and JavaScript. Always use this skill when naming a new class, variable, component, or file; setting up a new project's conventions; choosing a class prefix for a new CSS category; deciding on modifier API names (sizes, shades, hierarchy, breakpoints); or reviewing code for formatting and naming consistency. If you're about to invent a prefix, abbreviation, or modifier name without checking the conventions first, use this skill.