Home  ›  Web Development  ›  CSS

WEB DEVELOPMENT / CSS

CSS: Complete Guide to CSS3, Selectors, Layout & Responsive Design

Learn how CSS controls the appearance, layout, responsiveness and visual behaviour of modern websites — from selectors and the box model to Flexbox, Grid, animations, variables and responsive design.

Every concept comes with a short, valid example you can copy and adapt in your own projects.

EXAMPLE: CSS AND RENDERED RESULT
styles.css
.card {
  padding: 24px;
  border-radius: 12px;
  background: #ffffff;
  box-shadow: 0 10px 30px rgba(0,0,0,.08);
}
Browser preview
Styled card
Same markup, different presentation.
CSS code editor and browser preview illustrating website styling

THE BASICS

What Is CSS?

CSS stands for Cascading Style Sheets. It’s the style sheet language that controls how structured content is presented: colours, typography, spacing, borders, shadows, layout, responsive behaviour, visual states, transitions and animation.

Calling CSS “styling for HTML” undersells what it does now. Modern CSS handles full two-dimensional layout with Grid, adapts components to their container, calculates values at runtime, holds reusable custom properties, responds to user preferences such as reduced motion and colour scheme, and drives most of the interaction feedback in a typical interface.

CSS isn’t a programming language — it’s declarative. You describe the result you want and the browser works out how to produce it. That said, features like custom properties, calc() and container queries give it real computational capability within that declarative model.

CSS evolves as a set of web platform specifications developed by the W3C’s CSS Working Group, documented on MDN Web Docs. “CSS3” refers to the modular generation of those specifications rather than a separate language, and there’s no single final version — individual modules advance independently.

CSS controls

THE FOUNDATION

CSS vs HTML vs JavaScript

HTML — Structure

Defines what content is: headings, paragraphs, links, forms and regions. It carries the meaning software interprets. See our HTML guide.

CSS — Presentation

Decides how that content looks and how it's laid out across screen sizes, including states such as hover and focus.

JavaScript — Behaviour

Handles interaction and application logic, often by changing classes that CSS then styles. See our JavaScript guide.

The three are separable in theory and intertwined in practice. CSS selectors depend on HTML structure and class names; JavaScript usually toggles classes rather than setting styles directly; and several things that once needed scripting — disclosure widgets, scroll behaviour, sticky positioning — are now handled in markup and CSS. See the wider picture in our web development guides.

SYNTAX

How CSS Works and How Rules Are Written

A CSS rule has two parts: a selector that decides which elements it applies to, and a declaration block in braces containing one or more declarations. Each declaration is a property and a value, separated by a colon and ended with a semicolon.

