Best Practices and Common Mistakes
Every stylesheet starts tidy. Without a few good habits, every stylesheet ends up a junk drawer.
You know the junk drawer. Every house has one. It started as "the drawer for batteries," and now it holds batteries, rubber bands, three dead pens, a single mysterious key, and takeout menus from restaurants that closed years ago. Nobody decided to make it a mess. It just happened, one "I'll put this here for now" at a time.
Stylesheets do exactly the same thing. A quick fix here, an !important there, a rule copied from somewhere else "just to get it working." A year later, nobody dares delete anything because nobody knows what it does.
This lesson is about the habits that keep your CSS from becoming a junk drawer, and the mistakes that most often turn it into one.
Organize the file
A good stylesheet reads from general to specific, like a well-organized closet: the big stuff at the back, the everyday items at the front.
/* 1. Design tokens: colors, spacing, fonts */
:root { ... }
/* 2. Reset and base: box-sizing, body, headings, links */
*, *::before, *::after { box-sizing: border-box; }
body { ... }
/* 3. Layout: containers, page grid, header and footer */
.container { ... }
/* 4. Components: buttons, cards, nav, forms */
.button { ... }
.card { ... }
/* 5. Utilities: small single-purpose helpers */
.visually-hidden { ... } /* the pattern from Display */This order also works with the cascade you learned in The Cascade and Specificity: broad base styles come first, and more specific component styles come later, so they naturally win ties. On bigger projects, each of these sections often becomes its own file.
Name classes by purpose
/* Describes appearance: breaks when the design changes */
.blue-text { ... }
.big-box-left { ... }
/* Describes purpose: survives a redesign */
.price { ... }
.product-card { ... }
.site-nav { ... }If the brand color changes from blue to green, .blue-text becomes a lie. .price is still true. It's the same thinking as choosing HTML elements for their meaning in Semantic HTML.
Many teams use a naming pattern to show how classes relate. A popular one is called BEM (Block, Element, Modifier):
.card { ... } /* the block: the component itself */
.card__title { ... } /* an element: a part of the block */
.card--featured { ... } /* a modifier: a variation of the block */The double underscores and hyphens look odd at first, but they make it instantly clear that .card__title belongs to .card. You don't have to use BEM. Just pick a consistent convention and stick to it.
Keep specificity low and flat
This is the habit that prevents the most pain. Compare:
/* Deep and specific: hard to override, breaks if the HTML changes */
#main .content section article div.card h3.title {
color: #2f6f8f;
}
/* Flat and simple */
.card__title {
color: #2f6f8f;
}The first selector has a huge specificity score and depends on the exact HTML structure. Move the card out of that article, and the style disappears. Try to override it for one special card, and you need an even longer selector. That's how specificity wars start.
The rule of thumb: style with single classes whenever you can. Avoid ids for styling. Avoid long chains. And treat !important as a fire alarm, not a tool.
Common mistakes, and their fixes
Here's a gallery of the anti-patterns you'll see most often in real code. If you've written a few of these already, welcome to the club. Everyone has.
Fixed heights on content.
/* Breaks as soon as the text is longer, or the reader zooms in */
.card { height: 200px; }
/* Let content decide, with a floor if needed */
.card { min-height: 200px; }Magic numbers. margin-top: 37px because "it looked right." Six months later, nobody knows why it's 37, and it breaks when a font changes. Use your spacing scale from CSS Variables, and if a number truly has a reason, leave a comment explaining it.
Pixels for text. Covered in Units: it overrules readers who set a larger text size. Use rem.
Removing focus outlines. outline: none with no replacement. Covered in Hover, Focus, and Interactive States. Never.
Positioning everything absolutely. It looks perfect at one screen size and falls apart at every other. Use flexbox and grid for layout, and positioning for small overlays only.
Desktop-only thinking. Building the whole page on a big monitor and only checking a phone at the end. Start mobile-first, and check small screens as you go.
Background images for content. A team photo as a background-image has no alt text. Content images belong in HTML.
Copy-pasting instead of reusing. Five nearly identical button rules with slightly different paddings. Make one .button component, and use modifiers for the variations.
Dead code. Rules for elements that were deleted months ago. Your browser's developer tools have a Coverage panel that highlights unused CSS. Clean it out occasionally.
Debugging a layout that won't cooperate
Every developer, at every level, has sat staring at a layout that just won't behave. Here's a calm, step-by-step approach that works far better than randomly changing values:
Inspect it. Right-click, Inspect. Is your rule even being applied? Is it crossed out, meaning another rule is winning? (Debugging Basics walks through the tools.)
Look at the box. Check the box model diagram. Is there a margin or padding you didn't expect? Maybe from the browser's default styles?
Outline everything. Temporarily add this to see every box on the page:
css* { outline: 1px solid red; }Suddenly you can see exactly which box is too wide or overflowing. (Outline, not border, so it doesn't change any sizes. Remember why?)
Check the parent. Flex and grid properties go on the container, not the items. Is the thing you're styling actually the direct child you think it is?
Isolate it. Copy the broken piece into an empty playground, like the editors on these pages. If it works there, something else on the page is interfering.
Take a break. Honestly. A surprising number of CSS bugs solve themselves after a ten-minute walk.
Validate
Just like HTML, CSS has a validator. The W3C CSS Validation Service (jigsaw.w3.org/css-validator) catches typos like colour, missing semicolons, and invalid values. Browsers silently ignore CSS they don't understand, so a typo can hide for weeks. The validator finds it in seconds.
Try it: bug hunt
This card "works," sort of. But it's full of the mistakes from this lesson. How many can you spot and fix?
CSS
Preview
Try it yourself
Fix every problem you can find. Here's a checklist so you know when you're done (try first, then peek):
- The heading selector is far too specific and uses
!important. Replace it with a single class, like.card__title, and update the HTML. .blue-boxdescribes appearance. Rename it to something like.card.- The card is absolutely positioned with magic numbers. Remove the positioning.
- The fixed
heightmakes the text overflow. Remove it, or usemin-height. - Add
box-sizing: border-boxso the width means what it says. - The font sizes are in pixels. Convert them to
rem. - The paragraph text is too low-contrast. Darken it.
- The button's focus outline was removed. Replace it with a visible
:focus-visiblestyle.
If you found all eight, you've got the eye of a code reviewer. If you found four, that's still four more than you'd have spotted a month ago.
Check your understanding
Up next
You've heard "JavaScript can do that" several times in this track. In the next lesson, you'll see exactly where CSS hands off to JavaScript, and how they work together, in Where CSS Meets JavaScript.
