HTML & CSS
Master Guide
Everything a fullstack developer needs to know — from semantic structure to modern layout systems, animations, architecture, accessibility, and production performance.
HTML Fundamentals
HTMLHTML (HyperText Markup Language) is the skeleton of every webpage. It provides structure and meaning to content — not styling. Understanding it deeply is non-negotiable for fullstack work.
Anatomy of an HTML Element
<!-- Opening tag Attribute name Attribute value Content Closing tag --> <a href="https://example.com" target="_blank">Visit Example</a> <!-- Void (self-closing) elements have no closing tag --> <img src="photo.jpg" alt="A scenic view" width="800" height="600"> <br> <hr> <input> <meta> <link> <source>
Global Attributes
These apply to any HTML element:
| Attribute | Purpose | Example |
|---|---|---|
| id | Unique identifier on page | id="header" |
| class | CSS class targeting (space-separated) | class="card active" |
| data-* | Custom data attributes for JS | data-user-id="42" |
| style | Inline CSS (avoid in production) | style="color:red" |
| hidden | Hides element from rendering | hidden |
| tabindex | Controls keyboard focus order | tabindex="0" |
| contenteditable | Makes element editable inline | contenteditable="true" |
| draggable | Enables drag-and-drop | draggable="true" |
| lang | Language of element's content | lang="en" |
| title | Tooltip on hover | title="More info" |
| aria-* | Accessibility roles/properties | aria-label="Close" |
| role | ARIA semantic role | role="dialog" |
- Create an HTML file with a heading, paragraph, image (with meaningful alt text), and a link that opens in a new tab.
- Add
data-categoryattributes to at least 3 elements. - Use
titleattribute on the link to show a helpful tooltip. - Validate your HTML at validator.w3.org — fix all errors.
Document Structure
HTMLThe Complete Boilerplate
<!DOCTYPE html> <html lang="en"> <head> <!-- Character encoding — always first --> <meta charset="UTF-8"> <!-- Responsive viewport --> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SEO meta tags --> <meta name="description" content="Page description for search engines"> <meta name="keywords" content="html, css, tutorial"> <meta name="author" content="Your Name"> <!-- Open Graph (social media previews) --> <meta property="og:title" content="Page Title"> <meta property="og:description" content="Description"> <meta property="og:image" content="https://example.com/image.jpg"> <meta property="og:url" content="https://example.com"> <!-- Favicon --> <link rel="icon" type="image/png" href="/favicon.png"> <!-- Fonts — preconnect for performance --> <link rel="preconnect" href="https://fonts.googleapis.com"> <!-- Canonical URL (prevents duplicate content) --> <link rel="canonical" href="https://example.com/page"> <!-- Stylesheet --> <link rel="stylesheet" href="styles.css"> <title>Page Title | Site Name</title> </head> <body> <!-- Content goes here --> <!-- Scripts at end of body for performance --> <script src="app.js" defer></script> </body> </html>
defer on scripts to load them without blocking HTML parsing. Use async for scripts that don't depend on DOM or other scripts. Never use bare <script> in <head> without defer/async.- Build a complete HTML boilerplate from memory.
- Add full Open Graph tags and test with opengraph.xyz.
- Add a
<meta name="theme-color">and test on mobile Chrome.
Semantic HTML
HTML AccessibilitySemantic HTML gives meaning to structure. It matters for SEO, screen readers, and maintainability. A fullstack dev who ships <div> soup is a junior dev regardless of their backend skills.
Page-Level Landmarks
<body> <header> <!-- Site-wide header, logo, top nav --> <nav> <!-- Primary navigation links --> <ul><li><a href="/">Home</a></li></ul> </nav> </header> <main> <!-- ONE per page — the unique content --> <article> <!-- Self-contained content (blog post, card) --> <h1>Post Title</h1> <section> <!-- Themed section within article --> <h2>Introduction</h2> <p>...</p> </section> </article> <aside> <!-- Sidebar, related links, ads --> <p>Related posts...</p> </aside> </main> <footer> <!-- Copyright, links, contact --> <address>contact@site.com</address> </footer> </body>
Content Semantics Cheatsheet
| Element | Use when… | Don't use for… |
|---|---|---|
| <h1>–<h6> | Hierarchical headings — one h1 per page | Bold text, decorative sizing |
| <p> | Paragraphs of prose | Line breaks or spacing hacks |
| <ul> / <ol> | Unordered/ordered lists | Navigation (use nav+ul) |
| <dl> <dt> <dd> | Definition/description lists | Key-value pairs in general |
| <figure> / <figcaption> | Images with captions, diagrams | Decorative images |
| <blockquote> | Quoted text from another source | Indentation styling |
| <cite> | Title of creative work being cited | Author attribution |
| <time> | Dates/times (machine-readable) | Durations as plain text |
| <mark> | Highlighted/search-result text | General emphasis |
| <strong> | Strong importance | Bold for styling only (use CSS) |
| <em> | Stress emphasis | Italic for styling only |
| <abbr> | Abbreviations with title="…" | Acronyms that are self-evident |
| <details> / <summary> | Native accordion / disclosure | Complex interactive components |
| <dialog> | Modal dialogs (native) | Tooltips or dropdowns |
| <progress> | Task completion bars | Decorative bars |
| <meter> | Scalar measurement within range | Generic bars |
- Take a page made entirely of
<div>and<span>tags and refactor it to use proper semantic elements. - Verify with an accessibility audit: open DevTools → Lighthouse → Accessibility. Target 90+.
- Use
<details>/<summary>to build a FAQ section with NO JavaScript. - Add
<time datetime="2025-01-15">for all dates on the page.
Forms & Inputs
HTMLForms are how users talk to your backend. Getting them right — semantics, validation, accessibility — is a core fullstack skill.
Complete Form Reference
<form action="/api/submit" <!-- Where to send data --> method="post" <!-- GET or POST --> enctype="multipart/form-data" <!-- Required for file uploads --> novalidate <!-- Disable browser validation (use custom) --> autocomplete="on" > <!-- Every input needs a label --> <label for="email">Email Address</label> <input type="email" id="email" name="email" placeholder="you@example.com" required autocomplete="email" aria-describedby="email-hint" > <span id="email-hint">We'll never share your email.</span> <!-- Fieldset groups related controls --> <fieldset> <legend>Preferred contact method</legend> <label><input type="radio" name="contact" value="email"> Email</label> <label><input type="radio" name="contact" value="phone"> Phone</label> </fieldset> <button type="submit">Submit</button> <button type="reset">Clear</button> </form>
Input Types Reference
- Build a full registration form: name, email, password (with pattern validation), date of birth, gender (radio), country (select), bio (textarea), file upload for avatar, and terms checkbox.
- Every input must have a
<label for>and use properautocompleteattributes. - Add HTML5 constraint validation attributes:
required,minlength,maxlength,pattern,min,max. - Style
:validand:invalidstates with CSS (green/red borders).
Multimedia & SVG
HTMLResponsive Images
<!-- Basic responsive image --> <img src="hero.jpg" srcset="hero-480.jpg 480w, hero-800.jpg 800w, hero-1200.jpg 1200w" sizes="(max-width: 600px) 480px, (max-width: 1000px) 800px, 1200px" alt="Mountain landscape at dawn" width="1200" height="630" loading="lazy" decoding="async" > <!-- Art direction with <picture> --> <picture> <source media="(min-width: 800px)" srcset="desktop.webp" type="image/webp"> <source media="(min-width: 800px)" srcset="desktop.jpg"> <source srcset="mobile.webp" type="image/webp"> <img src="mobile.jpg" alt="Description"> </picture> <!-- Video with fallback --> <video controls poster="thumbnail.jpg" preload="metadata"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> <track kind="subtitles" src="subs.vtt" srclang="en" label="English"> <p>Your browser doesn't support video.</p> </video>
Inline SVG
<!-- Inline SVG is styleable with CSS, accessible, performant --> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" <!-- Decorative icon — hide from AT --> focusable="false" > <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" stroke="currentColor" <!-- Inherits CSS color --> fill="none" stroke-width="2" /> </svg> <!-- SVG sprite system --> <svg style="display:none"> <symbol id="icon-home" viewBox="0 0 24 24">...</symbol> </svg> <!-- Use it anywhere --> <svg><use href="#icon-home"></use></svg>
CSS Selectors
CSSSelectors are CSS's targeting system. Master them to write efficient, maintainable styles.
Selector Specificity
/* Specificity: (0,0,0,1) */ p { color: gray; } /* (0,0,1,0) — class selector */ .card { color: blue; } /* (0,0,1,1) */ p.intro { color: green; } /* (0,1,0,0) — ID selector */ #hero { color: red; } /* (1,0,0,0) — inline style beats all */ style="color: orange" /* :is() takes highest specificity of its list */ :is(#hero, .card, p) { color: purple; } /* = (0,1,0,0) */ /* :where() has ZERO specificity — great for resets */ :where(h1, h2, h3) { margin: 0; }
Complete Selector Reference
| Selector | Matches | Example |
|---|---|---|
| * | Everything | * { box-sizing: border-box } |
| E | Element type | p, h1, section |
| .class | Class attribute | .card, .btn-primary |
| #id | ID attribute | #header, #modal |
| A B | B inside A (any depth) | .card p |
| A > B | B direct child of A | ul > li |
| A + B | B immediately after A | h2 + p |
| A ~ B | B sibling(s) after A | h2 ~ p |
| [attr] | Has attribute | [disabled] |
| [attr="val"] | Exact value | [type="checkbox"] |
| [attr^="v"] | Starts with | [href^="https"] |
| [attr$="v"] | Ends with | [href$=".pdf"] |
| [attr*="v"] | Contains | [class*="btn"] |
| :hover / :focus | Mouse over / keyboard focus | a:hover |
| :nth-child(n) | nth child (1-indexed) | li:nth-child(odd) |
| :nth-of-type(n) | nth of its type | p:nth-of-type(2) |
| :first-child / :last-child | First/last child | li:last-child |
| :not(selector) | Doesn't match selector | input:not([type="hidden"]) |
| :has(selector) | Contains matching descendant | .card:has(img) |
| ::before / ::after | Generated content pseudo-elements | .btn::after |
| ::placeholder | Input placeholder text | input::placeholder |
| ::selection | User-selected text | ::selection |
- Style all external links (href starts with http) with an arrow indicator using
::after. - Use
:nth-childto create zebra-striped table rows without classes. - Use
:has()to style a.form-groupdifferently when its input is invalid. - Calculate specificity for 5 selectors of your choice — verify with browser DevTools.
Box Model & Display
CSSThe Box Model
Every element is a rectangular box composed of: content → padding → border → margin.
/* Always set this — sanest box model */ *, *::before, *::after { box-sizing: border-box; /* padding/border included in width */ } .box { width: 300px; height: 200px; padding: 20px 24px; /* top/bottom left/right */ border: 2px solid #333; margin: 16px auto; /* auto = center horizontally */ /* Border radius */ border-radius: 12px; border-radius: 50%; /* Full circle */ border-radius: 8px 0 8px 0; /* TL TR BR BL */ /* Outline — doesn't affect layout (good for focus) */ outline: 2px solid blue; outline-offset: 4px; /* Box shadow */ box-shadow: 0 4px 20px rgba(0,0,0,0.15); box-shadow: inset 0 2px 4px rgba(0,0,0,0.2); /* Inset */ }
Display Values
| Value | Behavior | Typical Use |
|---|---|---|
| block | Full width, new line before/after, respects all box model properties | div, p, h1–h6, section |
| inline | Flows with text, width/height ignored | span, a, em, strong |
| inline-block | Inline + respects width/height/padding | Buttons, badges |
| flex | Block-level flex container | Row/column layouts |
| inline-flex | Inline flex container | Inline button groups |
| grid | Block-level grid container | Page layouts |
| none | Removed from layout entirely | Hiding elements |
| contents | Element itself disappears, children remain | Semantic wrappers |
| table / table-cell | Behave like table elements | Rare edge cases |
Typography
CSSbody { font-family: 'Inter', system-ui, -apple-system, sans-serif; font-size: 16px; /* Browser default = 16px */ line-height: 1.6; /* Unitless — relative to font-size */ font-weight: 400; /* 100–900 */ color: #1a1a1a; } /* Type scale using rem */ h1 { font-size: 2.5rem; } /* 40px */ h2 { font-size: 2rem; } /* 32px */ h3 { font-size: 1.5rem; } /* 24px */ h4 { font-size: 1.25rem; } /* 20px */ /* Fluid typography with clamp() */ h1 { font-size: clamp(1.8rem, 4vw, 3.5rem); /* min ideal max */ } /* Text properties */ .text-styles { letter-spacing: 0.05em; word-spacing: 0.1em; text-transform: uppercase | lowercase | capitalize; text-decoration: underline | line-through | none; text-align: left | center | right | justify; text-indent: 2em; white-space: nowrap | pre | pre-wrap | pre-line; word-break: break-word | break-all; overflow-wrap: anywhere; hyphens: auto; } /* Truncate to one line */ .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Clamp to N lines */ .clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; } /* Variable fonts */ .variable-font { font-variation-settings: 'wght' 600, 'wdth' 75; }
- Build a typographic scale using CSS custom properties: --text-xs through --text-5xl.
- Implement fluid headings with
clamp()for all h1–h4. - Create a blog article layout with comfortable line-length (~65ch) and line-height.
- Style a card component with truncated title (1 line) and clamped description (3 lines).
Colors & Backgrounds
CSS/* All ways to express color */ .color-examples { color: red; /* Named */ color: #ff0000; /* Hex */ color: #f00; /* Hex shorthand */ color: rgb(255, 0, 0); /* RGB */ color: rgba(255, 0, 0, 0.5); /* RGBA with alpha */ color: rgb(255 0 0 / 50%); /* Modern RGB syntax */ color: hsl(0deg 100% 50%); /* HSL (hue saturation lightness) */ color: hsl(0deg 100% 50% / 0.7); /* HSL with alpha */ color: oklch(60% 0.2 30); /* Modern: perceptually uniform */ color: currentColor; /* Inherits from parent color */ color: transparent; } /* Backgrounds */ .bg-examples { background-color: #f5f5f5; /* Linear gradient */ background: linear-gradient(135deg, #667eea, #764ba2); /* Radial gradient */ background: radial-gradient(circle at 30% 50%, #4f9eff, #0a0d14); /* Conic gradient */ background: conic-gradient(from 0deg, red, yellow, green, red); /* Multiple backgrounds (first is on top) */ background: url(overlay.png) no-repeat center, linear-gradient(#000, #333); /* Image properties */ background-size: cover | contain | 300px | 50%; background-position: center | top right | 50% 50%; background-repeat: no-repeat | repeat-x | repeat-y; background-attachment: fixed | scroll | local; /* Parallax! */ background-clip: border-box | padding-box | text; }
Spacing & Sizing Units
CSS| Unit | Relative to | Best used for |
|---|---|---|
| px | Screen pixel | Borders, shadows, fine-tuned details |
| rem | Root font-size (16px) | Typography, consistent spacing |
| em | Current element font-size | Padding/margins that scale with text |
| % | Parent element | Fluid widths, responsive layouts |
| vw / vh | Viewport width/height | Full-screen sections, fluid type |
| vmin / vmax | Smaller/larger viewport dimension | Responsive icons, squares |
| dvh / svh / lvh | Dynamic/small/large viewport height | Mobile browser chrome fix |
| ch | Width of "0" character | Text column width (~65ch optimal) |
| fr | Fraction of free space (Grid only) | Grid column/row sizing |
| min-content | Smallest content can be | Grid/flex intrinsic sizing |
| max-content | Largest content naturally is | Grid/flex intrinsic sizing |
| fit-content | Shrinks but not below min-content | Buttons, inline blocks |
Logical Properties (Modern Approach)
.logical { /* Physical → Logical */ margin-top → margin-block-start; margin-bottom → margin-block-end; margin-left → margin-inline-start; margin-right → margin-inline-end; /* Shorthand */ margin-block: 16px; /* top + bottom */ margin-inline: 24px; /* left + right */ width → inline-size; height → block-size; }
Flexbox
CSSFlexbox is a one-dimensional layout system. Use it for rows or columns, navigation bars, button groups, centering, and card rows.
/* ─── CONTAINER ─── */ .flex-container { display: flex; flex-direction: row | row-reverse | column | column-reverse; flex-wrap: nowrap | wrap | wrap-reverse; flex-flow: row wrap; /* Shorthand */ gap: 16px; /* Space between items */ column-gap: 20px; row-gap: 12px; /* Alignment on main axis (row = horizontal) */ justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly; /* Alignment on cross axis (row = vertical) */ align-items: stretch | flex-start | flex-end | center | baseline; /* Multi-line cross-axis alignment */ align-content: flex-start | flex-end | center | space-between | space-around | stretch; } /* ─── ITEMS ─── */ .flex-item { flex-grow: 1; /* Grow to fill space (0 = don't grow) */ flex-shrink: 0; /* Don't shrink below basis (1 = shrink) */ flex-basis: 200px; /* Starting size before grow/shrink */ flex: 1 1 auto; /* Shorthand: grow shrink basis */ flex: 1; /* = 1 1 0 */ flex: auto; /* = 1 1 auto */ flex: none; /* = 0 0 auto (rigid) */ order: 2; /* Reorder visually (default 0) */ align-self: center; /* Override container align-items */ } /* ─── COMMON PATTERNS ─── */ /* Perfect centering */ .center { display: flex; place-items: center; } /* Push last item to end */ .nav { display: flex; } .nav .logo { margin-inline-end: auto; } /* Equal-width columns */ .cols > * { flex: 1; }
- Build a navbar: logo on left, nav links in center, CTA button on right — using only flexbox.
- Create a card grid where cards are equal height regardless of content length.
- Build a sidebar + main content layout using flexbox (sidebar fixed width, content grows).
- Create a "holy grail" layout: header, footer, left sidebar, right sidebar, main content — pure flexbox.
CSS Grid
CSSGrid is two-dimensional. Use it for page-level layouts, dashboard grids, magazine-style designs, and any time you need both rows AND columns simultaneously.
/* ─── CONTAINER ─── */ .grid { display: grid; /* Explicit columns */ grid-template-columns: 200px 1fr 2fr; grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); /* Explicit rows */ grid-template-rows: auto 1fr auto; /* Named areas */ grid-template-areas: "header header header" "sidebar main aside" "footer footer footer"; gap: 20px 16px; /* row-gap column-gap */ /* Implicit rows (auto-generated) */ grid-auto-rows: minmax(100px, auto); grid-auto-columns: 200px; grid-auto-flow: row | column | dense; /* Alignment */ justify-items: start | end | center | stretch; align-items: start | end | center | stretch; place-items: center; /* Shorthand for both */ justify-content: start | end | center | space-between | space-around; align-content: start | end | center | space-between; } /* ─── ITEMS ─── */ .header { grid-area: header; } .sidebar { grid-area: sidebar; } .main { grid-area: main; } /* Manual placement */ .feature { grid-column: 1 / 3; /* Start line / end line */ grid-column: 1 / -1; /* Span full width */ grid-column: span 2; /* Span 2 columns */ grid-row: 1 / 3; justify-self: center; align-self: end; }
auto-fill vs auto-fit
- Build a magazine-style layout: large featured article spanning 2 columns, 3 smaller articles below, sidebar on right — using named grid areas.
- Create a responsive image gallery using
auto-fit+minmax(). Images should reflow automatically at any screen width. - Build a Kanban board (3 columns: Todo, In Progress, Done) with CSS Grid. Each column is a grid with
grid-auto-rows. - Use
grid-auto-flow: denseto fill gaps in an irregular card grid.
Positioning
CSS/* static — default, flows normally */ .static { position: static; } /* relative — offset FROM its natural position, creates stacking context */ .relative { position: relative; top: 10px; left: 20px; } /* absolute — removed from flow, positioned relative to nearest positioned ancestor */ .absolute { position: absolute; top: 0; right: 0; inset: 0; /* Shorthand: top right bottom left */ } /* fixed — relative to viewport, stays during scroll */ .fixed-header { position: fixed; top: 0; left: 0; right: 0; z-index: 1000; } /* sticky — scrolls with page until threshold, then sticks */ .sticky-nav { position: sticky; top: 0; /* Required! */ z-index: 100; } /* z-index — controls stacking order within same stacking context */ .modal-overlay { z-index: 1000; } .modal { z-index: 1001; } .tooltip { z-index: 2000; }
opacity < 1, transform, filter, will-change, isolation: isolate all create new stacking contexts. This is why your z-index sometimes "doesn't work" — the element is in a different context.
Responsive Design
CSSMedia Queries
/* Mobile-first approach — base styles, then larger screens */ .container { width: 100%; padding: 0 16px; } @media (min-width: 640px) { /* sm */ } @media (min-width: 768px) { /* md */ } @media (min-width: 1024px) { /* lg */ } @media (min-width: 1280px) { /* xl */ } @media (min-width: 1536px) { /* 2xl */ } /* Feature queries */ @supports (display: grid) { .container { display: grid; } } /* User preferences */ @media (prefers-color-scheme: dark) { :root { --bg: #0a0a0a; --text: #fff; } } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; } } @media (prefers-contrast: high) { :root { --border: #fff; } } /* Container queries (game changer!) */ .card-wrapper { container-type: inline-size; container-name: card; } @container card (min-width: 400px) { .card { flex-direction: row; } }
- Build a product grid that shows 1 column on mobile, 2 on tablet, 4 on desktop — mobile-first.
- Implement a hamburger nav that collapses below 768px using only CSS (checkbox hack or :has()).
- Add a
prefers-color-schemedark mode implementation using CSS custom properties. - Use container queries to make a card component adapt based on its parent width, not viewport.
CSS Variables & Cascade
CSS/* Define on :root for global access */ :root { /* Color system */ --color-primary: oklch(65% 0.18 250); --color-primary-10: oklch(65% 0.18 250 / 10%); /* Space scale */ --space-1: 4px; --space-2: 8px; --space-4: 16px; --space-8: 32px; /* Animation */ --ease-out: cubic-bezier(0, 0, 0.2, 1); --duration-fast: 150ms; --duration-normal: 300ms; } /* Use a variable */ .btn { background: var(--color-primary); padding: var(--space-2) var(--space-4); /* Fallback value */ color: var(--text-color, white); } /* Scoped variables (override per component) */ .theme-dark { --color-primary: oklch(70% 0.2 250); } /* Computed with calc() */ .responsive-pad { --base: 16px; padding: calc(var(--base) * 2); } /* CSS Layers — explicit cascade control */ @layer reset, base, components, utilities; @layer reset { * { margin: 0; padding: 0; } } @layer components { .btn { padding: 8px 16px; } } @layer utilities { .mt-4 { margin-top: 16px !important; } /* OK in utilities layer */ }
Transforms & Transitions
CSS/* 2D Transforms */ .transform-2d { transform: translateX(50px); transform: translateY(-20%); transform: translate(50px, 20px); transform: scale(1.5); transform: scaleX(0.5); transform: rotate(45deg); transform: skew(10deg, 5deg); /* Chain multiple transforms */ transform: rotate(45deg) scale(1.2) translateX(10px); /* Transform origin */ transform-origin: top left | center | 50% 50%; } /* 3D Transforms */ .parent-3d { perspective: 1000px; } /* Required on parent */ .card-3d { transform-style: preserve-3d; transform: rotateY(30deg) rotateX(15deg); backface-visibility: hidden; /* For flip animations */ } /* Individual transform properties (modern — compositable!) */ .compositable { translate: 50px 20px; rotate: 45deg; scale: 1.5; } /* Transitions */ .smooth { transition: all 300ms ease; /* Avoid "all" in production */ transition: transform 250ms cubic-bezier(0.34, 1.56, 0.64, 1), /* Spring */ opacity 200ms ease, background-color 150ms ease; transition-delay: 100ms; } .smooth:hover { transform: translateY(-4px) scale(1.02); } /* Only animate compositor-friendly properties for 60fps */ /* ✅ opacity, transform, filter (GPU-accelerated) */ /* ❌ width, height, margin, top, left (causes layout reflow) */
Animations & Keyframes
CSS/* Define keyframes */ @keyframes fadeSlideIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } } @keyframes spin { to { transform: rotate(360deg); } } /* Apply animation */ .animated { animation-name: fadeSlideIn; animation-duration: 400ms; animation-timing-function: ease-out; animation-delay: 100ms; animation-iteration-count: 1 | infinite; animation-direction: normal | reverse | alternate | alternate-reverse; animation-fill-mode: both; /* Retain final state */ animation-play-state: running | paused; /* Shorthand */ animation: fadeSlideIn 400ms ease-out 100ms both; } /* Staggered animations with delay */ .list-item:nth-child(1) { animation-delay: 0ms; } .list-item:nth-child(2) { animation-delay: 80ms; } .list-item:nth-child(3) { animation-delay: 160ms; } /* View Transitions API (native page transitions!) */ @view-transition { navigation: auto; } ::view-transition-old(root) { animation: slideOut 300ms ease; } ::view-transition-new(root) { animation: slideIn 300ms ease; }
- Create a loading spinner using
@keyframesandborder+rotate. - Build a skeleton loading screen that pulses — used for content loading states.
- Animate a card list so items stagger in on page load (delay each by 80ms).
- Build a CSS-only modal with a fade + scale animation on open/close.
- Wrap all animations in
@media (prefers-reduced-motion: no-preference).
Pseudo-classes & Pseudo-elements
CSS| Pseudo-class | When it applies |
|---|---|
| :hover | Mouse is over the element |
| :focus | Element has keyboard/programmatic focus |
| :focus-visible | Focus from keyboard only (not mouse click) |
| :focus-within | Element OR any descendant is focused |
| :active | Being clicked/pressed |
| :visited | Link has been visited (limited styling) |
| :checked | Checkbox/radio is selected |
| :disabled / :enabled | Form element is disabled/enabled |
| :required / :optional | Form input has/lacks required attribute |
| :valid / :invalid | Input passes/fails constraint validation |
| :placeholder-shown | Placeholder is visible (input is empty) |
| :empty | Element has no children |
| :root | Top-level element (html) |
| :target | Element whose id matches URL hash |
| :is() | Matches any of its arguments |
| :where() | Same as :is() but zero specificity |
| :has() | "Parent" selector — has matching descendant |
| :not() | Doesn't match argument |
| :any-link | Any anchor with href |
/* ::before and ::after — generated content */ .icon-link::after { content: " ↗"; /* Required (even empty string "") */ display: inline-block; } /* Decorative element */ .card::before { content: ""; position: absolute; inset: -2px; background: linear-gradient(#4f9eff, #7c5cfc); border-radius: inherit; z-index: -1; /* Gradient border trick */ } ::placeholder { color: #666; font-style: italic; } ::selection { background: #4f9eff; color: #fff; } ::first-line { font-size: 1.1em; font-weight: bold; } ::first-letter { font-size: 3em; float: left; } /* Drop cap */ ::marker { color: #4f9eff; } /* List bullet */ ::backdrop { background: rgba(0,0,0,0.5); } /* <dialog> backdrop */
Modern CSS Features
CSS 2024–25/* ─── CSS NESTING (native) ─── */ .card { background: var(--surface); & .title { font-size: 1.2rem; } /* .card .title */ &:hover { border-color: blue; } /* .card:hover */ @media (min-width: 768px) { /* Nested media query */ display: flex; } } /* ─── @scope ─── */ @scope (.card) to (.card .inner) { p { color: red; } /* Only p within .card but outside .inner */ } /* ─── SCROLL-DRIVEN ANIMATIONS ─── */ .progress-bar { animation: grow linear; animation-timeline: scroll(); /* Driven by scroll position */ animation-range: entry 0% cover 100%; } @keyframes grow { from { transform: scaleX(0); } to { transform: scaleX(1); } } /* ─── ANCHOR POSITIONING (popups, tooltips) ─── */ .anchor { anchor-name: --btn; } .tooltip { position: absolute; position-anchor: --btn; top: anchor(bottom); left: anchor(center); } /* ─── color-mix() ─── */ .tinted { background: color-mix(in oklch, blue 30%, white); } /* ─── math functions ─── */ .math { width: min(100%, 600px); height: max(200px, 50vh); font-size: clamp(1rem, 2.5vw, 2rem); width: round(nearest, 333px, 50px); /* 350px */ } /* ─── @starting-style (enter animations!) ─── */ .popover { transition: opacity 300ms, transform 300ms; @starting-style { opacity: 0; transform: translateY(-8px); } }
- Refactor a stylesheet from SASS nesting to native CSS nesting — no preprocessor.
- Build a reading progress bar that fills purely with scroll-driven animations.
- Use
color-mix()to auto-generate lighter/darker variants of a brand color. - Implement a dark mode using
light-dark()function andcolor-schemeproperty.
Accessibility (a11y)
CriticalARIA — Accessible Rich Internet Applications
<!-- Labels --> <button aria-label="Close dialog">✕</button> <div aria-labelledby="dialog-title">...</div> <input aria-describedby="hint-text"> <!-- States --> <button aria-expanded="false" aria-controls="menu">Menu</button> <div id="menu" aria-hidden="true">...</div> <input aria-invalid="true" aria-errormessage="email-error"> <div role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div> <!-- Live regions — announce dynamic changes --> <div aria-live="polite" aria-atomic="true"> Status messages go here </div> <div role="alert">Urgent: Your session is expiring.</div> <!-- Skip navigation link --> <a href="#main" class="skip-link">Skip to main content</a>
/* Visually hidden but screen-reader accessible */ .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; } /* Focus styles — NEVER remove, only restyle */ :focus-visible { outline: 3px solid #4f9eff; outline-offset: 3px; border-radius: 4px; } /* Skip link */ .skip-link { position: absolute; transform: translateY(-200%); z-index: 9999; } .skip-link:focus { transform: translateY(0); }
WCAG 2.1 Checklist
| Criterion | Requirement |
|---|---|
| Color contrast | 4.5:1 for normal text, 3:1 for large text (AA level) |
| Keyboard nav | All interactive elements focusable, logical tab order |
| Focus visible | Clear focus indicator on all interactive elements |
| Alt text | All meaningful images have descriptive alt attributes |
| Heading hierarchy | Logical h1→h6 order, no skipping levels |
| Form labels | Every input has associated label |
| Error messages | Clear error messages linked to inputs |
| Touch targets | Min 44×44px touch target size |
| Resize text | No loss of content when text zoomed to 200% |
| Language | lang attribute on <html> |
Performance
Production<!-- Preload critical assets --> <link rel="preload" as="font" href="font.woff2" crossorigin> <link rel="preload" as="image" href="hero.webp"> <link rel="modulepreload" href="app.js"> /* Optimize long lists and pages */ .post { content-visibility: auto; contain-intrinsic-size: 0 300px; /* Hint for scroll bar sizing */ } /* GPU compositing for animated elements */ .animated-el { will-change: transform; contain: layout paint; /* CSS containment */ } /* Font performance */ @font-face { font-family: 'Brand'; src: url(brand.woff2) format('woff2'); font-display: swap; /* Show fallback, swap when loaded */ unicode-range: U+0000-00FF; /* Subset to Latin */ }
CSS Architecture
ScalabilityMethodologies Comparison
| Methodology | Idea | Best for |
|---|---|---|
| BEM | Block__Element--Modifier naming. .card__title--large | Teams, component libraries |
| SMACSS | Categorize: Base, Layout, Module, State, Theme | Large apps |
| ITCSS | Inverted Triangle: Settings → Tools → Generic → Elements → Objects → Components → Trumps | Design systems |
| Utility-first | One class = one property. Tailwind CSS approach. | Rapid prototyping |
| CSS Modules | Scoped class names, colocation with component files | React/Vue apps |
Design Token System
/* 3 tiers: Primitive → Semantic → Component */ /* Tier 1: Raw values */ :root { --blue-500: #3b82f6; --blue-600: #2563eb; --space-4: 16px; } /* Tier 2: Semantic meaning */ :root { --color-action: var(--blue-500); --color-action-hv: var(--blue-600); --space-component: var(--space-4); } /* Tier 3: Component-specific */ .btn { --btn-bg: var(--color-action); --btn-bg-hv: var(--color-action-hv); --btn-padding: var(--space-component); background: var(--btn-bg); padding: calc(var(--btn-padding) / 2) var(--btn-padding); } /* Override just the component token for variants */ .btn-danger { --btn-bg: var(--red-500); }
- Build a complete design token system for a SaaS app: colors (primitive + semantic), spacing scale, type scale, border-radius, shadow levels.
- Create a button component with 4 variants (primary, secondary, ghost, danger) and 3 sizes using only CSS custom properties — no modifier classes that duplicate rules.
- Structure a stylesheet using ITCSS — 7 layers, at least 2 files per layer concept.
- Implement a theme switcher (light/dark/high-contrast) using CSS layers and custom properties only, no JS class toggling.
Final Projects
Portfolio QualityBuild these in order. Each project combines multiple concepts and is production-portfolio worthy. Time estimates assume a solid understanding of the sections above.
- Build a full personal portfolio site: hero section, about, skills grid, projects, contact form.
- Semantic HTML throughout — passes Lighthouse accessibility 90+.
- Fully responsive from 320px to 2560px using mobile-first media queries.
- Smooth scroll with
scroll-behavior. Sticky header with blur backdrop-filter. - Custom
::selectioncolor and styled scrollbar. - All animations respect
prefers-reduced-motion. - Dark/light mode toggle using CSS custom properties + localStorage.
- Create an article page with a proper typographic hierarchy: drop cap, pull quotes, code blocks, figure captions.
- Related posts grid: auto-fill + minmax, each card has hover lift animation.
- Sidebar with sticky positioning that stays visible while scrolling article.
- Reading progress bar using scroll-driven animations or JS + CSS variables.
- Newsletter signup form with custom validation styles (
:valid/:invalid).
- Hero section: gradient background mesh, animated CTA button, floating badges with keyframes.
- Features grid: 3-column on desktop, 2 on tablet, 1 on mobile.
- Pricing cards: CSS Grid +
:has()to highlight selected plan. - Testimonial slider: CSS-only using
scroll-snapandoverscroll-behavior. - FAQ section with native
<details>/<summary>+ custom animated arrow. - Performance: Critical CSS inline, image lazy loading, font-display swap, LCP <2.5s.
- Collapsible sidebar + main layout using CSS Grid. Sidebar toggles with a CSS variable
--sidebar-width. - Stats cards with animated counters (CSS only using
@propertyandcounter()trick). - Data table with sticky header, zebra rows, sortable column indicator styling.
- Notification dropdown using
:popoverAPI (popover attribute + CSS::backdrop). - Full keyboard navigation — every interactive element reachable and clear focus styling.
- Container queries on cards: compact when sidebar open, expanded when closed.
- Product image gallery with thumbnail row and main image — CSS Grid. Zoom on hover with transform + overflow hidden.
- Color/size selectors: radio inputs completely restyled with CSS — no JS, full accessibility.
- Quantity stepper: custom styled number input with +/– buttons.
- Product reviews: star rating system built purely with CSS (reversed flex and :checked).
- Sticky "Add to Cart" bar that appears on scroll using
position: sticky+:has(). - Responsive: product image above description on mobile, side-by-side on desktop.
- Build a loading screen: animated logo using clip-path and SVG stroke-dashoffset.
- CSS-only card flip animation (3D transform, backface-visibility).
- Neon glow button using box-shadow layers and CSS animation.
- Animated gradient text using background-clip: text and keyframe hue-rotate.
- Pure CSS progress stepper with connecting lines using ::before pseudo-elements.
- Page transition system using View Transitions API.
- Create a complete component library: buttons (variants + sizes), badges, alerts, cards, modals, dropdowns, tabs, toasts, accordions, tooltips, progress bars, spinners.
- All components built with 3-tier token system. No hardcoded values.
- Full light and dark theme. Each component respects
prefers-color-scheme. - Comprehensive keyboard navigation on all interactive components.
- All components meet WCAG 2.1 AA — verified with axe DevTools.
- Build an HTML living style guide that documents every component with code examples.
- Choose a real-world website (Stripe, Linear, Vercel, Notion) and rebuild its homepage from scratch.
- Modern HTML: semantic structure, Open Graph, schema.org JSON-LD markup.
- Improve on the original: better accessibility score, reduced motion support, container queries.
- Target Core Web Vitals: LCP <2.5s, CLS <0.1, FID <100ms. Verify with Lighthouse.
- Write a 500-word post-mortem: what CSS decisions you made and why.