How these CSS examples are built
Each collection page runs its demos live, so you can hover, click and tab through them before you copy anything. Under every demo there is a short note on the technique and a code panel with the HTML and CSS, ready to paste.
The demos follow the same rules across all pages:
- Plain HTML and CSS first. JavaScript appears only where the pattern needs it, and it is vanilla, with no libraries to install.
- Keyboard and screen reader support: real labels, visible focus styles and the ARIA states the pattern calls for.
- Motion is opt-in. Animations sit inside a prefers-reduced-motion query, so people who turn motion off get a still version.
- Every demo is checked at phone width, and newer CSS features are gated with @supports so older browsers get a working fallback.
After the demos, each page has a guide to the properties, browser support and accessibility details behind them, so you know what to change when you adapt the code.
Inline, internal and external CSS examples
CSS reaches a page in 3 ways: a style attribute on one element, a style element in the head, or a link element that loads a separate .css file. Use the external file for anything beyond a throwaway demo.
| Method | Scope | Best use | Fails when |
|---|
| Inline | One element | A single unique tweak | You need :hover, another pseudo-class or a media query |
| Internal | One page | Single-page demos, CMS pages you cannot attach files to | A second page needs the same rules |
| External | Every page that links the file | Whole sites | The href path is wrong or the server skips the text/css type |
MDN calls the external stylesheet the most common and most useful method, because one file can style many pages. It also states that a stylesheet only applies when the server delivers it as text/css.
Inline: the declarations sit in the element's own style attribute.
<p style="color: navy; font-weight: bold;">Bold navy paragraph</p>
Result: that one paragraph turns bold navy and nothing else on the page changes.
Internal: a style element inside the head holds full rule sets.
<head>
<style>
h1 { color: teal; }
</style>
</head>
Result: every h1 on this page turns teal. The next page you build starts unstyled.
External: the link element goes in the head, and the rules live in a separate file.
<link rel="stylesheet" href="styles.css">
/* styles.css */
h1 { color: teal; }
p { line-height: 1.6; }
Result: every page that links styles.css gets teal headings and looser paragraph spacing. Edit the file once, and the whole site follows.
When an internal and an external sheet set the same property at equal specificity, the sheet read last wins (W3Schools). An inline style beats both.
If nothing styles at all, open the Network tab in Chrome DevTools. A 404 on styles.css means the path is wrong, and the browser fails silently without an error on the page.
How do CSS selectors pick which elements to style?
A selector matches elements by type, class, ID, attribute or position. When 2 rules match the same element, specificity decides which declaration applies, and source order breaks ties.
Selector types
Four types cover most daily work.
- Element:
p matches every paragraph - Class:
.card matches every element carrying class="card" - ID:
#site-header matches the one element with that id - Attribute:
a[target="_blank"] matches links that open in a new tab
Valid markup allows one element per id, while a class can sit on as many elements as you like (MDN). So classes carry reusable styles and IDs stay reserved for unique anchors.
Combinators and pseudo-classes
One block, three jobs:
nav > a:hover { text-decoration: underline; }
li:nth-child(odd) { background: #f4f4f4; }
.note::before { content: "Note: "; }
Result: direct child links of a nav underline on hover, odd list items get a light gray stripe, and each .note gets a label in front of its text.
- The child combinator (
>) skips deeper descendants - A space matches any descendant,
+ the next sibling, ~ every later sibling
A ::before rule shows nothing until the content property is set. Even an empty string counts.
Specificity conflicts
Say a heading carries both an ID and a class, and the two rules disagree.
<h1 id="title" class="heading">Hello</h1>
.heading { color: blue; }
#title { color: red; }
The heading renders red. The ID rule outranks the class rule, and the order inside the file does not matter.
MDN ranks the weights in this order:
- Inline style
- ID selectors
- Class, attribute and pseudo-class selectors
- Element and pseudo-element selectors
At equal weight the later rule wins. Reorder or sharpen the selector before reaching for !important, which overrides every normal declaration and becomes a maintenance problem fast.
Text, color and background CSS examples
Most visual styling rests on 6 properties: font-family, line-height, color, background, border-radius and box-shadow.
Text: a font stack always ends in a generic family, so the browser has a fallback.
body {
font-family: Georgia, "Times New Roman", serif;
font-size: 1.125rem;
line-height: 1.6;
}
Result: serif body text at a comfortable reading size, with a generic serif if Georgia is missing.
Color: the same teal, written 4 ways.
color: teal;color: #008080;color: rgb(0, 128, 128);color: hsl(180, 100%, 25%);
Add an alpha value with rgba(0, 128, 128, 0.6) when the color needs to show what sits behind it.
Background: an image and a gradient, side by side.
.banner {
background-image: url("banner.jpg");
background-size: cover;
background-position: center;
}
.hero {
background: linear-gradient(135deg, #0f766e, #134e4a);
}
The banner image fills its box without distortion, cropped around the center. The hero box shows a diagonal teal gradient.
Shape and depth:
.btn {
padding: 0.6em 1.2em;
border: 0;
border-radius: 999px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
}
Result: a pill-shaped button with a soft drop shadow. The cool CSS buttons and CSS shadow effects pages take both properties further.
WCAG 2.2 success criterion 1.4.3 (W3C, 2023) sets the Level AA floor at a 4.5:1 contrast ratio for normal text and 3:1 for large text (18pt, or 14pt bold).
Check any color pair you copy. The color picker in Chrome DevTools shows the ratio, and light gray on white is where copied snippets fail most often.
Flexbox, Grid or positioning: which layout example fits?
Use Flexbox when items line up along one axis, Grid when rows and columns both matter, and positioning when an element must stick or overlay. The MDN Layout cookbook follows the same split, pairing Flexbox with navigation and centering recipes and Grid with cards.
| Method | Axis | Best for | Fails when |
|---|
| Flexbox | One | Navigation bars, centering, button rows | Items must align in rows and columns together |
| Grid | Two | Card grids, page regions | It is overkill for a single row of buttons |
| Positioning | Out of flow | Sticky headers, overlays | An absolute child collapses its parent's height |
Flexbox and Grid are specified by the W3C CSS Working Group as separate modules, CSS Flexible Box Layout and CSS Grid Layout. They combine well. Grid places the page regions, and Flexbox aligns the contents inside each region.
Center an element with Flexbox
The container gets 3 declarations and a height.
.container {
display: flex;
align-items: center;
justify-content: center;
height: 200px;
}
Result: the child box sits in the exact middle, horizontally and vertically. Without the height, the container shrinks to its content and vertical centering has no room to show (MDN).
- Grid version:
display: grid; place-items: center; on the container - Item version:
margin: auto; on the child
Navigation bar with Flexbox
Pattern: a row of links, with the last one pushed to the far edge.
nav { display: flex; gap: 1rem; }
nav .push { margin-left: auto; }
Put .push on the final link (a login link, say) and it jumps to the right while the others stay left. This is the split navigation recipe from the MDN Layout cookbook.
Wrap the links in a nav element so screen readers announce a navigation region. The CSS headers and CSS dropdown menus pages build full navigation on the same idea.
Card grid with CSS Grid
Flexbox ran on 74% of mobile pages in the 2022 Web Almanac (HTTP Archive), while grid reached 12%. Card layouts are a good place to close that gap, because Grid lines up rows and columns at the same time.
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 1.5rem;
}
Result: as many columns of at least 240px as fit the container, stretched equally, wrapping to fewer columns on narrow screens with no media query.
The 240px minimum overflows a viewport narrower than 240px. Swap in minmax(min(240px, 100%), 1fr) to cap it. The CSS cards page uses this exact pattern.
Sticky header with position sticky
A sticky header scrolls with the page until it reaches its offset, then stays put.
header {
position: sticky;
top: 0;
background: #fff;
z-index: 10;
}
It breaks for 3 documented reasons, and none of them throw an error:
- No offset: without top, right, bottom or left, sticky behaves like relative (MDN)
- Overflow on an ancestor: hidden, auto or scroll makes that ancestor the scrolling reference, so the header never reaches its edge
- Short parent: the element only travels inside its containing block
If an ancestor only needs to clip content, overflow: clip does not create a scroll container and leaves sticky working.
How to make CSS examples responsive and add dark mode
Write the small-screen styles first, add a min-width media query for wider screens, and move colors into custom properties so one prefers-color-scheme query can swap the whole palette. Without the viewport meta tag, none of it works on phones.
Mobile-first layout: the base rule carries no media query at all.
.layout { display: grid; gap: 1rem; }
@media (min-width: 48rem) {
.layout { grid-template-columns: 2fr 1fr; }
}
Result: one stacked column on phones, then a wide main column with a narrow sidebar from 48rem upward (768px at the default font size). Set the breakpoint where the content starts looking stretched, not at a device width.
The viewport tag goes in the head:
<meta name="viewport" content="width=device-width, initial-scale=1">
Mobile browsers default to a layout viewport wider than the screen and scale the page down to fit. Media queries then read that wider width, so your breakpoints trigger at the wrong sizes.
Reusable colors: define the palette once on :root and reference it with var().
:root {
--bg: #ffffff;
--text: #1a1a1a;
--accent: #0f766e;
}
body { background: var(--bg); color: var(--text); }
a { color: var(--accent); }
Custom properties cascade like any other property, so one component can override a value locally, as in .card { --accent: crimson; } (MDN). The var() function also takes a fallback: var(--accent, teal) uses teal when --accent is undefined.
Dark mode: the media query only redefines the variables.
@media (prefers-color-scheme: dark) {
:root {
--bg: #111827;
--text: #e5e7eb;
--accent: #5eead4;
}
}
Result: the page follows the operating system theme with no JavaScript. MDN lists prefers-color-scheme under the Media Queries Level 5 specification.
Two ways this fails:
- Colors hard-coded elsewhere (a copied snippet with #fff, say) ignore the variables and stay light on a dark page
- Images with white backgrounds keep glaring until you swap them
Hover, transition and animation examples
Transitions need a state change to run, such as :hover or a class toggle. Keyframe animations run on their own as soon as the rule applies.
| Feature | Transition | Keyframe animation |
|---|
| Trigger | A state change | The rule applying |
| Steps | Start and end state | Any number of keyframes |
| Repeats | No | Yes, with animation-iteration-count |
Hover transition:
.btn {
background: teal;
color: #fff;
transition: background-color 0.2s ease, transform 0.2s ease;
}
.btn:hover,
.btn:focus-visible {
background: #0f766e;
transform: translateY(-1px);
}
Result: the button darkens and lifts 1px over 0.2 seconds, for mouse and keyboard users alike. More variations live on the CSS button hover effects page.
Touch screens have no hover state. Keep important content out of anything that only appears on hover.
Keyframe fade-in:
@keyframes fade-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: none; }
}
.toast { animation: fade-in 0.4s ease-out both; }
Result: the element fades in while sliding up 8px as soon as it renders. The both fill mode holds the invisible start state until the animation begins.
Animate transform and opacity. Width, height, top and left force layout and paint work on every frame.
In web.dev's animation guide, the same box dropped 50% of frames when moved with top and left, against 1% with transform. The guide also treats will-change as a fix for a measured problem, not a default.
Reduced motion: a media query tones the motion down for users who ask for it in their system settings.
@media (prefers-reduced-motion: reduce) {
.toast { animation: none; }
.btn { transition: none; }
}
MDN marks prefers-reduced-motion as Baseline Widely available. Skip it, and the fade-in still plays for people who asked their system to minimize motion. The CSS animations page wraps its demos in a reduced-motion check too.
How to test a CSS example and check browser support
Run the snippet in an editor that shows the result, inspect the applied rules in Chrome DevTools, then check each property's Baseline status on MDN or Can I use. Resize the window last, because layout and media query bugs only show at other widths.
- Paste the snippet into CodePen, the W3Schools Try it Yourself editor, or the MDN Playground (click Play on any MDN code block)
- Right-click the element, choose Inspect, and read the Styles pane in Chrome DevTools
- Look for crossed-out declarations, which another rule overrode
- Switch to the Computed pane to see the values the browser actually applied
- Look up every property on MDN or Can I use, and read its Baseline badge
- Drag the window narrower, or use device emulation, and watch each breakpoint
Baseline marks a feature Newly available once all core browsers (Chrome, Edge, Firefox, Safari) support it, and Widely available 30 months later (web.dev). Widely available features need no fallback. Wrap newer ones in @supports.
Mozilla built the redesigned MDN frontend on Widely available features and handled the rest case by case with polyfills or progressive enhancement (web.dev, August 2025 digest).
Baseline status of 4 features, as of October 2026:
- Flexbox: available across browsers since September 2015 (MDN)
- CSS Grid: available across browsers since October 2017 (MDN, grid-column entry)
- Container queries (style an element by its container's width): Widely available since 14 August 2025 (web-features data)
- :has() (select a parent by its children): Newly available since 19 December 2023, Widely available since 19 June 2026 (web-features data)
All 4 now work without a fallback in current browsers. Keep @supports for features that are still Newly available.
Vendor prefixes: most are gone. Autoprefixer reads Can I Use data and your Browserslist target, adds only the prefixes still needed, and strips outdated ones such as the old border-radius prefixes.
# .browserslistrc
defaults
The defaults query is the target Autoprefixer recommends. It works from the unprefixed property, so write the standard syntax yourself. A snippet that only contains -webkit- code gets no other prefixes added.
Why do copied CSS examples break?
Copied CSS breaks for 5 reasons: a specificity clash, a class name collision, missing markup, fixed dimensions, and outdated patterns. The first one is the most common, and DevTools finds it fastest.
In the Styles pane, a crossed-out declaration means another rule overrode it, and hovering a selector shows its specificity weight (Chrome DevTools documentation).
/* copied snippet */
.btn { background: teal; }
/* already on the site */
.nav a { background: gray; }
/* fix: scope the snippet */
.nav .btn { background: teal; }
The site rule wins because an element plus a class outweighs a lone class. Scoping the snippet under the same parent restores the order without reaching for !important.
- Name collision: generic names like .container, .card and .button already exist in the host stylesheet, so both rule sets apply to the same element. Prefix them (.promo-card) before pasting.
- Missing markup: the CSS assumes an HTML structure. MDN's pagination recipe, for one, styles list items inside a nav element, and it does nothing without that markup.
- Fixed dimensions: a hard-coded width on a container overflows a narrow phone screen. Swap it for max-width: 100%.
- Outdated patterns: float and clearfix layouts, table-based layout and old prefixed gradients still circulate in older snippets. Flexbox or Grid replaces the first two, and Autoprefixer cleans up the last.
Check the Styles pane before blaming the snippet.
CSS examples FAQ
What does a CSS example consist of?
A CSS example has 3 parts: a rule set (a selector with property and value declarations), the HTML it targets, and the visible result.
Drop the matching markup and a snippet appears to do nothing.
How do you build a CSS tooltip?
Wrap the trigger in an element with position: relative, hold the text in a ::after pseudo-element using content: attr(data-tip), position it absolutely, and reveal it on :hover and :focus-visible.
Touch screens have no hover, so keep important information visible by default. The CSS tooltips page has 17 working versions.
Can CSS style tables, forms and image galleries?
Yes. Tables need border-collapse: collapse and cell padding, and forms need padded inputs with a visible :focus-visible outline.
Galleries work best as a Grid with gap, with images set to object-fit: cover so mixed photo sizes stay uniform.
Should you use Tailwind CSS, Bootstrap or Sass instead of plain CSS?
Not at first. Learn plain CSS first, because Sass compiles down to it, and Tailwind CSS and Bootstrap apply it through utility and component classes.
Selectors and the cascade stay your debugging tools in all three. Adopt one when a team needs shared conventions.