Complete CSS Course Module 17: Advanced: Professional CSS: Architecture, Performance and Debugging

Organizing CSS: BEM Naming, File Structure and Best Practices

  • Beginner
  • Lesson 17.1
  • 4 min read
  • 74 of 77 in the course

In short

Organizing CSS well means clear class names like BEM, a simple file structure and a modern reset, so your styles stay easy to read as a project grows. Why does CSS organization matter? A small page with 50 lines of CSS is easy to manage.

Organizing CSS well means clear class names like BEM, a simple file structure and a modern reset, so your styles stay easy to read as a project grows.

Why does CSS organization matter?

A small page with 50 lines of CSS is easy to manage. A real website can have thousands of lines written by several people. Without a plan, you get problems: you are afraid to delete a rule because something might break, two classes have the same name, and you need !important to win every fight.

Good organization is like labeling the boxes when you move house. It takes a few minutes at the start, but it saves hours later.

What is BEM naming in CSS?

BEM stands for Block, Element, Modifier. It is a naming pattern that tells you what a class does just by reading it.

  • Block: a standalone component, like card, navbar or signup-form.
  • Element: a part of a block, joined with two underscores: card__title, card__image.
  • Modifier: a different version or state, joined with two dashes: card--featured, button--large.
<article class="card card--featured">
  <img class="card__image" src="https://picsum.photos/400/250" alt="Laptop on a desk">
  <div class="card__body">
    <h3 class="card__title">Learn CSS Grid</h3>
    <p class="card__text">Build real layouts in one afternoon.</p>
    <a class="card__button" href="#">Read more</a>
  </div>
</article>
.card {
  border: 1px solid #e5e7eb;
  border-radius: 12px;
  overflow: hidden;
  background: white;
}

.card__image {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}

.card__body {
  padding: 1rem;
}

.card__title {
  margin: 0 0 0.5rem;
  font-size: 1.25rem;
}

.card__button {
  display: inline-block;
  padding: 0.5rem 1rem;
  background: #4f46e5;
  color: white;
  border-radius: 6px;
  text-decoration: none;
}

.card--featured {
  border: 2px solid #4f46e5;
  box-shadow: 0 10px 25px rgb(79 70 229 / 0.2);
}

Every selector is a single class, so they all have the same low specificity. You never need long selectors like .sidebar .card div h3. When you see card__title in the HTML, you know exactly where its styles live.

Common mistake: Making "grandchild" names like card__body__title. BEM elements belong to the block, not to other elements. Use card__title even if the title sits inside card__body.

Utility classes: small single-purpose helpers

A utility class does one small job, like .text-center or .mt-0. Frameworks like Tailwind CSS are built entirely from utilities. Many teams mix the two ideas: BEM for components, plus a few utilities for small tweaks.

.text-center { text-align: center; }
.mt-0 { margin-top: 0; }
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

The .visually-hidden utility hides text on screen but keeps it readable for screen readers. It is useful for labels like "Search" on an icon-only button.

A modern CSS reset

Browsers add their own default styles, and they are not always helpful. A reset is a short set of rules at the start of your CSS that gives you a clean, predictable starting point.

/* ==========================================================
   Reset
   ========================================================== */
*, *::before, *::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

body {
  min-height: 100vh;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}

input, button, textarea, select {
  font: inherit;
}

p, h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word;
}

This makes sizes include padding and border, removes surprise margins, stops images from overflowing their containers, and makes form fields use your page font instead of a tiny default.

Tip: Notice the comment header above the reset. Big, clear section comments make long files easy to scan. Many editors also show them in the code outline.

How to structure CSS files in a project

For a small site, one file with clear sections is fine. For bigger projects, split the CSS into files by purpose. Here is a common folder structure:

css/
  main.css            imports everything in the right order
  base/
    reset.css
    tokens.css        variables: colors, spacing, fonts
    typography.css
  layout/
    header.css
    footer.css
    grid.css
  components/
    button.css
    card.css
    form.css
  utilities/
    utilities.css

The main.css file loads the others in order, and you can put each group in a cascade layer:

@layer reset, base, layout, components, utilities;

@import url("base/reset.css") layer(reset);
@import url("base/tokens.css") layer(base);
@import url("base/typography.css") layer(base);
@import url("layout/header.css") layer(layout);
@import url("components/card.css") layer(components);
@import url("utilities/utilities.css") layer(utilities);

Note: Each @import is a separate file download. On a real site, a build tool usually joins them into one file. While you learn, this structure still teaches good habits.

Some other best practices:

  • One component per file, named like the block: card.css holds .card, .card__title and so on.
  • Use variables (design tokens) instead of repeating raw colors and sizes.
  • Keep specificity low: prefer single classes over IDs and long chains.
  • Delete unused CSS when you remove a feature.

Practice exercise

Take a signup form you built before and rename all its classes with BEM. The block is signup. Create elements like signup__field, signup__label and signup__button, and a modifier signup__button--disabled. Add a comment header above the section.

Hint: Every rule should use only one class. If you write .signup label, change it to .signup__label.

Key takeaways

  • BEM means Block (card), Element (card__title) and Modifier (card--featured).
  • Single-class selectors keep specificity low and predictable.
  • Utility classes do one small job and work well alongside components.
  • A modern reset gives every project the same clean starting point.
  • Split CSS by purpose (base, layout, components, utilities) and use clear comment headers.