Understand CSS selectors, the cascade, the box model, units, typography, Flexbox, Grid, positioning, responsive layouts, animations, and practical styling patterns.
What Is CSS?
CSS (Cascading Style Sheets) controls how HTML content looks: colors, fonts, spacing, borders, and layout. HTML says what the content is; CSS says how it should be presented.
Three ways to add CSS
- External stylesheet: a
.cssfile linked from the page. Best for maintainability and caching. - Internal stylesheet: a
<style>block in the head. Fine for small demos. - Inline styles: a
styleattribute on one element. Hard to maintain and hard to override.
Anatomy of a rule
- The selector chooses which elements to style.
- A declaration block in braces holds one or more declarations.
- Each declaration is a property, a colon, a value, and a semicolon.
Linking a stylesheet and writing a rule
/* In HTML: <link rel="stylesheet" href="styles.css"> */
/* selector { property: value; } */
h1 {
color: #1d3557;
font-size: 2rem;
margin-bottom: 0.5rem;
}Selectors
Selectors target elements. Learning a handful of them covers most real-world styling.
- Type:
p,h2,aselect every element of that type. - Class:
.cardselects elements withclass="card"and is reusable. - ID:
#headerselects one unique element; prefer classes for styling. - Attribute:
[type="email"]selects by attribute value. - Pseudo-class:
:hover,:focus-visible,:first-child,:not()select by state or position. - Pseudo-element:
::before,::after,::first-linestyle generated or partial content. - Combinators: descendant (
nav a), child (ul > li), adjacent sibling (h2 + p), general sibling (h2 ~ p).
Common selector patterns
a { color: #2457d6; }
.card { padding: 1rem; }
#site-header { position: sticky; top: 0; }
input[type="email"] { border: 1px solid #94a3b8; }
nav a:hover,
nav a:focus-visible { text-decoration: underline; }
ul > li:first-child { font-weight: 700; }
li:not(.done) { opacity: 1; }
h2 + p { margin-top: 0; }
.btn::after { content: " →"; }The Cascade, Specificity, and Inheritance
When several rules target the same element, the cascade decides which one wins. Understanding it prevents most "why is my style not applying?" problems.
How the browser decides
- Importance and origin:
!importantand user or browser styles come first. - Specificity: more specific selectors beat less specific ones (inline > ID > class/attribute/pseudo-class > element).
- Source order: if specificity ties, the later rule wins.
Inheritance
- Text properties such as
color,font-family, andline-heightinherit by default. - Box properties such as
margin,padding, andborderdo not. - Use
inherit,initial, orunsetto control inheritance explicitly.
Specificity in action
p { color: black; } /* specificity 0,0,1 */
.note { color: green; } /* 0,1,0 beats the rule above */
p.note { color: blue; } /* 0,1,1 beats .note */
#intro { color: red; } /* 1,0,0 beats classes */
/* Prefer low-specificity, class-based selectors and avoid !important. */Units, Colors, and Custom Properties
Choosing units
pxfor precise details such as borders and shadows.remis relative to the root font size and is excellent for spacing and type.emis relative to the current element's font size.%,vw, andvhare relative to the parent or viewport.clamp(min, preferred, max)creates fluid values that never get too small or too large.
Custom properties (CSS variables)
Custom properties store reusable values and make theming simple, including dark mode.
Design tokens with CSS variables and dark mode
:root {
--color-bg: #f8fafc;
--color-text: #0f172a;
--color-brand: #2457d6;
--space-2: 0.5rem;
--space-4: 1rem;
--radius: 0.75rem;
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #0b1220;
--color-text: #e2e8f0;
}
}
body {
background: var(--color-bg);
color: var(--color-text);
font-size: clamp(1rem, 0.95rem + 0.3vw, 1.125rem);
}
.button {
background: var(--color-brand);
padding: var(--space-2) var(--space-4);
border-radius: var(--radius);
}The Box Model
Every element is a rectangular box made of content, padding, border, and margin.
- Content: the text or media itself.
- Padding: space between content and border.
- Border: the edge around the padding.
- Margin: space outside the border, separating elements.
Setting box-sizing: border-box makes the declared width include padding and border, which makes layouts far more predictable.
Border-box reset and box properties
*,
*::before,
*::after {
box-sizing: border-box;
}
.card {
width: 100%;
max-width: 24rem;
padding: 1.5rem;
border: 1px solid #d9e0ea;
margin-inline: auto; /* centers a block horizontally */
margin-block: 2rem;
}Typography and Text Styling
- Use a system font stack for speed or load web fonts with
font-display: swap. - Set
line-heightto around 1.5 for body text. - Keep line length between roughly 45 and 75 characters using
max-width: 65ch. - Use
text-wrap: balancefor headings to avoid awkward line breaks. - Check color contrast; body text should meet at least a 4.5:1 ratio.
Readable typography defaults
body {
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
}
h1, h2, h3 {
line-height: 1.2;
text-wrap: balance;
}
article p {
max-width: 65ch;
}
a {
text-underline-offset: 0.2em;
}Flexbox: One-Dimensional Layout
Flexbox lays out items along one main axis. It is ideal for navigation bars, toolbars, and centering.
Key properties
display: flexturns an element into a flex container.flex-directionsets the main axis:roworcolumn.justify-contentaligns items along the main axis.align-itemsaligns items along the cross axis.gapadds space between items.flex: 1lets an item grow to fill free space;flex-wrap: wrapallows wrapping.
A responsive navigation bar with Flexbox
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0.75rem 1.5rem;
}
.navbar ul {
display: flex;
gap: 1rem;
list-style: none;
margin: 0;
padding: 0;
}
.navbar .spacer { flex: 1; }
/* Perfect centering */
.center {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}CSS Grid: Two-Dimensional Layout
Grid controls rows and columns together. It is the best tool for page layouts and card galleries.
grid-template-columnsdefines the columns;frunits share free space.repeat(auto-fit, minmax(16rem, 1fr))creates a responsive grid without media queries.grid-template-areaslets you name regions of a page layout.gapsets the spacing between rows and columns.- Flexbox and Grid work together; they are not competing systems.
Responsive card grid and a named-area page layout
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
gap: 1rem;
}
.page {
display: grid;
grid-template-columns: 16rem 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
}
.page > header { grid-area: header; }
.page > aside { grid-area: sidebar; }
.page > main { grid-area: main; }
.page > footer { grid-area: footer; }
@media (max-width: 40rem) {
.page {
grid-template-columns: 1fr;
grid-template-areas: "header" "main" "sidebar" "footer";
}
}Positioning and Stacking
staticis the default normal flow.relativeoffsets an element from its normal spot and becomes an anchor for absolute children.absoluteremoves the element from flow and positions it against the nearest positioned ancestor.fixedpositions against the viewport.stickybehaves like relative until a scroll threshold, then sticks.z-indexcontrols stacking, but only works on positioned elements or flex/grid items.
Sticky header and a badge positioned on a card
.site-header {
position: sticky;
top: 0;
z-index: 10;
background: white;
}
.card { position: relative; }
.card .badge {
position: absolute;
top: 0.75rem;
right: 0.75rem;
padding: 0.15rem 0.5rem;
border-radius: 999px;
background: #e11d48;
color: white;
font-size: 0.75rem;
}Responsive Design
Responsive design adapts a page to different screens. Start with a layout that works on narrow screens, then add breakpoints when the content needs them.
The responsive toolkit
- Viewport meta tag in the HTML head.
- Fluid widths using
%,fr,min(),max(), andclamp(). - Flexible media with
max-width: 100%; height: auto. - Media queries to change layout at breakpoints.
- Container queries to style a component based on its own container's width.
- Mobile-first CSS using
min-widthqueries.
Mobile-first media queries and a container query
img, video { max-width: 100%; height: auto; }
.layout { display: grid; gap: 1rem; }
@media (min-width: 48rem) {
.layout { grid-template-columns: 2fr 1fr; }
}
@media (min-width: 64rem) {
.layout { grid-template-columns: 3fr 1fr; }
}
/* Container query: respond to the card's own width */
.card-wrap { container-type: inline-size; }
@container (min-width: 28rem) {
.card { display: grid; grid-template-columns: 8rem 1fr; gap: 1rem; }
}Transitions, Animations, and Motion Preferences
transitionanimates a property change smoothly, such as on hover.@keyframeswithanimationcreates multi-step animations.- Animate
transformandopacityfor the best performance. - Respect users who prefer less motion with
prefers-reduced-motion.
Hover transition and a reduced-motion-safe animation
.card {
transition: transform 160ms ease, box-shadow 160ms ease;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 0.5rem 1.5rem rgb(0 0 0 / 10%);
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: none; }
}
.hero { animation: fade-in 400ms ease both; }
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; transition: none !important; }
}CSS Best Practices
- Use a consistent naming convention such as BEM (
.card__title,.card--featured). - Keep selectors short and low in specificity; avoid
!important. - Define colors, spacing, and radii as custom properties.
- Prefer
rem,gap, and logical properties (margin-inline) for flexible layouts. - Always keep a visible
:focus-visiblestyle. - Organize files by purpose: reset, tokens, layout, components, utilities.
- Test at several widths and with browser zoom at 200%.
Complete Example: Responsive Card Layout
Link this stylesheet to an HTML page containing a .card-grid with several .card children.
Responsive card layout
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
font-family: system-ui, sans-serif;
line-height: 1.6;
color: #202938;
background: #f5f7fb;
}
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
gap: 1rem;
padding: 1.5rem;
}
.card {
padding: 1.25rem;
border: 1px solid #d9e0ea;
border-radius: 0.75rem;
background: white;
box-shadow: 0 0.25rem 1rem rgb(0 0 0 / 5%);
}
.card img {
display: block;
width: 100%;
height: auto;
border-radius: 0.5rem;
}
.button {
display: inline-block;
padding: 0.65rem 1rem;
border-radius: 0.4rem;
background: #2457d6;
color: white;
text-decoration: none;
}
.button:focus-visible {
outline: 3px solid #93b4ff;
outline-offset: 2px;
}
@media (prefers-reduced-motion: no-preference) {
.card { transition: transform 160ms ease; }
.card:hover { transform: translateY(-2px); }
}Frequently Asked Questions
What is the difference between Flexbox and Grid?
Flexbox is mainly one-dimensional and arranges items along a row or column. Grid handles rows and columns together. Choose based on the layout, and combine them when useful.
Should I use pixels or rem?
Pixels are useful for precise details like borders; rem units scale with the root font size and are often better for typography and spacing because they respect user preferences.
What is a media query?
A media query applies CSS conditionally, for example when the viewport is wider than a chosen breakpoint or when the user prefers dark mode or reduced motion.
Why is my CSS not applying?
Usually a more specific selector or a later rule is winning, the selector does not match the element, or the stylesheet is not linked correctly. Inspect the element in browser DevTools to see which rules apply.
What does box-sizing: border-box do?
It makes an element's declared width and height include padding and border, so adding padding does not make the box larger than you set.
When should I use CSS variables?
Use them for values you repeat or want to change in one place, such as colors, spacing, and radii. They also make theming and dark mode easy.