Professional CSS WorkflowPro· 45 min read

CSS Architecture: BEM & File Structure

Anyone can style a single page. The skill that gets you hired is keeping CSS sane on a large, team-built codebase — and that means a naming method (BEM) and a file structure (the 7-1 pattern).

What you will learn

  • Name classes consistently with BEM
  • Avoid specificity and clash problems by design
  • Organise files with the 7-1 / ITCSS approach

Why naming matters

On a small page, class names like .red or .box2 work fine. On a real product with dozens of components and several developers, vague names cause chaos: styles leak between components, two people pick the same class name, and nobody dares delete anything for fear of breaking another page. A naming methodology prevents this by giving every class a clear, predictable, self-documenting name.

BEM — Block, Element, Modifier

BEM is the most popular naming convention. It splits every class into up to three parts:

  • Block — a standalone component. Example: card, menu, button.
  • Element — a part inside a block, joined with two underscores. Example: card__title, card__image.
  • Modifier — a variation of a block or element, joined with two hyphens. Example: card--featured, button--large.

So the pattern is block__element--modifier. The double underscore and double hyphen are deliberate — they make the three roles instantly recognisable. Here is a card written the BEM way:

A card named with BEM
<style>
  .card { border:1px solid #e6e8f0; border-radius:12px; padding:16px; background:#fff; }
  .card__title { color:#4338ca; margin:0 0 6px; font-size:18px; }
  .card__text  { color:#5b6178; margin:0; }
  /* Modifier: a featured variation of the same block */
  .card--featured { border-color:#4338ca; background:#eef2ff; }
</style>

<div class="card card--featured">
  <h3 class="card__title">Featured Plan</h3>
  <p class="card__text">A featured card uses the modifier class for its variation.</p>
</div>
<div class="card">
  <h3 class="card__title">Standard Plan</h3>
  <p class="card__text">The same block and elements, without the modifier.</p>
</div>
Live preview

Read the class names and the structure is obvious without seeing the CSS:

  • card is the block (the component). Both cards use it.
  • card__title and card__text are elements inside the block — the double underscore says “this belongs to card”.
  • card--featured is a modifier — the double hyphen says “this is a variation of card”. The first card adds it (so it gets the indigo treatment); the second does not.
  • Crucially, every selector is a single class — flat and low-specificity. There are no long .card .title chains, so nothing leaks and nothing fights over specificity.

Note: Output: Two cards using identical BEM markup. The first also carries the card--featured modifier, so it shows an indigo border on a light-blue background; the second is the plain version. The class names alone tell you exactly what each piece is.

Watch out: The BEM separators are specific: two underscores for an element (card__title) and two hyphens for a modifier (card--featured). A single underscore or hyphen is just part of a name and does not signal the BEM role.

File structure: the 7-1 pattern

Naming solves clashes; file structure solves “where does this style live?”. The popular 7-1 pattern (used heavily with Sass) splits your CSS into seven folders plus one main file that imports them all:

FolderHolds
abstracts/Variables, mixins, functions (no CSS output on their own)
base/Resets, base element styles, typography
components/Buttons, cards, forms — one file per component
layout/Header, footer, grid, navigation
pages/Page-specific styles
themes/Light/dark or brand themes
vendors/Third-party CSS (frameworks, libraries)

A single main.scss then imports everything in order, so the cascade is predictable. A trimmed example:

main.scss ties the 7-1 folders together
// main.scss — the one file you compile
@use "abstracts/variables";
@use "abstracts/mixins";
@use "base/reset";
@use "base/typography";
@use "components/button";
@use "components/card";
@use "layout/header";
@use "layout/footer";

Each line pulls in one partial, grouped by purpose and ordered from most general (variables, resets) to most specific (components, layout). When you need to change a button, you know exactly where to look: components/button. New developers can navigate the codebase on day one. This is the difference between “styles a page” and “works on a team codebase”.

Note: A related idea is ITCSS (Inverted Triangle CSS), which orders styles from low-specificity and far-reaching (settings, tools, generic) down to high-specificity and narrow (components, utilities). It pairs naturally with cascade layers from the Modern CSS unit.

Tip: A reliable rule of thumb: one component, one file, one BEM block. Name the file after the block (_card.scss for the card block), and every class inside starts with card. Predictable names plus predictable files is what keeps large CSS maintainable.

Q. In BEM, what does the class card__title--large represent?

Answer: BEM reads block__element--modifier: card is the block, title is an element inside it (double underscore), and large is a modifier (double hyphen).

✍️ Practice

  1. Take an existing component and rename all its classes to BEM (block__element--modifier), using only single-class selectors.
  2. Sketch a 7-1 folder structure for a small site and write the main.scss that @uses each partial.

🏠 Homework

  1. Refactor your landing page’s CSS to BEM naming and reorganise it into 7-1 folders combined by one main file.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →