html-css-guide
SKILL.md
HTML/CSS Guide
Applies to: HTML5, CSS3, SCSS/LESS, Responsive Design, WCAG 2.1 AA
Core Principles
- Semantic First: Use HTML elements for their meaning, not their appearance; style with CSS
- Accessible by Default: Every page must be navigable by keyboard, screen reader, and assistive technology
- Progressive Enhancement: Build a solid HTML foundation, then layer on CSS and JavaScript
- Mobile First: Design for the smallest viewport, then enhance with
min-widthmedia queries - Performance Budget: Minimize render-blocking resources; prefer system fonts, modern image formats, and critical CSS inlining
Guardrails
Semantic HTML
- Use
<main>once per page;<header>,<footer>,<nav>,<aside>for landmarks - Use
<article>for self-contained content;<section>for thematic groups with a heading - Use
<figure>/<figcaption>for captioned media;<time datetime="...">for dates - Headings (
<h1>-<h6>) must follow a logical outline; never skip levels for styling - Use
<button>for actions and<a>for navigation; never<div onclick> - Lists (
<ul>,<ol>,<dl>) for groups of related items; not<div>sequences
<article>
<header>
<h2>Deploying with Zero Downtime</h2>
<time datetime="2025-03-15">March 15, 2025</time>
</header>
<section aria-labelledby="prereqs">
<h3 id="prereqs">Prerequisites</h3>
<ul>
<li>Container runtime (Docker or Podman)</li>
<li>Load balancer with health checks</li>
</ul>
</section>
</article>
Accessibility (WCAG 2.1 AA)
- Every
<img>must havealt; decorative images usealt="" - All form inputs must have associated
<label>elements (usefor/id) - Color contrast: 4.5:1 for normal text, 3:1 for large text (18px+ bold or 24px+)
- Focus indicators must be visible; never
outline: nonewithout a replacement - Skip-to-content link as the first focusable element on every page
- All interactive elements must be keyboard-operable
- Use
aria-live="polite"for dynamic updates;role="alert"for immediate announcements - Use
aria-expanded,aria-controls,aria-haspopupfor disclosure widgets - Do not rely on color alone to convey information (add icons, text, or patterns)
<a href="#main" class="skip-link">Skip to main content</a>
<form aria-labelledby="signup-heading">
<h2 id="signup-heading">Create Account</h2>
<label for="email">Email</label>
<input id="email" type="email" required autocomplete="email"
aria-describedby="email-hint" />
<p id="email-hint" class="hint">We will never share your email.</p>
<button type="submit">Create Account</button>
</form>
CSS Architecture
- One component per file; file name matches component (
card.css,nav.css) - Use
@layerfor specificity control: reset, base, layout, components, utilities - Prefer BEM (
.block__element--modifier) or utility-first -- pick one, stay consistent - Never use
!importantoutside utility overrides; fix specificity instead - Max 3 levels of nesting (native or preprocessor)
- Custom properties for all theme values (colors, spacing, typography, radii)
- No inline styles unless dynamically computed by JavaScript
@layer reset, base, layout, components, utilities;
@layer base {
:root {
--color-primary: oklch(55% 0.22 265);
--color-surface: oklch(98% 0.005 265);
--color-text: oklch(20% 0.02 265);
--space-sm: 0.5rem;
--space-md: 1rem;
--space-lg: 2rem;
--radius-md: 0.5rem;
--font-body: system-ui, -apple-system, sans-serif;
}
}
@layer components {
.card { background: var(--color-surface); border-radius: var(--radius-md); padding: var(--space-md); }
.card__title { font-size: 1.25rem; color: var(--color-text); }
.card--featured { border: 2px solid var(--color-primary); }
}
Performance
- Inline critical CSS in
<head>for first contentful paint - Use
font-display: swapfor web fonts; prefer system font stacks - Modern image formats: AVIF > WebP > JPEG; use
<picture>with fallbacks - Animate only
transformandopacityto avoid layout reflows - Use
content-visibility: autofor off-screen sections - Set
width/heightoraspect-ratioon media to prevent layout shift
<picture>
<source srcset="hero.avif" type="image/avif" />
<source srcset="hero.webp" type="image/webp" />
<img src="hero.jpg" alt="Dashboard overview" width="1200" height="630"
loading="lazy" decoding="async" />
</picture>
Responsive Design
- Mobile-first: base styles for small screens, add complexity with
min-widthqueries - Use
rem/emfor sizing; reservepxfor borders and fine details only - Fluid typography with
clamp():font-size: clamp(1rem, 0.5rem + 1.5vw, 1.5rem) - Container queries (
@container) for component-level responsiveness - Test at 320px, 768px, 1024px, 1440px, and with 200% browser zoom
- Touch targets: at least 44x44px on mobile
Key Patterns
Grid (2D) vs Flexbox (1D)
Use CSS Grid for page layouts with rows and columns; use Flexbox for single-axis alignment.
/* Grid: 2D page layout */
.page {
display: grid;
grid-template: "header header" auto "sidebar main" 1fr "footer footer" auto / 16rem 1fr;
min-height: 100dvh;
}
/* Flexbox: 1D navigation */
.nav { display: flex; align-items: center; gap: var(--space-md); }
.nav__logo { margin-right: auto; }
Container Queries
.card-container { container-type: inline-size; container-name: card; }
@container card (min-width: 30rem) {
.card { flex-direction: row; align-items: center; }
}
The :has() Selector
.field:has(input:focus) { outline: 2px solid var(--color-primary); }
.card:has(img) { padding: 0; }
form:has(:invalid) button[type="submit"] { opacity: 0.5; pointer-events: none; }
Cascade Layers (@layer)
@layer reset, base, layout, components, utilities;
@layer reset { *, *::before, *::after { box-sizing: border-box; margin: 0; } }
@layer utilities {
.visually-hidden {
clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px;
overflow: hidden; position: absolute; white-space: nowrap; width: 1px;
}
}
Dark Mode and User Preferences
:root { color-scheme: light dark; --color-bg: oklch(98% 0.005 265); }
@media (prefers-color-scheme: dark) { :root { --color-bg: oklch(15% 0.02 265); } }
[data-theme="dark"] { --color-bg: oklch(15% 0.02 265); }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important; transition-duration: 0.01ms !important;
}
}
Accessibility Checklist (WCAG 2.1 AA)
Perceivable
- All images have descriptive
alt(oralt=""for decorative) - Color contrast: 4.5:1 body text, 3:1 large text
- Information not conveyed by color alone
- Text resizable to 200% without content loss
- Captions for video; transcripts for audio
Operable
- All functionality keyboard-accessible (Tab, Enter, Escape, arrows)
- Logical focus order; visible focus indicators
- No keyboard traps; modals return focus on close
- Skip navigation link as first focusable element
- Touch targets at least 44x44px
Understandable
-
<html lang="...">set correctly - Form inputs have visible labels and descriptive error messages
- Consistent navigation across pages
Robust
- Valid HTML (W3C validator)
- ARIA roles, states, and properties match widget behavior
- Tested with screen reader (VoiceOver, NVDA, or JAWS)
- Tested with 200% browser zoom
Tooling
npx stylelint "**/*.css" # CSS lint
npx stylelint "**/*.css" --fix # CSS lint auto-fix
npx htmlhint "**/*.html" # HTML validation
npx prettier --check "**/*.{html,css,scss}" # Format check
npx prettier --write "**/*.{html,css,scss}" # Format fix
npx lighthouse http://localhost:3000 --output html --view # Audit
npx @axe-core/cli http://localhost:3000 # Accessibility check
npx pa11y http://localhost:3000 # Accessibility test
Stylelint Configuration
{
"extends": ["stylelint-config-standard"],
"rules": {
"declaration-no-important": true,
"selector-max-specificity": "0,3,0",
"max-nesting-depth": 3,
"color-function-notation": "modern",
"selector-class-pattern": "^[a-z][a-z0-9]*(__[a-z0-9-]+)?(--[a-z0-9-]+)?$"
}
}
References
For detailed layout examples, accessibility patterns, and modern CSS features, see:
- references/patterns.md -- Grid/Flexbox layouts, modal dialogs, fluid typography, scroll animations
External References
Weekly Installs
10
Repository
ar4mirez/samuelGitHub Stars
3
First Seen
Feb 20, 2026
Security Audits
Installed on
opencode10
github-copilot10
codex10
kimi-cli10
gemini-cli10
amp10