Visible and accessible focus
Here's a mindset shift: until now you wrote CSS so it would look good. Now you'll write it so everyone can use it, no matter how they navigate. That's accessibility, and it separates people who make websites from people who make websites properly.
Focus indicates which element will receive the keyboard. ⚠️ Classic trap:
killing it with outline: none "because it's ugly". If you remove it without an
alternative, you blindfold everyone who navigates with a keyboard, and that's a
lot of people. :focus-visible solves the age-old dilemma: it shows the focus
ring when navigating with the keyboard, but not on every mouse click. Best of
both worlds.
.button:focus-visible {
outline: 3px solid #2563eb;
outline-offset: 2px;
}
Respecting user preferences
The operating system exposes preferences that CSS can read with media queries:
/* Reduce or remove animations for whoever asks for it (dizziness, vestibular) */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
/* Adapt the theme to the system's dark mode */
@media (prefers-color-scheme: dark) {
:root {
--background: #0f172a;
--text: #e2e8f0;
}
}
Contrast
⚠️ Classic trap: that light gray on white that looks so elegant on your brand new screen in broad daylight is, for many people, unreadable. Text must have enough contrast against its background. The WCAG AA guidelines ask for a minimum ratio of 4.5:1 for normal text and 3:1 for large text. Don't eyeball it: always check the contrast with a tool.
Architecture: BEM
As CSS grows, the biggest difficulty is not writing it but maintaining it
without it collapsing on top of you. ⚠️ Classic trap: magic names like
.blue2 or .finalBox that even you can't decode a week later. BEM
(Block, Element, Modifier) is a naming convention that makes your CSS
predictable and readable at a glance:
.card { } /* Block: the component */
.card__title { } /* Element: a part of the block (double underscore) */
.card--featured { } /* Modifier: a variant (double dash) */
<article class="card card--featured">
<h2 class="card__title">Hello</h2>
</article>
Controlling specificity
Specificity decides which rule wins when several affect the same element. A good architecture keeps it low and flat:
- Prefer classes over IDs or chained tag selectors.
- Avoid over-nesting:
.menu .list .item ais fragile and hard to override. - Reserve
!importantfor exceptional cases; it is usually a symptom of uncontrolled specificity.
BEM, by using flat single-level classes, keeps specificity constant and
spares you the !important wars (the ones where only you lose).
And with this you close the Web track. Stop for a second and look back: you
started with an <h1> and now you handle semantics, layout, forms, animations,
accessibility and maintainable modern CSS. You can build complete, well-made
interfaces. Genuinely, congratulations. 🎉
The only thing they're missing is motion: reacting to a click, validating, updating data without reloading the page... that's JavaScript, and it's exactly what comes next. You're halfway there, and the best part is just starting.