Guide writing or changing CSS so the change fits the project: find its browser targets, build pipeline, stylesheet ownership, naming convention and design tokens first, then make the smallest maintainable change, with the right layout mechanism, responsive and right-to-left behavior, WCAG 2.2 AA accessibility, a fallback for any feature a target lacks, and a check of the result. Use whenever you write or edit stylesheets, style blocks, CSS Modules, Tailwind classes or CSS-in-JS, including layout fixes, theming, dark mode, responsive work and focus styles, even when the user doesn't say CSS. It never restructures a stylesheet, adds a methodology or framework, or renames existing classes unless asked. Not for reviewing CSS already written (the knackpack:css-code-reviewer agent, started only when the user asks for a review), the look and flow of a running app (the UI reviewer), React's own semantics (the React reviewer), or custom elements' behavior (the web-components-engineering skill).
89%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Write CSS the way the project already writes it, change as little as the requirement needs, and leave nothing that breaks for a keyboard user, a right-to-left reader, someone at 200% zoom or a browser the project supports. These rules hold for every edit, however small: a one-line style fix is where an unseen stacking context or an unsupported feature slips through.
@scope, a preprocessor or a CSS framework the project doesn't use, unless the user asks.npx (with no terminal attached it downloads and runs missing packages without asking), and never run a tool's fix or write mode (stylelint --fix, prettier --write) over files you didn't change. Use the tools already in node_modules, by path.Read before writing, and keep the answers in mind for every step:
browserslist in package.json or .browserslistrc (and its environment sections), a Baseline target in docs or build config, and floors the toolchain imposes: Vite 8's default CSS target is a fixed Baseline-widely-available set, Lightning CSS takes its own targets, and Tailwind v4 needs Safari 16.4, Chrome 111 and Firefox 128. With no targets declared, assume Baseline widely available and say so.postcss-preset-env may compile nesting), Lightning CSS, Tailwind's major version, CSS Modules, CSS-in-JS. Write source the pipeline understands: &__element concatenation is Sass and isn't valid in native nesting.@layer order and where it's first stated; how components are isolated.--blue-600, semantic roles such as --color-text-muted, component tokens), and how themes and dark mode switch them..is-open, [aria-expanded="true"], [data-state]).grep the class names and custom properties across the repository.Reuse before adding. Use an existing token for every color, space, radius, shadow, font size and z-index that has one; prefer the semantic token over the primitive. Add a token only when the role is new, named by role, not value, in the token source. Extend a component with a modifier or a custom property it exposes rather than reaching into it from a page (.reports-page .media__title).
Pick the layout mechanism by the problem:
min-width: 0 (or min-height: 0 in a column), or long words and tables overflow the container.minmax(0, 1fr) where a track holds long content, repeat(auto-fit, minmax(<min>, 1fr)) for card grids that reflow without breakpoints, and subgrid to align children across cards, spanning the parent tracks they share.min(), max(), clamp(), fit-content, max-inline-size and wrapping let layouts adapt without breakpoints.container-type: inline-size (not size, which collapses a container whose height comes from its content); and a container-name on shared components.margin-inline-start, inset-inline-end, text-align: start) when the product ships right-to-left or vertical text, or is a library others localize; otherwise follow the file's existing style. Don't mix a physical and a logical property for the same side.Keep the cascade predictable: match the specificity of the rules around it; no IDs or !important unless the project uses them for that purpose; :where() for defaults that consumers must override easily. Unlayered rules beat every layered rule, so put new rules in the layer the project uses for that kind of code. Native nesting's & takes the highest specificity of its parent list.
z-index only competes within its stacking context. transform, opacity below 1, filter, backdrop-filter, isolation, will-change, contain, position: fixed or sticky, and a z-index on a positioned element or a flex or grid item all create one. Before raising a z-index, find the contexts of both elements; use the project's z-index scale. Dialogs opened with showModal() and popovers live in the top layer, where z-index does nothing.transform, filter, backdrop-filter, perspective, contain: layout or paint, or content-visibility: auto traps position: fixed inside it. position: sticky needs an inset such as top, stops at its parent's end, and fails under any ancestor with overflow: hidden, auto or scroll.100vw includes a classic scrollbar and causes horizontal scrolling; prefer 100%. On mobile, 100vh is the large viewport and hides content behind the toolbar; use 100svh or 100dvh, with 100vh first as a fallback if a target lacks them.var() whose property is undefined makes the declaration fall to unset, not to an earlier declaration, so give var() a fallback argument; an @property with a relative-unit initial-value or a missing descriptor is ignored; one unsupported selector in a list drops the whole rule (except inside :is() and :where()); an @import after other rules is ignored; light-dark() needs color-scheme: light dark.display rule overrides the hidden attribute; opacity: 0 leaves content focusable; display: contents on a button, link, list, table or heading breaks its accessibility.Meet WCAG 2.2 at the project's level, AA by default:
:focus-visible. Draw focus rings with an outline (offset if needed), or keep a transparent outline beside a box-shadow ring, since forced-colors mode removes shadows and repaints outlines.@media (forced-colors: active), use system colors (CanvasText, ButtonText, Highlight); keep forced-color-adjust: none to swatches and similar.min-height, not a fixed px height with hidden overflow); never size text only in viewport units; break long strings with overflow-wrap.:focus-visible or :focus-within; hover-only effects go inside @media (hover: hover).scroll-padding-top (or -bottom) at least the bar's height, so focused controls aren't hidden under it.order, *-reverse or grid placement.@media (prefers-reduced-motion: no-preference), or tone it down under reduce with a tiny duration rather than 0s, which stops end events from firing. Anything that moves by itself for more than five seconds beside content needs a pause control.color-scheme with the theme so form controls and scrollbars match.Classify each feature you use by the targets, with current data (MDN's compatibility tables, webstatus.dev, web.dev's Baseline pages):
@supports testing the exact feature (@supports (display: grid) doesn't test subgrid). Essential UI must not depend on it.Don't add a fallback for a feature every target supports, and don't adopt a feature only because it's new.
node_modules, on the files you changed, without fix or write options; fix only what you introduced.dir="rtl", dark mode, forced colors and reduced motion (browser developer tools can emulate the last three).bezmoradi/knackpack
fb3e936
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.