Tailwind, Bootstrap, Material UI, Chakra — every popular CSS framework is, at its core, an abbreviation for CSS you could already write. The demo at the top of this post is one live example: four cards that fold into one, two, three, or four columns depending on the window — in a single line of CSS, no media queries, no breakpoints, no framework. Learn the foundations and every codebase becomes readable: yours, a colleague's, an open-source project you cloned ten minutes ago.
1. Flexbox — one line for perfect alignment
Flexbox is for laying items in a single direction — a row or a column. Three properties cover 95% of use cases:
.row {
display: flex;
gap: 1rem;
align-items: center;
justify-content: space-between;
}
Read it as a sentence:
display: flex— "lay children in a row."gap: 1rem— "leave 1rem between them." (Margins no longer needed.)align-items: center— "vertically centered."justify-content: space-between— "spread to both ends."
Tailwind equivalent: flex gap-4 items-center justify-between. Same four words.
2. Grid — two dimensions in one line
Grid is flexbox's older, more powerful sibling. It handles columns and rows at once. This single declaration is what powers the demo above:
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1rem;
}
Read: "make as many columns as fit; each one at least 180px wide, growing to fill space." Resize the demo and watch the columns reflow themselves. That's it. That's the trick.
3. Custom properties — your own design system
Custom properties (CSS variables) let you define tokens once and reuse them. This is what every framework's "theme" system is, under the hood:
:root {
--color-primary: #5d00ff;
--color-text: #2a1a4a;
--space: 1rem;
--radius: 12px;
}
.button {
background: var(--color-primary);
color: white;
padding: var(--space) calc(var(--space) * 1.5);
border-radius: var(--radius);
}
body.dark {
--color-text: #eee;
}
Change --color-primary in one place; every button, badge,
and link updates. And body.dark shows the superpower:
variables cascade. Override them in a context, and
every element under that context picks up the change. No JavaScript,
no rebuild.
4. clamp() — responsive without breakpoints
Media queries are fine, but clamp(min, ideal, max) is often
all you need:
h1 {
font-size: clamp(1.5rem, 4vw + 1rem, 3rem);
line-height: 1.2;
}
.container {
width: clamp(320px, 90%, 1200px);
margin: 0 auto;
padding-inline: clamp(1rem, 4vw, 3rem);
}
Read clamp as "grow with the viewport, but never smaller
than the first number or larger than the last." That one function
replaces three breakpoints.
Five tricks worth carrying
The parent selector: :has()
/* Highlight any form that contains an invalid field */
form:has(input:invalid) { border-color: red; }
/* Style a card that contains an image differently */
.card:has(img) { padding-top: 0; }
/* Logical AND: article with both heading and paragraph */
article:has(h2):has(p) { /* ... */ }
For twenty years the web missed a "parent selector." It's here now, and it changes how you think about layout: styles can depend on what an element contains.
Intrinsic aspect ratios
.video { aspect-ratio: 16 / 9; }
.square { aspect-ratio: 1; }
No more padding-bottom hacks. The element reserves space for the correct shape before content even loads — so the page doesn't jump when it arrives.
color-mix() — no preprocessor needed
.ghost {
background: color-mix(in srgb, var(--color-primary) 20%, transparent);
border: 1px solid color-mix(in srgb, var(--color-primary) 40%, transparent);
}
Sass and Less existed largely because CSS lacked this. It's built in now. You can mix, lighten, and darken without a build step.
scroll-margin-top — anchors that respect sticky headers
h2 { scroll-margin-top: 6rem; }
Click a #section link on a site with a sticky header and
you've probably watched the heading disappear behind the header.
Five words of CSS fix it forever — the browser scrolls 6rem short of
the element.
min-content, max-content, fit-content()
.sidebar { width: fit-content(320px); }
.caption { width: max-content; }
.nowrap { width: min-content; }
Widths that respond to the actual text inside. max-content
= "as wide as needed for one line." min-content = "as
narrow as possible without overflow." fit-content(n) = "fit
to content, but don't exceed n." You'll use these more than you'd
expect, once you know they exist.
Same card, two ways
A common pattern — a bordered card with a hover accent. In Tailwind:
<div class="rounded-2xl border border-white/10 bg-white/5 p-6
hover:border-primary/40 transition-colors">
...
</div>
The same thing in vanilla CSS:
<div class="card">...</div>
<style>
.card {
border-radius: 1rem;
border: 1px solid rgba(255,255,255,0.1);
background: rgba(255,255,255,0.05);
padding: 1.5rem;
transition: border-color 0.2s;
}
.card:hover {
border-color: color-mix(in srgb, #5d00ff 40%, transparent);
}
</style>
Identical output. One is terser, the other is explicit. Which you prefer is taste — but understanding both is not optional if you want to read the world's code.
When to reach for a framework
Frameworks earn their weight in exactly these situations:
- Team of five or more — shared vocabulary reduces bikeshedding.
- Design system with many tokens — a framework enforces consistency.
- Strict tree-shaking / purge — Tailwind's JIT ships only the classes you use.
For a one-person project, a blog, a landing page, or a small tool — plain CSS is faster to write, smaller to ship, and easier to debug. It's also kinder to the reader: your code reads the same to a beginner as it does to an expert.
On measure
The mizan — measure, proportion, balance — is an old idea. Markets use it; architects use it; the Qur'an repeats it ("Give full measure, do not be of those who cause loss", Mutaffifîn 83:1-3). CSS is, in the end, a tiny mizan for the screen: rhythm, spacing, weight, contrast. A card that respects its neighbors, a line length that respects the eye, a column count that respects the window. The tools matter less than the care you put into the measure.
Takeaways
- Flexbox and Grid handle 95% of layouts, in one declaration each.
- Custom properties give you a design system without tooling.
clamp(),:has(),color-mix(),aspect-ratio, andscroll-margin-topquietly modernized CSS.- Frameworks are opinions wrapped around the same language you already know.
The more you learn the foundations, the less any one framework can box you in. Write simple CSS, name your tokens well, and your style sheets will age gracefully — long after today's frameworks have been replaced by the next ones.
Next up: "Why your site loads slow (and the five fixes that actually matter)" — waterfall-driven performance, no premature optimization.
Keep the surface simple. Keep the craft honest.