195 Structuring CSS with the BEM pattern [4d]

Updated . Posted . Visible to the public.

We are using the BEM pattern ("Block, Element, Modifier") to structure our CSS in all new projects. We try to migrate legacy projects to BEM, block-by-block.

Important

Work on this lesson in teacher mode.

Learning goals

  • You can explain why unstructured CSS becomes hard to maintain — global scope, cascading side effects, selectors coupled to markup — and what a naming convention like BEM does about it.
  • You can explain the three BEM concepts — block, element, modifier — and write our naming convention for each: .block, .block--element, .block.-modifier.
  • You can explain how a BEM naming convention prevents accidental style inheritance, e.g. a .title rule of one component bleeding into nested or unrelated markup.
  • You can decide where to draw the line between blocks: when something is a reusable block of its own and when it is an element of a larger block. You cut blocks by responsibility, like well-designed Ruby classes.
  • You can build a screen from a small set of reusable blocks, with few elements and no wrappers that exist only for styling.
  • You keep a block's own styling separate from its positioning on a particular screen.
  • You can recognize BEM-structured markup (and its absence) by inspecting a page.
  • You can migrate existing CSS to BEM step by step, block by block.

Resources

Read what's new to you, skim what's familiar, skip what you already master. Stop when you can meet the learning goals.

Your agent can also generate an overview, a tutorial or an explanation for anything here, tailored to what you already know. Just ask.

Cutting block boundaries

Deciding what becomes a block is the hardest part of BEM — the naming is easy. Cut blocks by responsibility, the way you cut Ruby classes: each block does one thing. Neither extreme works: one god block serves no second screen, and blocks cut too small can't stand on their own without wrappers.

It is often a good idea to have a dedicated layout block whose only responsibility is dividing the screen between global regions — typically things like a top bar, a sidebar or the main content area. Content blocks like a navigation or a list then only care about their own contents — how their items are displayed, what the current item looks like — and never about their own position or outer margins.

Avoid unnecessary wrappers: use as few HTML elements as possible, but not fewer. A wrapper that exists only for styling is usually a sign of a wrong cut.

A useful check: try to explain to someone else what a block does. If you find yourself meandering through a convoluted explanation with tons of context, or chaining responsibilities with "and" again and again, you probably made the wrong cut.

Exercises

Deskbot

Re-implement the look of this screen from Deskbot, the hot-desking app you use every day to book tables, parking and food:

Image

  • Work in your exercises repository, with static HTML and CSS files — no app framework for this one.
  • Invent enough fake weeks and days to lay out the list with real-looking data. Notice how the day rows come in several states — today, booked, absent — and how the same goes for the toggles.
  • Make sure that your implementation uses a clear set of BEM blocks with the right boundaries (see Cutting block boundaries above). Blocks like the day rows should be reusable for other screens.
  • In your README, list each block with its responsibility in one sentence. If a sentence needs several "and"s, reconsider the cut.

What counts here is your HTML and CSS structure — we want to see how you cut. The page should look roughly like the screenshot: close enough to prove your HTML structure can carry the real layout. The test: pixel perfection must be reachable later by editing only CSS rules, never the HTML. You don't need responsive behavior, JavaScript, or hover and animation polish.

You'll learn proper layout technique in the next card. Until then you may use display: flex for rows and columns without understanding it deeply yet — ask your agent for just enough CSS to move on, and don't worry if your layout code feels clumsy.

Note

  • You have access to Deskbot's repository, but don't peek at its actual HTML and CSS — it is a Bootstrap frontend, not BEM, so you would copy the wrong structure anyway.
  • You are likely to have trouble deciding where to draw the line between the blocks. E.g. a structure could either be two independent blocks or a block that contains two elements. There is not always a right answer to that. Discuss the pros and cons of each approach with your mentor.

MovieDB

Restructure the views and CSS of MovieDB so every screen is built from a small set of reusable BEM blocks:

  • Cut by responsibility (see Cutting block boundaries above): a layout block owns the screen division; content blocks never position themselves or carry outer margins.
  • No wrappers that exist only for styling.
  • In your merge request description, list each block with its responsibility in one sentence.
Profile picture of Henning Koch
Henning Koch
Last edit
Henning Koch
Attachments
Keywords
advanced
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra Curriculum (2015-09-08 16:23)