CSS controls how a page looks. You write rules that say “elements matching this selector should look like this”.
h1 {
color: #16181d;
font-size: 2rem;
}Four topics cover most of what you will actually do: selectors, the box model, flexbox and grid.
Selectors#
p { } /* every paragraph */
.card { } /* class="card" */
#header { } /* id="header" */
.card p { } /* paragraphs inside .card */
.card > p { } /* direct children only */
a:hover { } /* while hovered */
input:focus { } /* while focused */
li:nth-child(odd) { } /* every other one */Use classes for nearly everything. Ids are hard to override and cannot be reused.
Which rule wins#
When two rules target the same element, the more specific one wins: inline styles, then ids, then classes, then tags. Equal specificity means the later rule wins.
p { color: blue; }
.intro { color: green; } /* wins over the tag rule */
#lead { color: red; } /* wins over the class rule */If a rule is not applying, this is usually why — see why is my CSS not working.
The box model#
Every element is a box: content, then padding, then border, then margin.
.card {
width: 300px;
padding: 20px;
border: 1px solid #ddd;
margin: 16px;
}By default that box is 342px wide, because padding and border are added to the width. Almost nobody wants that. Fix it once at the top of every stylesheet:
*, *::before, *::after {
box-sizing: border-box;
}Now width: 300px means the box is 300px including padding and border. This single line prevents a large amount of layout confusion.
Flexbox: one direction at a time#
For rows and columns — navigation bars, card rows, centring.
.row {
display: flex;
gap: 16px; /* space between items */
justify-content: space-between; /* along the main axis */
align-items: center; /* across it */
flex-wrap: wrap; /* let items drop to a new line */
}The thing to remember: justify-content works along the direction you set, and align-items works across it. With flex-direction: column, they swap.
Perfect centring, which used to be famously awkward:
.centre {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}Grid: rows and columns together#
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr); /* three equal columns */
gap: 20px;
}
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 20px;
}That second one is the most useful line in modern CSS. It fits as many columns as will fit at 240px minimum, so the layout adapts with no media queries at all.
Rule of thumb: flexbox when items flow in one direction, grid when you are placing things into a structure.
Units#
| Unit | Means | Use for |
|---|---|---|
px |
Fixed pixels | Borders, small fixed spacing |
rem |
Relative to root font size | Font sizes, spacing |
% |
Of the parent | Widths |
vw / vh |
Of the viewport | Full-screen sections |
fr |
A share of grid space | Grid columns |
Prefer rem for text so the layout respects a reader’s browser font-size setting.
Custom properties#
:root {
--accent: #4f46e5;
--radius: 12px;
}
.btn {
background: var(--accent);
border-radius: var(--radius);
}Change the colour in one place and the whole site updates. They also make dark mode straightforward.
Questions people ask#
Should I learn Tailwind or Bootstrap?
After plain CSS, not instead of it. Both assume you know what the underlying properties do; otherwise every layout problem becomes guesswork.
Why does my margin collapse?
Vertical margins between siblings merge into the larger of the two rather than adding up. Use gap in a flex or grid container to avoid the whole issue.
How do I centre a div?
Flexbox on the parent with justify-content: center; align-items: center;. Or for horizontal only, margin: 0 auto with a set width.