Note Use defer for classic scripts so they run after HTML parsing completes. Module scripts are deferred by default. Avoid placing scripts in the head without defer or async.
<h1>Annual Report</h1>
<h2>Financial Summary</h2>
<h3>Revenue by Region</h3>
Note Use only one h1 per page for best SEO. Never skip heading levels (e.g., jumping from h1 to h4). Headings create a document outline used by assistive technology.
headingtitleh1h2section heading
Paragraphs
syntax
<p>Text content here.</p>
example
<p>Our platform processes over two million transactions daily.</p>
<p>Each transaction is encrypted end-to-end for security.</p>
Note Browsers add default top and bottom margins to paragraphs. Reset or adjust with CSS if needed.
Note A span has no semantic meaning. Use it purely for styling a portion of text when no better semantic element exists.
inline stylespanhighlight textwrap text
Strong & Emphasis
syntax
<strong>important</strong>
<em>emphasized</em>
example
<p><strong>Warning:</strong> This action <em>cannot</em> be undone.</p>
Note strong conveys urgency or importance (renders bold). em conveys stress emphasis (renders italic). Prefer these over <b> and <i> for meaningful emphasis, since screen readers alter vocal tone for strong/em.
Note pre preserves all whitespace and line breaks exactly as written. Wrap code inside pre for multi-line blocks. Use code alone for inline code snippets.
<p>123 Main Street<br>Suite 400<br>Springfield, IL 62704</p>
<hr>
<p>New section begins here.</p>
Note br is for meaningful line breaks like addresses or poetry, not for spacing. Use CSS margins or padding for spacing. hr represents a thematic shift between content blocks.
<p>Price: <del>$49.99</del> <ins>$29.99</ins></p>
<p>Search results for <mark>flexbox</mark></p>
<small>Terms and conditions apply.</small>
Note del and ins are ideal for showing edits or price changes. mark highlights search matches or key phrases. small is for side comments and legal text.
Note Use nav for major navigation blocks, not every group of links. If multiple nav elements exist on a page, give each a unique aria-label to distinguish them for assistive tech.
Note Use url-encoded characters in mailto query strings for subject and body. Phone numbers should use the international E.164 format with the + prefix.
Note Common rel values: nofollow (tells search engines not to follow), noopener (security for new tabs), preconnect (early connection to external origins), canonical (preferred URL).
rel attributenofollowpreconnectlink relationshipseo link
<figure>
<img src="/charts/revenue.png" alt="Bar chart showing 40% revenue growth year over year">
<figcaption>Revenue growth from2023 to 2025</figcaption>
</figure>
Note figure is for self-contained content that could be moved to an appendix without losing meaning. The figcaption provides a visible caption, while alt describes the image content itself.
Note The browser picks the first matching source. Always include the img fallback as the last child. Use picture for art direction (different crops at different sizes) or serving modern formats with fallbacks.
Note The w descriptor tells the browser the intrinsic pixel width of each image. sizes tells it how wide the image will display at each breakpoint, so it can pick the best file. This is for resolution switching, not art direction.
<img src="/gallery/photo-42.jpg" alt="Sunset over the canyon" loading="lazy" width="600" height="400">
Note loading="lazy" defers loading until the image nears the viewport. Do not lazy-load images that are visible on initial load (above the fold) since it slows their appearance. Use loading="eager" (the default) for hero images.
<video controls width="720" height="405" poster="/thumbs/demo.jpg">
<source src="/videos/demo.webm"type="video/webm">
<source src="/videos/demo.mp4"type="video/mp4">
Your browser does not support video playback.
</video>
Note Provide multiple source formats for compatibility. The poster attribute shows a thumbnail before playback. Avoid autoplay with sound since browsers block it and users dislike it.
embed videovideo playervideo tagplay video
Audio
syntax
<audio src="url" controls></audio>
example
<audio controls>
<source src="/audio/podcast-ep12.ogg"type="audio/ogg">
<source src="/audio/podcast-ep12.mp3"type="audio/mpeg">
Audio playback is not supported in your browser.
</audio>
Note Like video, provide multiple source formats. The controls attribute gives users play, pause, and volume UI. Without controls, the element is invisible.
embed audioaudio playerplay soundmusic playerpodcast player
Decorative Images (Empty Alt)
syntax
<img src="url" alt="" role="presentation">
example
<img src="/images/decorative-divider.svg" alt="">
Note For purely decorative images that add no information, use an empty alt attribute. Screen readers will skip them entirely. Never omit the alt attribute since that causes readers to announce the file name.
<ol>
<li>Preheat oven to 375 degrees</li>
<li>Mix dry ingredients in a large bowl</li>
<li>Add wet ingredients and stir until smooth</li>
<li>Bake for25 minutes</li>
</ol>
Note Use start to begin numbering at a specific value, and reversed attribute for countdown order. The type attribute changes markers (1, a, A, i, I).
Note The nested list must be placed inside the parent li element, not after it. You can nest ul inside ol and vice versa.
nested listsub listindented listlist inside list
Definition List
syntax
<dl>
<dt>Term</dt>
<dd>Definition</dd>
</dl>
example
<dl>
<dt>Latency</dt>
<dd>The time delay between a request and its response.</dd>
<dt>Throughput</dt>
<dd>The amount of data processed in a given time period.</dd>
</dl>
Note Ideal for glossaries, metadata key-value pairs, and FAQ sections. A single dt can have multiple dd elements for multiple definitions.
definition listglossarykey value listdl dt ddterm definition
Note Always use thead/tbody for proper structure. Use th for header cells and td for data cells. This helps screen readers navigate the table correctly.
create tablehtml tabledata tabletable rows
Colspan & Rowspan
syntax
<td colspan="n">Spans n columns</td>
<td rowspan="n">Spans n rows</td>
Note The caption element provides an accessible name for the table. It must be the first child of the table element. tfoot contains summary rows like totals.
Note GET appends data to the URL (visible, cacheable, bookmarkable). POST sends data in the request body (for sensitive data and large payloads). Omitting method defaults to GET.
Note Different type values trigger different mobile keyboards and built-in validation. For example, type="email" shows an @ key on mobile and validates email format.
text inputinput fieldtext boxemail inputpassword field
Note Number inputs show spinners on desktop and numeric keyboards on mobile. The step attribute controls increment size. Use step="any" for decimal values.
number inputsliderrange inputquantity fieldnumeric input
Note Date picker appearance varies significantly across browsers and platforms. The value format is always ISO 8601 (YYYY-MM-DD) regardless of display format. Use min and max to constrain the selectable range.
date pickerdate inputtime inputdatetimecalendar input
Note Radio buttons with the same name attribute form an exclusive group where only one can be selected. Checkboxes allow multiple selections. Wrap each in a label for a clickable hit area.
Note Use optgroup to categorize options. Add an empty first option as a placeholder. For multi-selection, add the multiple attribute, but consider checkboxes instead since multi-select is not intuitive for many users.
Note Unlike input, the textarea value goes between the opening and closing tags, not in a value attribute. Use the CSS resize property to control whether users can resize it.
textareamultiline inputtext areacomment boxmessage field
<label for="fullname">Full Name</label>
<input type="text" id="fullname" name="fullname">
<!-- Or wrapping approach -->
<label>
Phone Number
<input type="tel" name="phone">
</label>
Note Every form input must have a label for accessibility. The for attribute must match the input's id. Alternatively, wrap the input inside the label element to create an implicit association.
Note Unlike select, datalist allows free-text entry in addition to the suggestions. The user is not forced to pick from the list. Browser rendering of suggestions varies.
Note Built-in validation runs on form submission and is bypassed by adding formnovalidate to the submit button or novalidate to the form. The title attribute provides a hint message shown when the pattern fails.
form validationrequired fieldpattern validationinput validationmin max
Note header and footer can be used for the entire page or within an article/section element. A page can have multiple headers and footers in different contexts.
Note There must be only one visible main element per page. It should not be nested inside header, footer, nav, article, or aside. Skip-navigation links typically target main.
main contentprimary contentmain elementpage content
Note An article is a self-contained piece of content that could be independently distributed (blog post, comment, product card). A section is a thematic grouping of content. Both should generally include a heading.
Note aside represents content tangentially related to its parent. When used at the page level it acts as a sidebar. Inside an article, it represents a pullquote or supplementary info.
<details>
<summary>How do I reset my password?</summary>
<p>Go to the login page and click "Forgot Password". Enter your email address and we will send you a reset link within 5 minutes.</p>
</details>
<details open>
<summary>System Requirements</summary>
<ul>
<li>64-bit operating system</li>
<li>4 GB RAM minimum</li>
</ul>
</details>
Note This creates a native collapsible section with no JavaScript needed. The open attribute shows the content expanded by default. Style the summary's marker with ::marker or list-style.
<dialog id="confirmDialog">
<h2>Confirm Deletion</h2>
<p>This will permanently remove the item. Continue?</p>
<form method="dialog">
<button value="cancel">Cancel</button>
<button value="confirm">Delete</button>
</form>
</dialog>
<!-- Open with: document.getElementById('confirmDialog').showModal() -->
Note Use showModal() to open with a backdrop that traps focus (accessible). Use show() for a non-modal popup. The form method="dialog" approach closes the dialog and sets its returnValue to the button's value.
Note Content inside template is not rendered, not visible, and not queried by selectors. It serves as a blueprint for JavaScript-generated elements. Clone its content with cloneNode(true).
templatereusable htmlclone elementhtml template
<time> Machine-Readable Dates
syntax
<time datetime="YYYY-MM-DD">display text</time>
example
<p>Published on <time datetime="2026-03-15">March 15, 2026</time></p>
<p>Event starts at <time datetime="2026-04-10T09:00">9:00 AM, April 10</time></p>
Note The datetime attribute provides a machine-readable format for search engines and tools, while the visible text can use any human-friendly format.
date elementtime elementdatetimemachine readable date
Note The title appears in browser tabs, bookmarks, and search engine results. Keep it under 60 characters. Place the specific page name before the site name for better scannability.
page titletitle tagtab titleseo title
Meta Description
syntax
<meta name="description" content="...">
example
<meta name="description" content="Compare our Starter, Pro, and Enterprise plans. Start free and scale as your team grows.">
Note Search engines display this as the page snippet. Keep it between 120-160 characters. Each page should have a unique description that summarizes its specific content.
meta descriptionseo descriptionsearch snippetpage description
Note Open Graph controls how your page appears when shared on social platforms. The og:image should be at least 1200x630 pixels. Test with platform-specific debugging tools after deploying.
social sharingopen graphog tagsshare previewsocial media card
Note Use canonical when the same content is accessible at multiple URLs (with/without www, query parameters, etc.). It tells search engines which URL to index and rank.
<meta name="robots" content="noindex, nofollow">
<!-- Use on staging, admin, orprivate pages -->
<meta name="robots" content="index, follow">
<!-- Default behavior, but explicit is fine -->
Note noindex prevents a page from appearing in search results. nofollow tells crawlers not to follow links on the page. For specific bots, use their name instead of robots (e.g., googlebot).
robots metanoindexnofollowhide from searchcrawl control
Note Modern browsers support SVG favicons which scale perfectly. Include the .ico fallback for older browsers. apple-touch-icon is used when users add your site to their iOS home screen.
Note JSON-LD structured data helps search engines understand your content and may trigger rich results (star ratings, recipe cards, event details). Place it in the head or body. Validate with search engine testing tools.
Note Prefer classes over IDs for styling since IDs have much higher specificity and cannot be reused. IDs are fine for JavaScript hooks and anchor targets.
css selectorclass selectorid selectorelement selectorselect element
Attribute Selectors
syntax
[attr] /* has attribute */
[attr="value"] /* exact match */
[attr^="prefix"] /* starts with */
[attr$="suffix"] /* ends with */
[attr*="part"] /* contains */
Note Use :focus-visible instead of :focus for keyboard-only focus rings. It avoids showing outlines on mouse clicks while keeping them for keyboard navigation.
Note Pseudo-elements use double colons (::) by convention. ::before and ::after require the content property. They are not in the DOM so they cannot be selected by users or read reliably by all screen readers.
before afterpseudo elementadd contentfirst lettertext selection styleplaceholder style
Combinators
syntax
A B /* descendant */
A > B /* direct child */
A + B /* adjacent sibling */
A ~ B /* general sibling */
example
/* All paragraphs inside .content */
.content p {
margin-bottom: 1em;
}
/* Only direct children */
.nav > li {
display: inline-block;
}
/* Paragraph right after an h2 */
h2 + p {
font-size: 1.125em;
}
/* All paragraphs after an h2 */
h2 ~ p {
color: #374151;
}
Note The descendant selector (space) matches at any depth. The child selector (>) matches only direct children. Adjacent (+) matches only the immediately following sibling.
/* Style a card only if it contains an image */
.card:has(img) {
padding: 0;
}
/* Style a form groupwith an invalid input */
.form-group:has(input:invalid) {
border-left: 3px solid #ef4444;
}
/* Style a heading followed by a subtitle */
h2:has(+ .subtitle) {
margin-bottom: 4px;
}
Note :has() is often called the parent selector. It selects an element based on whether it contains or is followed by a matching element. Fully supported in modern browsers as of 2024.
has selectorparent selectorselect parentconditional styleif contains
:is(), :where(), :not()
syntax
:is(selector-list) { } /* takes highest specificity in list */
:where(selector-list) { } /* zero specificity */
:not(selector) { }
example
/* Apply to h1, h2, or h3 inside .article */
.article :is(h1, h2, h3) {
color: #1e293b;
}
/* Reset styles with zero specificity (easy to override) */
:where(.prose) p {
margin-bottom: 1em;
}
/* All inputs except submit buttons */
input:not([type="submit"]) {
border: 1px solid #d1d5db;
}
Note :is() and :where() take a selector list and simplify complex selectors. The key difference: :is() takes the specificity of its most specific argument, while :where() always has zero specificity. :not() can now accept complex selectors.
is selectorwhere selectornot selectorexclude selectorselector listzero specificity
Specificity Rules
syntax
/* Specificity: (ID, Class, Element) */
/* #nav .item a => (1, 1, 1) */
/* .menu a => (0, 1, 1) */
/* a => (0, 0, 1) */
Note When two rules conflict, the one with higher specificity wins. If equal, the last one in source order wins. Avoid !important except for utility classes. Use @layer to manage specificity across libraries.
*, *::before, *::after {
box-sizing: border-box;
}
/* With border-box: a 300px wide element stays 300px
even with padding and border added */
.card {
width: 300px;
padding: 20px;
border: 1px solid #e5e7eb;
/* Total width: still 300px */
}
Note The universal border-box reset is considered best practice. Without it, padding and borders are added on top of the width, making sizing unpredictable.
box sizingborder boxinclude padding in widthsizing model
Margin
syntax
margin: top right bottom left;
margin: vertical horizontal;
margin: all;
Note Vertical margins collapse: when two vertical margins touch, only the larger one applies (not their sum). Margins on flex and grid children do not collapse. Use margin: 0 auto on a block element with a set width to center it.
Note Unlike margins, padding never collapses. Padding is inside the element's border, so background colors and images extend into the padded area. Use padding-block and padding-inline for writing-mode-aware spacing.
Note Border styles include solid, dashed, dotted, double, groove, ridge, inset, outset, and none. Use border-radius: 50% on a square element to create a circle. Individual sides can be styled separately.
Note Avoid setting fixed heights on text containers since content length varies. Use min-height instead. The aspect-ratio property maintains proportions without needing both width and height.
widthheightmax widthmin heightelement sizeaspect ratio
Note overflow: auto only shows scrollbars when content actually overflows, while scroll always shows them. overflow: clip is like hidden but does not create a scroll container, preventing programmatic scrolling. Combine overflow: hidden with text-overflow: ellipsis for truncated text.
Note Unlike border, outline does not take up space in the layout and does not affect element sizing. It can overlap adjacent elements. outline-offset pushes the outline away from the element edge. Never remove focus outlines without providing an alternative indicator.
Note block takes full width, starts on a new line, accepts all box model properties. inline only takes content width, ignores vertical margin/padding. inline-block is inline but respects all box model properties. display: none removes the element entirely. For screen-reader-only content, use the visually-hidden pattern instead.
Note Setting display: flex turns direct children into flex items. The default direction is row (horizontal). Items shrink to fit by default but do not wrap.
Note justify-content distributes items along the main axis (horizontal in row, vertical in column). space-between puts the first and last items at the edges. space-evenly distributes equal space around every item including edges.
align-items: stretch | flex-start | center | flex-end | baseline;
example
/* Vertically center items in a row */
.toolbar {
display: flex;
align-items: center;
height: 64px;
}
/* Align text baselines across different font sizes */
.price-row {
display: flex;
align-items: baseline;
}
Note align-items controls alignment on the cross axis (vertical in row, horizontal in column). The default is stretch, which makes items fill the container height. Use baseline to align items by their text baseline regardless of size.
Note By default, flex items squeeze onto one line (nowrap). With wrap, items flow to the next line when they run out of space. This is essential for responsive layouts without media queries.
flex wrapwrap itemsmulti-line flexwrap to next line
Note gap creates space between flex items without adding margins to outer edges. It works in both flexbox and grid. This eliminates the need for margin hacks on the first or last child.
.sidebar {
flex: 00280px; /* fixed width, no grow or shrink */
}
.main-content {
flex: 1; /* grow to fill remaining space */
}
.equal-columns > * {
flex: 110%; /* equal width columns */
}
Note flex: 1 is shorthand for flex: 1 1 0%, meaning the item can grow and shrink and starts from zero base size. flex-basis sets the initial size before growing/shrinking. Using 0% basis makes items share space equally.
Note align-self overrides the container's align-items value for a single flex item. It applies on the cross axis. There is no justify-self in flexbox since the main axis is controlled by the container.
Note The default order is 0. Lower values appear first. This changes visual order only, not tab order or screen reader order, so use sparingly to avoid accessibility confusion.
/* Center a single element both horizontally and vertically */
.page-center {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* Shorter alternative using place properties */
.quick-center {
display: flex;
place-content: center;
place-items: center;
}
Note This three-line pattern is the simplest way to center anything vertically and horizontally. Add min-height: 100vh to center within the full viewport.
center divcenter elementvertical centerhorizontal centercenter anything
Flex Spacer Pattern (Push Items Apart)
syntax
margin-left: auto; /* or margin-right: auto */
example
/* Push the last item to the far right */
.navbar {
display: flex;
align-items: center;
gap: 16px;
}
.navbar .user-menu {
margin-left: auto;
}
Note Auto margins in flexbox consume all available space in that direction. This pushes elements apart without justify-content: space-between, which is useful when you need only one item pushed to the end.
push to rightauto marginflex spacerpush item endflex margin auto
Note display: grid turns direct children into grid items. Unlike flexbox, grid controls both columns and rows simultaneously, making it ideal for two-dimensional layouts.
Note The fr unit distributes remaining free space proportionally. 1fr 2fr 1fr means the middle column gets twice the space of the side columns. Fixed sizes (px, rem) are allocated first, then fr units share what is left.
Note repeat() avoids writing the same value many times. You can repeat patterns too: repeat(3, 1fr 2fr) produces six columns alternating between 1fr and 2fr.
/* Cards that auto-wrap, minimum 280px each */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
}
Note auto-fill creates as many tracks as fit, leaving empty tracks if there are fewer items. auto-fit collapses empty tracks, letting items stretch to fill the row. For most card grids, auto-fit is what you want.
auto fitauto fillresponsive gridauto columnsresponsive cardscard grid
Minmax Function
syntax
minmax(minimum, maximum)
example
.layout {
display: grid;
grid-template-columns: minmax(200px, 300px) 1fr minmax(200px, 300px);
}
/* Sidebar that shrinks on small screens */
.page {
grid-template-columns: minmax(150px, 250px) 1fr;
}
Note minmax() sets a size range for grid tracks. Common pattern: minmax(0, 1fr) prevents grid blowout when content is wider than the column. The default minimum for fr units is min-content, not 0.
Note Named areas provide a visual map of your layout right in the CSS. Use a period (.) for empty cells. Each area name must form a rectangle. Changing the template in a media query rearranges the entire layout.
Note Grid lines are numbered starting at 1. Negative numbers count from the end (-1 is the last line). span n is a shorthand that avoids hardcoding line numbers.
Note The gap property works identically in grid and flexbox. It replaces the older grid-gap property. Gap only creates space between items, never on the outer edges.
grid gapgrid spacingspace between grid itemsrow gapcolumn gap
Grid Alignment
syntax
justify-items: start | center | end | stretch;
align-items: start | center | end | stretch;
place-items: align justify;
example
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
place-items: center; /* center in both axes */
}
/* Individual item */
.special-item {
justify-self: end;
align-self: start;
}
Note In grid, justify controls the inline (horizontal) axis and align controls the block (vertical) axis. place-items is shorthand for both. Unlike flexbox, grid supports justify-self for individual items.
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3; /* participate in3 parent rows */
}
/* Now all card titles, bodies, and footers align across cards */
Note Subgrid lets a nested grid item inherit its parent's track sizing. This is essential for aligning content across sibling cards (like matching title heights). The child must span the relevant parent tracks.
subgridnested gridalign across cardsinherited trackscard alignment
body {
font-family: "Inter", "Segoe UI", system-ui, sans-serif;
}
code, pre {
font-family: "JetBrains Mono", "Fira Code", ui-monospace, monospace;
}
Note Always end the stack with a generic family (sans-serif, serif, monospace, cursive, system-ui). The system-ui keyword uses the operating system's default font. Quotes are required when font names contain spaces.
font familychange fontfont stacksystem fontmonospace font
Font Size
syntax
font-size: value; /* px, rem, em, %, clamp() */
example
html {
font-size: 16px; /* base for rem units */
}
body {
font-size: 1rem;
}
h1 {
font-size: clamp(1.75rem, 4vw, 3rem);
}
.small-text {
font-size: 0.875rem; /* 14px at 16px base */
}
Note Use rem for consistent sizing relative to the root. em is relative to the parent's font size which compounds in nested elements. clamp() creates fluid typography that scales between a minimum and maximum.
font sizetext sizerem vs emfluid typographyresponsive font
Font Weight
syntax
font-weight: 100-900 | normal | bold | lighter | bolder;
Note 100=Thin, 200=ExtraLight, 300=Light, 400=Normal, 500=Medium, 600=SemiBold, 700=Bold, 800=ExtraBold, 900=Black. The font file must include the requested weight or the browser will fake bold, which looks poor.
Note Use unitless numbers (like 1.6) rather than fixed units so the line height scales proportionally with font size. Body text typically reads best between 1.5 and 1.7. Headings look better tighter at 1.1 to 1.3.
line heightline spacingtext spacingleading
Text Align
syntax
text-align: left | center | right | justify | start | end;
Note Prefer start and end over left and right for internationalization support (RTL languages). Avoid text-align: justify for body text on the web since it creates uneven word spacing without hyphenation.
text aligncenter textright aligntext alignmentjustify text
Text Decoration
syntax
text-decoration: line style color thickness;
text-underline-offset: value;
Note Use text-underline-offset to move underlines away from the text baseline for better readability. text-decoration-skip-ink: auto (the default in most browsers) makes underlines skip descenders cleanly.
Note When using uppercase, add letter-spacing (0.04em to 0.1em) to improve readability. Keep actual content in normal case in the HTML since text-transform is purely visual and screen readers may spell out uppercase letters.
Note Use em units for letter-spacing so it scales with font size. Tight letter-spacing works well for large headings. Wide letter-spacing suits small uppercase labels.
letter spacingword spacingtrackingcharacter spacing
Word Break & Overflow Wrap
syntax
word-break: normal | break-all | keep-all;
overflow-wrap: normal | break-word | anywhere;
Note overflow-wrap: break-word only breaks long words that would overflow their container. word-break: break-all breaks between any characters, even mid-word. Use overflow-wrap for most cases and word-break: break-all only for data like hashes or URLs.
word breakbreak wordlong texttext overflowwrap text
Note text-wrap: balance distributes text evenly across lines, preventing headings with one orphaned word on the last line. text-wrap: pretty focuses on avoiding orphans in body text. balance has a limit of a few lines for performance reasons.
text wrap balanceeven text linesavoid orphansbalanced headingpretty text
Note Use font-display: swap to show fallback text while the font loads, preventing invisible text. WOFF2 offers the best compression. Preload critical fonts with <link rel="preload" as="font" crossorigin>.
web fontcustom fontfont faceload fontwoff2font display
Note Modern CSS uses space-separated values with a slash for alpha: rgb(255 0 0 / 0.5). The older comma syntax still works but is being phased out. oklch provides perceptually uniform colors, so adjusting lightness produces visually consistent results across hues.
Note currentColor refers to the element's computed color value. It keeps borders, SVG fills, shadows, and other properties in sync with the text color. Change color once and everything follows.
Note Gradients are background-image values, not colors, so they cannot be used with the color property. You can layer multiple gradients separated by commas. Conic gradients are great for pie-chart-like visuals.
Note background-size: cover fills the entire container (may crop). contain fits the whole image (may leave empty space). When using the background shorthand, the size must follow position with a slash separator.
Note opacity affects the entire element and all its children. For transparent backgrounds only, use rgba or hsla with alpha instead. An element with opacity less than 1 creates a new stacking context.
Note Custom properties cascade and inherit like any CSS property. Define theme tokens on :root for global access. They can be changed per element, making component theming straightforward. The fallback value in var() is used only if the variable is not defined.
Note color-mix() blends two colors in the specified color space. Use oklch for perceptually even mixing. This replaces the need for pre-computed hover shades. Specify percentages to control the blend ratio.
color mixdarken colorlighten colorblend colorshover color
Note Layer multiple shadows for realistic depth (soft large shadow + tight small shadow). Use box-shadow: 0 0 0 Npx color as a pseudo-border that does not affect layout. The inset keyword creates inner shadows.
box shadowdrop shadowcard shadowelevationinner shadowfocus ring shadow
Note position: relative keeps the element in the normal flow but enables offset with top/right/bottom/left. Its main use is establishing a positioning context for absolutely positioned children.
position relativeoffset elementpositioning contextnudge element
Position Absolute
syntax
position: absolute;
top | right | bottom | left: value;
Note Absolute positioning removes the element from the document flow and positions it relative to the nearest positioned ancestor (one with position: relative, absolute, fixed, or sticky). If none exists, it positions relative to the viewport.
position absoluteabsolute positioningplace elementtooltip positionoverlay element
Position Fixed
syntax
position: fixed;
top | right | bottom | left: value;
Note Fixed elements are positioned relative to the viewport and stay in place during scrolling. They are removed from the document flow. A transform, filter, or perspective on any ancestor breaks fixed positioning and makes it relative to that ancestor instead.
Note Sticky is a hybrid: it behaves as relative until the scroll position reaches the threshold (top/bottom), then it sticks like fixed. The element must have a scrollable ancestor and the parent must have enough height for it to work. overflow: hidden on an ancestor can prevent sticking.
stickysticky headerstick on scrollsticky elementposition sticky
Note z-index only works on positioned elements (relative, absolute, fixed, sticky) and flex/grid children. Elements with opacity < 1, transform, or filter create new stacking contexts. Use isolation: isolate to explicitly create one without side effects.
z-indexstacking orderlayer orderbring to frontoverlapstacking context
Float & Clear
syntax
float: left | right | none;
clear: left | right | both;
Note Floats were once used for page layouts but flexbox and grid have replaced that use case. Floats are still useful for wrapping text around images. Use the clearfix hack or display: flow-root on the parent to contain floated children.
floattext wrap imageclear floatclearfixfloat left right
Note For most cases, the grid place-items: center approach is the shortest and most versatile. Use margin auto for simple block-level horizontal centering. The absolute method works when you need to center within a positioned parent.
center divcenter elementhow to centercentering csshorizontal centervertical center
Inset Shorthand
syntax
inset: top right bottom left;
inset: all;
example
/* Fill entire parent */
.overlay {
position: absolute;
inset: 0;
background: rgb(000 / 0.5);
}
/* 20px from each edge */
.inset-box {
position: absolute;
inset: 20px;
}
Note inset is shorthand for top, right, bottom, and left. inset: 0 is equivalent to top: 0; right: 0; bottom: 0; left: 0. It follows the same clockwise shorthand pattern as margin and padding.
insetfill parentstretch to edgesposition shorthandoverlay
Note Mobile-first (min-width) is the recommended approach: start with small screens and add complexity at wider breakpoints. Common breakpoints: 640px (small), 768px (medium), 1024px (large), 1280px (extra large).
media queryresponsivebreakpointmobile firstscreen size
Note prefers-color-scheme detects dark/light mode system preference. prefers-reduced-motion is critical for accessibility. hover: hover avoids applying hover styles on touch devices where hover is awkward.
dark modereduced motionhover detectionuser preferencecolor schemeaccessibility media
Note Container queries respond to the size of a parent container rather than the viewport. This makes components truly self-contained. Set container-type on the parent to opt in. Use container-name when you need to target a specific ancestor.
Note clamp() eliminates the need for many media queries. It sets a preferred value that flexes between a minimum and maximum. The preferred value usually includes a viewport unit so it scales fluidly. Ideal for typography and spacing.
Note On mobile browsers, 100vh is taller than the visible area because it does not account for the URL bar. Use 100dvh (dynamic viewport height) which updates as the browser chrome appears and disappears. svh is the smallest possible viewport, lvh is the largest.
viewport heightvhvwdvhfull screenviewport units
Min & Max Functions
syntax
min(value1, value2, ...)
max(value1, value2, ...)
example
.container {
width: min(90%, 1200px);
/* same as: width: 90%; max-width: 1200px; */
}
.sidebar {
width: max(200px, 20%);
/* at least 200px, grows with container */
}
.padding-responsive {
padding: max(16px, 3vw);
}
Note min() picks the smallest value, acting like a max-width. max() picks the largest, acting like a min-width. You can mix units freely inside these functions. They often replace media queries for simple responsive adjustments.
min functionmax functionresponsive widthfluid layoutmin max css
Note Range syntax is more readable than the traditional min-width/max-width approach. It is supported in all modern browsers. You can use <, <=, >, and >= operators. This replaces awkward constructs like (max-width: 1023.98px).
media rangerange syntaxbetween breakpointsmodern media query
Note Container query units (cqi for inline, cqb for block) are relative to the container's dimensions, not the viewport. 1cqi equals 1% of the container's inline size. They allow truly component-relative sizing.
Note Prefer transitioning specific properties rather than using 'all' since transitioning everything can cause unexpected side effects and reduced performance. Stick to transform and opacity for the smoothest animations (they are GPU-accelerated).
Note Keyframe animations run independently from state changes unlike transitions which need a trigger. Define keyframes globally and apply them with the animation property. The animation runs once by default.
keyframescss animationanimate elemententrance animationfade in
Animation Property
syntax
animation: name duration timing-function delay iteration-count direction fill-mode;
example
.spinner {
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.pulse {
animation: pulse 2s ease-in-out infinite alternate;
}
@keyframes pulse {
from { transform: scale(1); }
to { transform: scale(1.05); }
}
Note Key values: infinite loops forever. alternate reverses direction each cycle. forwards (fill-mode) keeps the final keyframe state after the animation ends. Combine multiple animations with commas.
Note Modern CSS supports individual transform properties (translate, rotate, scale) that can be animated independently. The older transform property applies all transforms at once. Transforms do not affect document flow and are GPU-accelerated.
transformtranslaterotatescalemove elementflip element
Note ease-out starts fast and slows down, ideal for enter animations. ease-in starts slow and speeds up, better for exit animations. Custom cubic-bezier values give you fine control. Values beyond 0-1 on the y-axis create overshoot/bounce effects.
easingtiming functioncubic bezierease in outbounce effectanimation speed
View Transitions
syntax
/* Opt elements into the transition */
.element {
view-transition-name: unique-name;
}
/* Customize the transition */
::view-transition-old(name) { ... }
::view-transition-new(name) { ... }
Note View transitions animate between DOM states with a cross-fade by default. Assign view-transition-name to elements that should animate individually rather than cross-fading with the whole page. Each name must be unique on the page. Triggered via JavaScript's document.startViewTransition() API.
html {
scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
}
Note Applies to scrolling triggered by anchor links and JavaScript scrollTo/scrollIntoView calls. Always disable smooth scrolling for users who prefer reduced motion. This does not affect user-initiated scroll (mouse wheel, trackpad).
Note will-change hints to the browser to prepare for an animation, promoting the element to its own compositor layer. Overusing it wastes memory. Apply it only to elements that will actually animate and remove it after the animation finishes if possible.
will changeanimation performancegpu accelerationoptimize animationjank free
Note Native CSS nesting works in all major browsers without a preprocessor. Use & for pseudo-classes and pseudo-elements. Media queries can be nested inside rules. You no longer need the & prefix for simple descendant selectors like .child.
Note Layers control the cascade order regardless of specificity or source order within each layer. Later layers in the declaration beat earlier ones. Unlayered styles beat all layered styles. This solves specificity wars with third-party CSS libraries.
@scope (.scope-root) to (.scope-limit) {
/* styles apply between root andlimit */
}
example
@scope (.card) to (.card-footer) {
p {
color: #374151;
line-height: 1.6;
}
a {
color: #2563eb;
text-decoration: underline;
}
}
/* The .card-footer and its contents are excluded */
Note @scope limits where styles apply by defining both a root and an optional lower boundary. Styles only match elements between the root and the limit, not inside the limit. This provides true component scoping without build tools.
Note @property registers a custom property with a specific type, enabling the browser to animate it. Without registration, custom properties are strings that cannot be transitioned. Supported types include <color>, <length>, <angle>, <number>, <percentage>.
at propertytyped variableanimate variablecustom property typegradient animation
/* Dim page when modal is open */
body:has(dialog[open]) {
overflow: hidden;
}
/* Change grid layout based on numberof children */
.grid:has(> :nth-child(4)) {
grid-template-columns: repeat(2, 1fr);
}
.grid:has(> :nth-child(7)) {
grid-template-columns: repeat(3, 1fr);
}
/* Style label when sibling input is focused */
.field:has(input:focus) label {
color: #2563eb;
}
Note :has() can check for any condition: child state, sibling state, attribute presence, or even count of children. It enables previously impossible CSS-only patterns like conditional layouts and form state styling without JavaScript.
has patternsconditional csscount children cssmodal open stylecss only logic
/* Progress bar tied to page scroll */
.scroll-progress {
position: fixed;
top: 0;
left: 0;
height: 3px;
background: #3b82f6;
transform-origin: left;
animation: scaleProgress linear;
animation-timeline: scroll();
}
@keyframes scaleProgress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* Fade in when element enters viewport */
.reveal {
animation: fadeIn linear;
animation-timeline: view();
animation-range: entry 0% entry 100%;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
Note scroll() ties animation progress to scroll position of a scroll container. view() ties it to the element's visibility in the viewport. animation-range controls which portion of the scroll/view timeline the animation occupies. No JavaScript needed for scroll-linked effects.
scroll animationscroll drivenscroll progressreveal on scrollparallax cssscroll timeline
Note Anchor positioning lets you position elements relative to other elements anywhere in the DOM without a shared parent. position-try-fallbacks automatically repositions (flips) when the element would overflow the viewport. This replaces JavaScript-based tooltip/popover positioning libraries.
anchor positioningtooltip positionpopover positionposition relative to elementcss anchoring
Note light-dark() provides dark mode support inline without media queries. It uses the color-scheme property to determine which value to use. Declare color-scheme: light dark on :root to enable it. This is much simpler than managing separate media query blocks for colors.
Note The popover attribute creates a top-layer element that dismisses on outside click or Escape key, with no JavaScript required. It handles focus trapping and accessibility automatically. Style the ::backdrop pseudo-element for the overlay behind it.
popoverpopupdropdown menutoggle popuppopover apidismiss on click outside
@starting-style (Entry Animations)
syntax
@starting-style {
.element {
/* initial state before transition */
}
}
Note @starting-style defines the initial state for elements transitioning from display: none (or not yet rendered). Without it, browsers cannot animate elements that appear for the first time. Combined with allow-discrete on the display property, it enables pure CSS enter/exit animations.
Note balance evenly distributes text across lines (best for headings). pretty avoids orphaned words on the last line (best for paragraphs). stable prevents text from reflowing while the user is editing. These require no JavaScript and are progressive enhancements.
text wrapbalance textpretty textavoid orphansheading wrap
Relative Color Syntax
syntax
color: oklch(fromvar(--base) calc(l * factor) c h);
Note Relative color syntax creates color variations from a base color by decomposing it into components and modifying them with calc(). This works in any color space (oklch, hsl, srgb). It is the most powerful approach for generating color palettes from a single token.
relative colorcolor variationdarken lightencolor palettederive color