In p { color: #222222; }, p is the selector, color the property and #222222 the value.

Browsers gather every rule that could apply to an element — from your stylesheets, the browser’s own defaults and any user styles — then resolve the conflicts to produce a single computed value for each property. That resolution process is the “cascading” part, and understanding it is what separates guessing from knowing why a style did or didn’t apply.

 CSS — anatomy of a ruleEXAMPLE
selector {
  property: value;
}

/* A real example */
p {
  color: #222222;
  line-height: 1.6;
}
 CSS — selectors and combinatorsEXAMPLE
/* Type, class, ID */
p { }
.card { }
#header { }

/* Attribute and universal */
input[type="email"] { }
* { }

/* Grouping */
h1, h2, h3 { }

/* Combinators */
nav a { }           /* descendant */
.parent > .child { } /* direct child */
h2 + p { }          /* adjacent sibling */
h2 ~ p { }          /* general sibling */

SELECTORS

CSS Selectors and Combinators

Selectors decide which elements a rule targets. Type selectors match elements by name, class selectors match a reusable label, ID selectors match one unique element, attribute selectors match on attributes and values, and the universal selector matches everything. Grouping several selectors with commas applies one block to all of them.

Classes are the workhorse for styling because they’re reusable and keep specificity manageable. IDs carry much higher specificity, which makes rules hard to override later — reserve them for anchors and JavaScript hooks rather than routine styling.

Combinators express relationships. A space means descendant at any depth; > means direct child only; + matches the element immediately following a sibling; ~ matches any following sibling. Prefer shallow selectors — long descendant chains are brittle, because any structural change breaks them.

STATES

Pseudo-Classes and Pseudo-Elements

Pseudo-classes target elements in a particular state or position. Interaction states include :hover, :active, :focus, :focus-visible, :visited, :checked and :disabled. Structural ones include :first-child, :last-child and :nth-child().

:focus-visible deserves attention: it applies focus styling when the browser judges it useful — typically keyboard navigation — so you can give keyboard users a clear indicator without a ring appearing on every mouse click. Never style :hover alone for anything important; touch devices have no hover and keyboard users never trigger it.

Pseudo-elements style a part of an element or insert generated content: ::before and ::after (which need a content value), plus ::first-letter, ::first-line, ::selection and ::placeholder. Generated content is decorative — don’t put information there that people need.

 CSS — pseudo-classes and pseudo-elementsEXAMPLE
/* Interaction states */
.button:hover { background: #0D4A8A; }
.button:focus-visible {
  outline: 3px solid #1562B1;
  outline-offset: 3px;
}
.field:disabled { opacity: 0.6; }

/* Structural */
.list li:first-child { }
.list li:nth-child(odd) { }

/* Pseudo-elements */
.quote::before { content: "\201C"; }
.input::placeholder { color: #6b7a8c; }
::selection { background: #EAF2FB; }
SIMPLIFIED CASCADE MODEL
All declarations that could apply
1. Origin and importance — author, user, browser, and !important
2. Cascade layers — @layer order
3. Specificity — how precisely the selector matches
4. Source order — later wins among equals
Winning declaration → computed style
How the CSS cascade resolves competing style rules

THE CASCADE

The Cascade, Specificity and Inheritance

When several rules set the same property on the same element, the cascade decides which wins. Specificity is only one step in that process — and not the first. The browser considers origin and importance (author, user and browser styles, with !important reordering things), then cascade layers, then specificity, and finally source order.

Specificity is a rough hierarchy: element and pseudo-element selectors count least, classes, attributes and pseudo-classes more, IDs more again, with inline styles above all selectors. Reaching for !important to win a battle almost always creates a harder one later.

Inheritance is separate. Some properties — color, font-family, line-height and other text-related ones — pass to descendants automatically; most layout properties don’t. Setting typography on body and letting it flow down removes a great deal of repetition. The keywords inherit, initial, unset and revert control this explicitly.

VALUES

CSS Values, Units and Colours

Values come in several forms: keywords such as auto, numbers, lengths, percentages, colours, functions and custom values. Which unit to use depends on what the value should respond to.

px is absolute and predictable. rem is relative to the root font size, so it scales when a user changes their browser text size — a good default for typography and spacing. em is relative to the element’s own font size, useful for spacing that should scale with the text it sits beside. Percentages relate to the containing block. Viewport units vw, vh, vmin and vmax relate to the viewport, and the newer svh, lvh and dvh handle mobile browsers whose toolbars change the visible height. No unit is universally right.

Colours can be named keywords, hex, rgb() or hsl(), with newer colour functions and wider gamuts available in modern browsers. HSL is often easier to reason about because adjusting lightness is a single number. Alpha transparency is written with a slash in modern syntax, or via the older rgba() and hsla() forms.

 CSS — units and coloursEXAMPLE
/* Absolute and relative lengths */
.box {
  padding: 16px;        /* absolute */
  font-size: 1rem;      /* root font size */
  margin-block: 2em;    /* own font size */
  width: 100%;          /* of the container */
  max-width: 60ch;      /* character width */
}

/* Viewport units */
.hero { min-height: 60svh; }

/* Colour notations */
.a { color: #1562B1; }
.b { color: rgb(21 98 177); }
.c { color: hsl(209 79% 39%); }
.d { background: rgb(21 98 177 / 0.1); }
 CSS — typography and web fontsEXAMPLE
body {
  font-family: "Inter", system-ui, sans-serif;
  font-size: 1rem;
  line-height: 1.6;
  color: #222222;
}

h1 {
  font-family: "Montserrat", system-ui, sans-serif;
  font-weight: 800;
  letter-spacing: -0.02em;
}

p { max-width: 65ch; }

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter.woff2") format("woff2");
  font-weight: 400 700;
  font-display: swap;
}

TYPOGRAPHY

CSS Typography and Web Fonts

Typography is where CSS most directly affects whether content is readable. The core properties are font-family, font-size, font-weight, line-height, letter-spacing, text-align, text-transform, text-decoration and font-style.

A few habits help: set a comfortable line-height (unitless values inherit proportionally), limit line length with max-width in ch units, and avoid justified text on the web, where the spacing gets uneven. Left-aligned body text is easier to read than centred blocks.

Web fonts load through @font-face or a font service. Always provide a fallback stack ending in a generic family. font-display: swap shows fallback text immediately rather than leaving invisible text while the font loads. Each additional family and weight costs bandwidth, so load only what the design uses — variable fonts can cover a range of weights in one file. A custom font isn’t automatically better than a well-chosen system stack.

BOX MODEL

The CSS Box Model, Sizing and Spacing

Every element is a box with four layers: content at the centre, then padding inside the border, the border itself, and margin outside it.

box-sizing decides what width measures. The default content-box excludes padding and border, so adding padding makes an element wider than declared. border-box includes them, which is why most projects set it globally — useful rather than mandatory.

For sizing, pairing width: 100% with max-width is more flexible than a fixed width, and min-height is usually safer than height, which can clip content. aspect-ratio maintains proportions without padding tricks.

Margin creates space outside, padding inside. margin: 0 auto centres a block with a set width. Vertical margins between siblings collapse into the larger of the two rather than adding up — surprising the first time you meet it, and one reason gap in flex and grid layouts is easier to reason about. Borders take border-width, border-style and border-color, with border-radius for rounded corners.

THE CSS BOX MODEL
MARGIN
BORDER
PADDING
CONTENT
CSS box model showing content padding border and margin
 CSS — box model and sizingEXAMPLE
*, *::before, *::after {
  box-sizing: border-box;
}

.card {
  width: 100%;
  max-width: 400px;
  padding: 24px;
  border: 1px solid #DCE8F5;
  border-radius: 12px;
  margin-block: 32px;
}

.media { aspect-ratio: 16 / 9; }

LAYOUT BEHAVIOUR

Display, Flow, Positioning and Stacking

The display property determines how an element generates boxes and lays out its children: block, inline, inline-block, flex, grid, none and contents. Changing it changes layout behaviour entirely, which is why block versus inline is a default rather than a fixed property of any element.

In normal flow, block boxes stack vertically and fill available width, while inline boxes flow along the text. Most layout work is adjusting that flow rather than replacing it.

Hiding things: three different tools

Method
Layout
Interaction
Suited to
display: none
LayoutRemoved from layout entirely
InteractionNot rendered, not focusable
Suited toHiding content completely
visibility: hidden
LayoutSpace is still reserved
InteractionNot focusable
Suited toKeeping layout while hiding
opacity: 0
LayoutSpace reserved, fully transparent
InteractionStill interactive and focusable
Suited toFade transitions, not hiding
Comparison of display none, visibility hidden and opacity zero

Positioning changes how an element sits relative to flow. relative offsets an element while keeping its space; absolute removes it from flow and positions it against the nearest positioned ancestor; fixed pins it to the viewport; sticky behaves normally until a scroll threshold, then holds position. Building whole layouts out of absolute positioning is fragile — use flex and grid instead.

z-index controls stacking order, but only within a stacking context. A higher number does not always win: if an ancestor creates its own stacking context, its children are stacked inside it and can never rise above a sibling of that ancestor. Properties such as transform, filter, opacity below 1 and position with z-index all create contexts — which is why an element with z-index: 9999 can still sit behind something with z-index: 2.

overflow decides what happens to content that doesn’t fit: visible, hidden, clip, scroll or auto. Use auto for scrollable regions such as wide tables, and be careful with hidden — it’s a common cause of content silently disappearing, and it can break sticky positioning in ancestors.

CSS POSITIONING
static — the default; stays in normal flow
relative — offset from its normal place; space reserved
absolute — removed from flow; positioned to nearest positioned ancestor
fixed — removed from flow; positioned to the viewport
sticky — flows normally until it reaches a threshold, then sticks
CSS positioning values from static through relative, absolute, fixed and sticky
EXAMPLE FLEX LAYOUT
FLEX CONTAINER — MAIN AXIS →
Item 1
Item 2
Item 3
CROSS AXIS ↕
CSS Flexbox layout showing main and cross axes
 CSS — FlexboxEXAMPLE
.container {
  display: flex;
  flex-direction: row;   /* or column */
  flex-wrap: wrap;
  justify-content: space-between; /* main axis */
  align-items: center;            /* cross axis */
  gap: 20px;
}

.item {
  flex: 1 1 240px;  /* grow, shrink, basis */
}

.item--pinned {
  margin-inline-start: auto;
  align-self: flex-start;
}

FLEXBOX

CSS Flexbox

Flexbox lays out items along a single axis and distributes space between them. Setting display: flex makes an element a flex container and its children flex items.

Everything in Flexbox relates to two axes. The main axis follows flex-direction — horizontal for row, vertical for column — and the cross axis runs perpendicular to it. justify-content aligns along the main axis, align-items along the cross axis. Swap the direction and those two swap meaning, which explains most early confusion.

For sizing, the flex shorthand sets grow (share of leftover space), shrink (how it gives space back) and basis (starting size). flex: 1 1 240px gives items a 240px preference that flexes both ways. flex-wrap: wrap lets items move onto new lines, align-self overrides alignment for one item, order changes visual order — use it sparingly, since it desynchronises visual and keyboard order — and gap spaces items without margin arithmetic.

GRID

CSS Grid and How It Compares to Flexbox

Grid lays out content in two dimensions at once. grid-template-columns and grid-template-rows define tracks, gap spaces them, and items are placed automatically or explicitly with grid-column and grid-row.

The fr unit distributes free space, repeat() avoids writing tracks out longhand, and minmax() sets a floor and ceiling per track. Combining them — repeat(auto-fit, minmax(240px, 1fr)) — produces a card grid that reflows at any width with no media queries at all, which is one of the most useful lines in modern CSS. grid-template-areas lets you name regions and draw the layout in the stylesheet, and rows created beyond your explicit tracks form the implicit grid, sized by grid-auto-rows.

Aspect
Flexbox
Grid
Dimensions
FlexboxOne axis at a time
GridRows and columns together
Content vs layout
FlexboxSizes driven by content
GridSizes driven by the defined tracks
Typical use
FlexboxNavigation bars, button rows, card internals
GridPage layouts, galleries, dashboards
Alignment
FlexboxAlong main and cross axes
GridPer track, per area and per item
Overlap
FlexboxNot designed for it
GridItems can share cells and overlap
Together
FlexboxOften a grid item's internals
GridOften the outer layout system
Flexbox compared with CSS Grid
EXAMPLE GRID LAYOUT
1
2
3
4
5
6
3 COLUMNS × 2 ROWS
CSS Grid layout showing rows and columns
 CSS — GridEXAMPLE
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

/* Responsive without media queries */
.auto-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 24px;
}

/* Named areas */
.page {
  display: grid;
  grid-template-areas:
    "header header"
    "side   main"
    "footer footer";
  grid-template-columns: 240px 1fr;
}
.page > header { grid-area: header; }

Neither replaces the other, and most real interfaces use both: Grid for the page structure, Flexbox for the contents of individual components. Choose by asking whether you’re arranging along one axis or two.

RESPONSIVE

Responsive CSS: Media Queries, Container Queries and Fluid Values

Responsive design in CSS comes from flexible systems first — percentage and max-width sizing, flexible images, Flexbox and Grid — with breakpoints handling only what those can’t.

Media queries apply rules based on viewport characteristics and user preferences: width, height, orientation, prefers-reduced-motion and prefers-color-scheme. A mobile-first approach writes the simplest layout as the base and adds complexity with min-width queries, which usually means less CSS and fewer overrides. Choose breakpoints where your layout actually breaks rather than copying a list of device widths — 768px is a convention, not a rule.

Container queries let a component respond to the width of its own container instead of the viewport. That’s what makes a card genuinely reusable: the same component can be narrow in a sidebar and wide in a main column without knowing where it sits. They complement media queries rather than replacing them — page-level decisions and user preferences still belong to media queries.

Fluid values remove breakpoints altogether in places. clamp(minimum, preferred, maximum) scales a value smoothly between bounds; the example figures are illustrative and should be tuned to your own type scale, with the minimum kept readable.

EXAMPLE RESPONSIVE BEHAVIOUR
DESKTOP
CardCardCard
TABLET
CardCard
MOBILE
CardCard
Responsive CSS layout across desktop tablet and mobile
 CSS — mobile-first media queriesEXAMPLE
.card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
}

@media (min-width: 48em) {
  .card-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Preference-based queries */
@media (prefers-color-scheme: dark) { }
@media (prefers-reduced-motion: reduce) { }
 CSS — container queries and fluid typeEXAMPLE
.card-wrapper {
  container-type: inline-size;
}

@container (min-width: 500px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
  }
}

h1 {
  font-size: clamp(2rem, 5vw, 4rem);
}
 CSS — custom properties and design tokensEXAMPLE
:root {
  --color-primary: #1562B1;
  --color-surface: #F5F9FC;
  --space-sm: 8px;
  --space-md: 24px;
  --radius-md: 12px;
  --shadow-sm: 0 10px 30px rgb(0 0 0 / 0.08);
}

.card {
  color: var(--color-primary);
  padding: var(--space-md);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

/* Fallback if the variable isn't set */
.badge { color: var(--color-accent, #1562B1); }

FUNCTIONS & VARIABLES

CSS Functions, Custom Properties and Design Tokens

CSS functions calculate values at runtime. calc() mixes units in arithmetic, min() and max() pick from candidates, clamp() constrains a value between bounds, var() reads a custom property, rgb() and hsl() build colours, and minmax() and repeat() define grid tracks.

Custom properties — often called CSS variables — store reusable values. Unlike preprocessor variables they’re part of CSS itself: they participate in the cascade, inherit to descendants, can be redefined for a scope or under a media query, and can be read and changed by JavaScript at runtime. That’s what makes theming and dark mode straightforward, since redefining a handful of properties restyles everything referencing them.

Defined on :root, they become design tokens: named values for colour, spacing, typography, radius and shadow that keep a site visually consistent and make a change in one place propagate everywhere. var() also accepts a fallback for when a property isn’t defined.

VISUAL PROPERTIES

Backgrounds, Gradients, Shadows and Media Fitting

Backgrounds combine background-color, background-image, background-size, background-position, background-repeat and background-attachment. Always set a colour behind an image so text stays readable if the image fails to load.

Gradients are generated images: linear-gradient() along a line, radial-gradient() outward from a point, conic-gradient() around one. They’re light and scalable, but check text contrast against the whole gradient — the light end is usually where it fails.

Shadows take horizontal and vertical offsets, blur, optional spread and colour. Large, soft, low-opacity shadows read as depth; heavy dark ones read as artefacts. Keeping two or three shadow tokens across a project is more coherent than inventing one per component.

object-fit controls how a replaced element such as an image fills its box — cover crops to fill, contain fits entirely — with object-position choosing the focal point. Combined with aspect-ratio, it keeps image cards uniform regardless of the source dimensions.

 CSS — backgrounds, gradients, shadows and mediaEXAMPLE
.panel {
  background-color: #F5F9FC;
  background-image: linear-gradient(135deg, #1562B1, #0D4A8A);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.card {
  box-shadow: 0 10px 30px rgb(0 0 0 / 0.08);
}

.thumb {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: center;
}
 CSS — transitions, animations and motion preferencesEXAMPLE
.button {
  transition: transform 180ms ease, background-color 180ms ease;
}

.card:hover {
  transform: translateY(-4px);
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

.panel {
  animation: fadeIn 300ms ease-out both;
}

/* Illustrative — adapt per project */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
 CSS — visible focus stylingEXAMPLE
button:focus-visible,
a:focus-visible {
  outline: 3px solid #1562B1;
  outline-offset: 3px;
}

/* Never do this without a replacement */
/* :focus { outline: none; } */

MOTION & STATES

Transforms, Transitions, Animations and Focus

Transforms move, scale, rotate and skew an element without affecting the layout around it, which makes them efficient to animate. Transitions smooth a change between two states over a duration with an easing curve. Animations use @keyframes for sequences that can repeat, alternate and hold their end state through animation-fill-mode.

Animate sparingly and prefer transform and opacity, which browsers handle more cheaply than animating layout properties. Motion should communicate something — a state change, a relationship, a transition — rather than fill silence.

prefers-reduced-motion respects the operating system setting for people who experience discomfort from movement. The blanket override shown is a common starting point, not a universal drop-in: some motion conveys meaning and is better reduced than removed. See website accessibility.

Focus styling is non-negotiable. Removing outlines without an equally visible replacement makes keyboard navigation guesswork. :focus-visible lets you show a strong indicator for keyboard users without a ring on every mouse click.

CSS IN CONTEXT

CSS, Accessibility, Performance and SEO

CSS and Accessibility

CSS decides whether text has sufficient contrast, whether focus is visible, whether interaction depends on hover, whether content survives zoom and text resizing, and whether motion respects preferences. It can remove barriers or create them — but styling alone can't make a page accessible; that depends on markup, behaviour and testing too. See website accessibility.

Colour and Contrast

Text, interface controls, focus indicators and icons that carry meaning all need adequate contrast against their backgrounds, with requirements varying by text size and element type. Never judge by eye — check actual values with a contrast tool against the official WCAG criteria, and never rely on colour alone to convey information.

CSS and Performance

Stylesheets are render-blocking, so size matters: large files, accumulated unused rules, many font families and weights, expensive effects such as large blurs, and heavy animation all have a cost. Performance depends on the whole page, not CSS alone. See website speed.

Does CSS Affect SEO?

Not directly — CSS is presentation, not content. Its influence is indirect, through mobile usability, page performance, layout stability, whether content is visible and readable, and accessibility. No CSS property is a ranking lever. See website SEO.

ARCHITECTURE

CSS Architecture: Layers, Naming and Organisation

As a project grows, the hard part stops being what a property does and becomes where a rule belongs and why one overrides another.

Cascade layers (@layer) let you declare an explicit order — reset, base, layout, components, utilities — so later layers win regardless of selector specificity. That removes most of the specificity arms race and the !important habit that follows it.

Resets and normalisation deal with browser default styles. A reset strips them back; a normalise approach smooths inconsistencies while keeping sensible defaults; many teams write their own small base layer. No single approach is best.

For naming, BEM uses block, element and modifier (.card, .card__title, .card--featured) to keep selectors flat and intent obvious. Utility classes apply single-purpose styles for fast composition. They’re different trade-offs — component classes centralise meaning, utilities reduce custom CSS — and many projects mix them.

Logical properties such as margin-inline, padding-block and inset-inline describe positions relative to writing direction rather than physical sides, so layouts adapt for right-to-left and vertical scripts. writing-mode controls the direction itself. Useful for multilingual work, not required everywhere.

 CSS — architecture and organisationEXAMPLE
/* Declare layer order once, up front */
@layer reset, base, layout, components, utilities;

@layer components {
  /* BEM: block, element, modifier */
  .card { }
  .card__title { }
  .card--featured { }
}

@layer utilities {
  .text-center { text-align: center; }
  .flow > * + * { margin-block-start: var(--space-md); }
}

/* Logical properties adapt to writing direction */
.box {
  margin-inline: auto;
  padding-block: 24px;
}

MODERN CSS

Modern CSS Features Worth Learning

Listed by category, not ranked. Support for individual features differs between browsers and changes over time, so check current compatibility data rather than assuming — and provide fallbacks where a feature is doing structural work.

Container Queries

Components respond to their own container's size rather than the viewport.

Cascade Layers

@layer sets an explicit override order independent of specificity.

Custom Properties

Cascading, inheritable variables readable and writable at runtime.

clamp(), min(), max()

Constrain and interpolate values without breakpoints.

aspect-ratio

Maintain proportions without padding hacks.

Logical Properties

Spacing and position that follow writing direction.

Modern Colour Functions

Newer colour spaces and syntax for wider gamuts and easier manipulation.

Subgrid

Nested grids align to their ancestor's tracks, keeping rows consistent across cards.

:is() and :where()

Group selectors compactly; :is() takes the specificity of its most specific argument, :where() contributes none.

:has()

Style an element based on what it contains or is related to — a card with an image, a label whose input is invalid.

:has() is often called the parent selector, and it genuinely fills a long-standing gap — styling a container based on its contents, or a label based on its input’s state. It’s powerful, but it isn’t a general substitute for JavaScript: it styles, it doesn’t compute or respond to arbitrary application state.

Subgrid solves the ragged-card problem: nested grids can align to the parent’s tracks so headings and footers line up across cards of different content lengths.

 CSS — :is(), :where() and :has()EXAMPLE
/* Grouping without repetition */
:is(h1, h2, h3) > a { text-decoration: none; }

/* Zero specificity — easy to override */
:where(.prose) p { margin-block: 1em; }

/* Style a parent based on its contents */
.card:has(img) {
  display: grid;
  grid-template-columns: 120px 1fr;
}

.field:has(input:invalid) { border-color: #8A1C1C; }

COMPATIBILITY & DEBUGGING

Progressive Enhancement, Fallbacks and Debugging CSS

Progressive enhancement means the core content and functionality work first, with layout, interaction and visual refinement layered on. If an advanced feature isn’t available, the page should still be usable rather than broken.

Feature queries (@supports) test whether a browser understands a property and value, letting you write a sensible fallback and then enhance. Browser support changes continuously, so check current compatibility data rather than relying on any claim about what “all browsers” do — including claims on this page.

For debugging, browser DevTools are the whole game. The styles panel shows matched rules with overridden ones struck through, the computed panel shows final values, and the box model diagram explains most sizing confusion. The flex and grid inspectors overlay real track lines, and device mode tests breakpoints. Panel names and layout differ between browsers, but the capabilities are broadly equivalent.

01

Inspect the Element

Open DevTools and select the element that's misbehaving.

02

Check the Selector

Confirm your rule is matching at all; struck-through rules were overridden.

03

Check Specificity

See which rule won and why.

04

Check the Cascade

Look for layers, !important and source order.

05

Check Inheritance

Is the value coming from an ancestor rather than your rule?

06

Check Computed Styles

The computed panel shows the final resolved value.

07

Check the Box Model

Padding, border and margin explain most sizing surprises.

08

Check Layout

Use the flex and grid inspectors to see the actual tracks.

09

Check Responsive Rules

Switch device mode and confirm which queries apply.

10

Test the Fix

Verify at several widths and with real content.

 CSS — feature queries and fallbacksEXAMPLE
/* Fallback first, enhancement after */
.layout {
  display: flex;
  flex-wrap: wrap;
}

@supports (display: grid) {
  .layout {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  }
}

@supports (backdrop-filter: blur(10px)) {
  .glass { backdrop-filter: blur(10px); }
}

IMPROVEMENTS

Practical CSS Improvements and Anti-Patterns

Simplified before-and-after pairs. Context always matters — a fixed width is fine inside a controlled component — but these swaps solve the problems that come up most often.

Common CSS
More flexible CSS
Why it helps
width: 1200px;
More flexible CSSwidth: 100%; max-width: 1200px;
Why it helpsFills small screens without overflowing
margin-left: 300px;
More flexible CSSFlexbox or Grid with gap
Why it helpsSpacing survives content and viewport changes
font-size: 64px;
More flexible CSSfont-size: clamp(2rem, 5vw, 4rem);
Why it helpsScales between sensible bounds
height: 400px;
More flexible CSSmin-height: 400px;
Why it helpsContent can grow without being clipped
:focus { outline: none; }
More flexible CSS:focus-visible { outline: 3px solid …; }
Why it helpsKeyboard users can see where they are
div div div ul li a { … }
More flexible CSS.nav__link { … }
Why it helpsFlat, readable and easy to override
Comparison of rigid CSS with more flexible alternatives

Common CSS mistakes to avoid

Excessive !important

Wins today, blocks every override tomorrow.

Runaway Specificity

Rules that can only be beaten by worse rules.

Deeply Nested Selectors

Break the moment the markup changes.

Fixed Widths Everywhere

Overflow on small screens, wasted space on large.

Negative Margin Patching

Fragile spacing that hides a layout problem.

Absolute Positioning for Layout

Doesn't reflow, doesn't adapt, doesn't scale.

Ignoring Responsive Design

Desktop-only layouts on a mostly mobile web.

Hidden Focus Indicators

Keyboard navigation becomes guesswork.

Hover-Only Interaction

Invisible to touch and keyboard users.

Excessive Animation

Distraction, discomfort and wasted frames.

Too Many Font Families

Visual incoherence plus loading cost.

Duplicate and Unused CSS

Dead weight nobody dares delete.

Arbitrary Breakpoints

Device-list widths instead of where the layout breaks.

IDs for Styling

High specificity with no reuse.

Inline Styles Everywhere

Unmaintainable and hardest to override.

CSS Papering Over Bad HTML

Styling around a structure that should be fixed.

Colour as the Only Cue

Meaning lost for many readers.

Ignoring DevTools

Guessing at problems the browser would show you.

WORDPRESS & ELEMENTOR

CSS in WordPress and Elementor

A WordPress page’s final appearance comes from several stylesheets at once: the theme, any child theme, plugins, the block editor, and Elementor’s own CSS. When something looks wrong, it’s usually a cascade question — which of those is winning, and why.

Elementor is itself built on CSS. Containers use flexbox, the responsive controls generate media queries, and global colours and fonts act as a design token layer. Use those native controls first: they’re responsive-aware and survive redesigns better than hand-written overrides.

Custom CSS belongs where the controls genuinely can’t reach — clamp() typography, container queries, complex selectors, pseudo-elements. Add a CSS class to a widget and target that, rather than writing selectors against generated element IDs, which change. Resist !important: with theme, plugin and builder styles already competing, it escalates quickly.

Reusable components — buttons, cards, forms, navigation, alerts, badges, tables and hero sections — are worth defining once as classes you apply, whichever tool builds the page.

Buttons
Cards
Forms
Navigation
Alerts
Badges
Tables
Hero sections

Elementor CSS best practices

Use Global Colours

Define the palette once so a brand change is a single edit.

Use Global Fonts

Avoid styling every heading independently.

Use Containers

Build responsive structure with real containers and flex settings.

Use CSS for Refinement

Don't use custom CSS to compensate for poor structure.

Avoid Excessive !important

Keep specificity manageable across theme, plugins and builder.

Use Reusable Classes

Add a class and style it once instead of repeating settings.

Test Responsive Behaviour

Check every breakpoint, not just desktop.

Test Accessibility

Check contrast, focus visibility and readable typography.

 HTML, CSS and JavaScript togetherEXAMPLE
<!-- HTML: structure -->
<button type="button" class="menu-button" aria-expanded="false">Menu</button>

/* CSS: presentation and state styling */
.menu-button {
  padding: 12px 18px;
  border-radius: 8px;
  background: var(--color-primary);
  color: #fff;
}
.menu-button[aria-expanded="true"] {
  background: #0D4A8A;
}

// JavaScript: behaviour
btn.addEventListener("click", () => {
  const open = btn.getAttribute("aria-expanded") === "true";
  btn.setAttribute("aria-expanded", String(!open));
});

WORKING TOGETHER

How HTML, CSS and JavaScript Fit Together

This small component shows the usual division of labour. The HTML declares a button and an accessibility state. The CSS styles it, including a rule that reacts to that state attribute. The JavaScript does nothing but keep the attribute accurate.

That pattern — scripts change state, CSS reacts to state — keeps styling in stylesheets where it can be overridden and maintained, rather than scattered through inline style assignments. It also means the accessibility information and the visual state can’t drift apart.

CSS connects outward too: it implements the decisions made in website design basics and UI/UX design, powers the techniques in responsive design, and is what frameworks like React ultimately ship alongside their markup.

REFERENCE

CSS Cheat Sheet

A categorised quick reference for the properties and features covered above. For the authoritative definition of any property, use MDN Web Docs or the relevant CSS specification rather than a summary.

SELECTORS*element.class#id[attr]:hover:focus-visible::before
BOX MODELmarginpaddingborderborder-radiusbox-sizing
SIZINGwidthmax-widthmin-heightaspect-ratioobject-fit
LAYOUTdisplaypositionflexgridgapz-indexoverflow
FLEXBOXflex-directionjustify-contentalign-itemsflex-wrapflex
GRIDgrid-template-columnsrepeat()minmax()auto-fitgrid-area
TYPOGRAPHYfont-familyfont-sizefont-weightline-heightletter-spacing
COLOURcolorbackgroundborder-colorlinear-gradient()
EFFECTSbox-shadowopacitytransformtransitionanimation
RESPONSIVE@media@containerclamp()container-type
VARIABLES--custom-propertyvar()@layer
FUNCTIONScalc()min()max()clamp()var()
Categorised CSS reference covering selectors, box model, sizing, layout, Flexbox, Grid, typography, colour, effects, responsive features, variables and functions

INTERVIEW PREP

Common CSS Interview Questions

Concise, technically accurate answers to the CSS questions that come up most often in interviews and technical assessments.

CHECKLISTS

CSS Accessibility, Performance and Quality Checklists

Three review passes over the same stylesheet. Practical working lists rather than formal audits — the accessibility one is not a complete WCAG assessment.

Accessibility

Performance

Quality

 CSS quality checklistEXAMPLE
ACCESSIBILITY
[ ] Text has sufficient contrast
[ ] Focus indicators remain visible
[ ] Keyboard interaction is supported
[ ] Hover is not the only interaction state
[ ] Text can be resized appropriately
[ ] Content survives zoom
[ ] Motion respects reduced-motion preferences
[ ] Forms remain readable
[ ] Touch targets remain usable
[ ] Information is not conveyed by colour alone
[ ] Responsive layouts remain usable
[ ] Hidden content is handled appropriately
[ ] Animations avoid unnecessary distraction
[ ] Custom controls remain accessible

PERFORMANCE
[ ] Stylesheets are not unnecessarily large
[ ] Unused CSS removed where practical
[ ] Animation kept purposeful
[ ] Fonts optimised and limited
[ ] Expensive effects used sparingly
[ ] Selectors kept reasonable
[ ] DOM complexity kept manageable
[ ] Tested on real devices
[ ] Performance rechecked after visual changes

QUALITY
[ ] Selectors are understandable
[ ] Specificity is manageable
[ ] Layout uses appropriate CSS systems
[ ] Responsive behaviour is tested
[ ] Typography remains readable
[ ] Colours maintain contrast
[ ] Focus states are visible
[ ] CSS is not unnecessarily duplicated
[ ] Variables used where helpful
[ ] Components are reusable
[ ] Breakpoints based on layout needs
[ ] Modern features have fallbacks
[ ] Browser compatibility considered
[ ] Tested with real content

CSS development tools

LEARNING PATH

CSS Learning Roadmap and Practice Projects

A workable order for learning CSS. The cascade appears early on purpose — most frustration with CSS comes from not knowing why a rule lost, not from the properties themselves.

CSS fundamentals
Selectors
Cascade and specificity
Box model
Typography
Colours and units
Display and flow
Positioning
Flexbox
Grid
Responsive design
Media queries
Container queries
Variables and functions
Transitions
Animations
Accessibility
Performance
Architecture
Build projects

These are practice projects to build yourself rather than templates to download. Each isolates a specific set of techniques, and each will surface problems that only appear with real content.

Responsive Profile Card

Box model, typography, shadows and a flexible width.

Navigation Bar

Flexbox alignment, states and a mobile layout.

Responsive Card Grid

Grid with auto-fit and minmax, no media queries needed.

Pricing Section

Consistent cards, emphasis states and alignment.

Grid Gallery

Track sizing, aspect-ratio and object-fit.

Responsive Landing Page

Full page structure across breakpoints.

Accessible Form

Labels, focus states, contrast and error styling.

Design System

Custom properties, tokens and reusable components.

Dashboard Layout

Grid areas, sticky regions and overflow handling.

Portfolio Website

Everything combined, tested with real content.

HTML structure
Base styles and tokens
Typography
Spacing
Layout
Responsive rules
States
Accessibility
Animation
Testing
Optimisation
CSS project workflow from HTML structure and base styles through layout, responsive rules, states, accessibility, testing and optimisation

NEXT TOPICS

Continue Learning Web Development

HTML

Learn how HTML structures content with semantic elements, links, forms, media and accessible markup.

JavaScript

Learn how JavaScript adds behaviour and dynamic interaction to web interfaces.

PHP

Explore server-side web development and dynamic applications.

React

Learn component-based frontend development using JavaScript.

Laravel

Explore PHP-based web application development.

Website APIs

Understand how websites exchange data with external services.

Responsive Design

Learn how layouts adapt across desktop, tablet and mobile.

Website Accessibility

Learn how styling choices support accessible interfaces.

FAQ

CSS: Frequently Asked Questions

Short answers to the questions people ask most about CSS.

Build Better Websites With CSS

Learn how CSS transforms structured HTML into responsive, accessible and visually consistent web experiences using modern layout, typography, responsive design and reusable styling systems.