Color Mode

CSS Design Patterns and Naming Conventions

As websites grew from simple pages to complex applications, developers faced a recurring problem: CSS became increasingly difficult to maintain. What started as a few hundred lines of styles quickly ballooned into thousands, with selectors fighting for specificity, styles mysteriously affecting unintended elements, and teams unable to agree on how to name things. The very flexibility that made CSS powerful also made it chaotic.

CSS design patterns emerged to solve these problems. They provide systematic approaches to organizing, naming, and structuring CSS code. In this lesson, you will learn about two prominent methodologies: BEM (Block Element Modifier) and CUBE CSS (Composition Utility Block Exception). Understanding these patterns prepares you for working with CSS at scale and provides insight into how modern CSS frameworks organize their code.

The Evolution of CSS Organization

In the early 2000s, most websites used simple CSS with minimal organization. Developers named classes descriptively (.red-text, .big-heading) or semantically (.article-title, .sidebar). This worked fine for small sites, but as web applications grew more complex, problems emerged. Styles leaked between components, specificity battles required increasingly complex selectors, and teams struggled to understand which styles were safe to modify.

By the late 2000s and early 2010s, developers began creating systematic methodologies. OOCSS (Object Oriented CSS) introduced the idea of separating structure from skin. SMACSS (Scalable and Modular Architecture for CSS) categorized styles into base, layout, module, state, and theme. BEM emerged from Yandex in 2010, offering a strict naming convention that made relationships between HTML and CSS explicit. More recently, CUBE CSS appeared as a response to modern CSS capabilities, embracing the cascade rather than fighting it.

Today, most CSS frameworks and design systems use some form of these methodologies, often with custom variations. Understanding these patterns helps you work effectively in any codebase, whether you are joining a team that strictly follows BEM or contributing to a project with its own methodology.

BEM: Block Element Modifier

BEM (Block Element Modifier) is a naming convention that makes the relationship between HTML and CSS explicit through class names. Developed by Yandex for large-scale projects, BEM solves the problem of unclear dependencies by encoding structure directly into class names. When you see a BEM class name, you immediately understand what it represents and how it relates to other elements.

Understanding BEM Structure

BEM divides user interfaces into three types of entities:

BEM Naming Convention

BEM uses a specific syntax to name classes:


      .block {}
      .block__element {}
      .block--modifier {}
      .block__element--modifier {}
  

The double underscore (__) separates a block from its element, and the double hyphen (--) separates a block or element from its modifier. This syntax creates long class names, but the verbosity serves a purpose: it eliminates ambiguity. You never have to wonder whether .item belongs to a navigation menu, a list, or something else entirely.

BEM in Practice: Navigation Menu

Consider a navigation menu. In traditional CSS, you might write:


      <nav class="nav">
          <ul class="menu">
              <li class="item active">
                  <a href="/">Home</a>
              </li>
              <li class="item">
                  <a href="/about">About</a>
              </li>
          </ul>
      </nav>
  

The problem here is unclear relationships. Is .menu related to .nav? Can .item be used elsewhere? Is .active specific to navigation or a global state class? BEM eliminates these questions:


      <nav class="nav">
          <ul class="nav__list">
              <li class="nav__item nav__item--active">
                  <a class="nav__link" href="/">Home</a>
              </li>
              <li class="nav__item">
                  <a class="nav__link" href="/about">About</a>
              </li>
          </ul>
      </nav>
  

Now the relationships are explicit. Every class name tells you it belongs to the navigation block, and the modifier clearly indicates the active state is specific to navigation items.


      .nav {
          background-color: oklch(0.95 0 0);
          padding: 1rem;
      }
  
      .nav__list {
          display: flex;
          gap: 2rem;
          list-style: none;
          margin: 0;
          padding: 0;
      }
  
      .nav__item {
          /* Styles for navigation items */
      }
  
      .nav__item--active {
          font-weight: bold;
      }
  
      .nav__link {
          color: oklch(0.3 0 0);
          text-decoration: none;
      }
  
      .nav__link:hover {
          text-decoration: underline;
      }
  

BEM Rules and Best Practices

BEM has specific rules that maintain consistency:

Why Avoid Element Nesting in Names?

You might have a structure like <div class="card"><div class="header"><h2 class="title">. In BEM, the title is .card__title, not .card__header__title. This keeps class names manageable and prevents them from becoming too coupled to DOM structure. If you restructure your HTML, the class names remain meaningful.

Interactive Example: Product Card

Below is an interactive example demonstrating BEM structure with a product card component. Notice how the naming convention makes the component structure immediately clear. Toggle the modifiers to see how BEM makes variations explicit. Open your browser's developer tools to inspect the HTML and see the class names in action:

Headphones

Wireless Headphones

Premium sound quality with active noise cancellation and comfortable over-ear design.

$199.99

Notice how the class names explicitly show relationships:

When to Use BEM

BEM works particularly well in certain scenarios:

BEM Advantages and Challenges

BEM offers significant benefits but also presents challenges. The advantages include explicit relationships (you never wonder what a class does), low specificity (all classes have the same specificity, eliminating cascade conflicts), portability (blocks can move anywhere), and searchability (unique class names make finding styles easy).

The challenges include verbose class names that can make HTML harder to read, the learning curve for teams new to the methodology, and the discipline required to follow the rules consistently. Some developers also find BEM's strictness limiting when dealing with deeply nested components or complex state variations. However, many companies require BEM adherence, and others develop their own variations that relax certain rules while keeping the core benefits.

CUBE CSS: Composition Utility Block Exception

CUBE CSS (Composition Utility Block Exception) represents a different philosophy. Rather than fighting the cascade, CUBE CSS embraces it. Developed by Andy Bell in response to modern CSS capabilities, CUBE CSS uses the cascade, inheritance, and specificity as features rather than problems to solve. Where BEM creates explicit relationships through naming, CUBE CSS creates them through thoughtful CSS organization and layering.

The CUBE CSS Philosophy

CUBE CSS recognizes that CSS has evolved significantly since methodologies like BEM emerged. Modern CSS includes custom properties, logical properties, powerful selectors, and mathematical functions. CUBE CSS leverages these features while organizing styles into four distinct layers, each with a specific purpose and level of specificity.

The key insight of CUBE CSS is that not all styles should have the same specificity or approach. Some styles are global and should cascade broadly. Others are specific and should target precisely. CUBE CSS organizes these different types of styles systematically, creating a layered architecture where each layer builds upon the previous one.

Understanding CUBE Layers

CUBE CSS organizes styles into four layers:

Composition (C)

Composition styles handle layout and the skeletal structure of your interface. They define how elements are arranged in space but do not handle visual styling. Composition classes might control grid layouts, flexbox arrangements, spacing between elements, or responsive behavior. These styles are global and can be reused throughout the application.


      /* Composition handles layout structure */
      .flow > * + * {
          margin-block-start: var(--flow-space, 1em);
      }
  
      .grid {
          display: grid;
          gap: var(--grid-gap, 1rem);
      }
  
      .grid[data-layout="50-50"] {
          grid-template-columns: repeat(2, 1fr);
      }
  
      .cluster {
          display: flex;
          flex-wrap: wrap;
          gap: var(--cluster-gap, 1rem);
          justify-content: var(--cluster-justify, flex-start);
          align-items: var(--cluster-align, center);
      }
  

Utility (U)

Utility classes do one thing and do it well. They are single-purpose classes that apply specific styles, often using important to ensure they always apply. Utilities handle common styling needs like colors, typography, spacing, and visibility. They provide the flexibility to style elements without writing custom CSS.


      /* Utilities are single-purpose and often use !important */
      .text-center {
          text-align: center !important;
      }
  
      .color-primary {
          color: var(--color-primary) !important;
      }
  
      .font-bold {
          font-weight: 700 !important;
      }
  
      .visually-hidden {
          position: absolute !important;
          width: 1px !important;
          height: 1px !important;
          overflow: hidden !important;
          clip: rect(0, 0, 0, 0) !important;
      }
  

Block (B)

Blocks are reusable components with specific styling. Unlike BEM blocks, CUBE CSS blocks focus on visual styling rather than structure (which is handled by composition). Blocks contain the unique styles that make a component look like itself. They use class selectors and semantic element selectors to apply styles.


      /* Blocks define component-specific styling */
      .card {
          background-color: var(--color-surface);
          border-radius: var(--border-radius);
          box-shadow: var(--shadow-sm);
      }
  
      .card > h2 {
          font-size: var(--font-size-lg);
          color: var(--color-heading);
      }
  
      .card p {
          color: var(--color-text);
          line-height: 1.6;
      }
  

Exception (E)

Exceptions handle edge cases and deviations from the norm. They use data attributes or state-based selectors to modify blocks or elements when specific conditions apply. Exceptions are the highest specificity layer and override other styles when necessary.


      /* Exceptions handle special cases and states */
      .card[data-variant="featured"] {
          border: 2px solid var(--color-primary);
      }
  
      .card[data-state="loading"] {
          opacity: 0.6;
          pointer-events: none;
      }
  
      .button[disabled] {
          opacity: 0.5;
          cursor: not-allowed;
      }
  

CUBE CSS in Practice: Blog Post Layout

To understand how CUBE CSS layers work together, consider a blog post layout. The composition layer handles the overall structure, utilities provide quick styling options, blocks define the unique appearance of components, and exceptions handle special states.


      <article class="flow">
          <header class="cluster">
              <h1 class="font-bold">Understanding CUBE CSS</h1>
              <time class="color-secondary">January 26, 2026</time>
          </header>
          
          <div class="post-content">
              <p>First paragraph of content...</p>
              <p>Second paragraph of content...</p>
          </div>
          
          <aside class="callout" data-variant="info">
              <p>Important information...</p>
          </aside>
      </article>
  

The corresponding CSS demonstrates the layered approach:


      /* Composition: handles spacing between elements */
      .flow > * + * {
          margin-block-start: var(--flow-space, 1.5em);
      }
  
      /* Composition: handles header layout */
      .cluster {
          display: flex;
          flex-wrap: wrap;
          gap: 1rem;
          align-items: baseline;
      }
  
      /* Utility: typography */
      .font-bold {
          font-weight: 700 !important;
      }
  
      /* Utility: color */
      .color-secondary {
          color: var(--color-secondary) !important;
      }
  
      /* Block: post content styling */
      .post-content p {
          line-height: 1.7;
          max-width: 65ch;
      }
  
      /* Block: callout component */
      .callout {
          padding: 1.5rem;
          border-left: 4px solid var(--color-border);
          background-color: var(--color-surface);
      }
  
      /* Exception: callout variants */
      .callout[data-variant="info"] {
          border-color: var(--color-info);
          background-color: var(--color-info-bg);
      }
  
      .callout[data-variant="warning"] {
          border-color: var(--color-warning);
          background-color: var(--color-warning-bg);
      }
  

Interactive Example: CUBE CSS Card System

This example demonstrates how CUBE CSS layers work together. The composition classes handle layout (.flow, .cluster), utilities provide quick styling (.font-bold, .color-primary), the block defines component appearance (.cube-card), and data attributes create exceptions. Toggle the controls to see how different layers combine. Open your browser's developer tools to inspect the HTML and see how the layers are applied:

Headphones

Wireless Headphones

Premium sound with active noise cancellation

$199.99

Active Layers:

  • Composition: .flow (vertical spacing), .cluster (horizontal layout)
  • Utilities: .font-bold, .color-primary, .color-secondary
  • Block: .cube-card with all component-specific styling
  • Exceptions: None active (toggle controls above)

Notice how each layer has a specific responsibility:

When to Use CUBE CSS

CUBE CSS excels in specific situations:

CUBE CSS Advantages and Challenges

CUBE CSS offers distinct advantages: it works with CSS rather than against it, leverages modern CSS features effectively, creates flexible and reusable layout patterns, and results in less verbose HTML than BEM. The layered architecture makes it clear where different types of styles belong.

However, CUBE CSS presents challenges. It requires deeper CSS knowledge to use effectively, particularly understanding specificity and the cascade. The flexibility that makes it powerful can also make it easier to create conflicting styles if the team does not follow the methodology consistently. Some developers find the reliance on element selectors within blocks makes refactoring HTML structure more difficult than with BEM's class-based approach.

Component-Based Thinking

Both BEM and CUBE CSS encourage thinking in components, though they approach it differently. Understanding component-based thinking is essential for modern web development, as it forms the foundation for how frameworks organize code and how design systems structure interfaces.

What Are Components?

A component is a self-contained, reusable piece of user interface. Components can be simple (a button) or complex (a data table with sorting and filtering). The key characteristic is that a component encapsulates everything it needs: structure (HTML), presentation (CSS), and often behavior (JavaScript).

Component-based thinking means breaking interfaces into discrete pieces that can be developed, tested, and reused independently. Rather than thinking about pages, you think about the components that make up those pages. This approach scales better as projects grow because you can add new pages by composing existing components rather than writing everything from scratch.

Separating Concerns in Components

Well-designed components separate different types of responsibilities:

BEM handles separation through strict naming conventions. Each BEM class clearly indicates what it styles. CUBE CSS handles separation through its layered architecture, with composition handling layout, blocks handling presentation, and exceptions handling state.

Component Organization Strategies

Organizing component CSS requires deciding how to structure files and where to place different types of styles. Common approaches include:

Modern build tools allow you to choose the approach that makes sense for your project. The important principle is consistency: pick an approach and follow it throughout the codebase.

Naming Conventions Beyond BEM and CUBE

While BEM and CUBE CSS are prominent methodologies, companies often develop their own approaches. Some teams use simplified BEM (single hyphen instead of double), others use prefixes to indicate component types, and some create hybrid approaches that mix utility classes with component classes.

The key is that whatever naming convention you use, it should be consistent and documented. New team members should be able to understand the naming convention quickly, and the convention should scale as the project grows. Whether you use BEM, CUBE CSS, or something else entirely, the goal is the same: make CSS maintainable, understandable, and scalable.

Comparing Methodologies

BEM and CUBE CSS represent different philosophies for solving the same problem. Understanding when to use each approach helps you make informed decisions about CSS architecture. Neither methodology is universally better; each has strengths that shine in different contexts.

Philosophy and Approach

BEM treats the cascade as a problem to avoid. It uses class selectors exclusively and ensures every element has a unique class name. This isolation makes components truly independent but requires more classes and longer names. BEM says: "Make every relationship explicit, and you will never be surprised by specificity conflicts."

CUBE CSS treats the cascade as a feature to embrace. It uses inheritance strategically, allows element selectors within blocks, and creates reusable layout patterns that work anywhere. CUBE CSS says: "Organize your styles into layers, and the cascade becomes predictable and powerful."

Team and Project Considerations

Team size and CSS experience influence which methodology works better. BEM excels with large teams or teams new to CSS architecture. The explicit naming requires no assumptions about CSS knowledge. You can hand a BEM class to any developer, and they will know exactly what it styles and how it relates to other classes. CUBE CSS works better with smaller teams or teams with strong CSS fundamentals. Understanding when to use element selectors versus classes, and how the layers interact, requires more CSS expertise.

Project longevity also matters. For long-lived projects that many developers will touch over years, BEM's explicitness pays dividends. Five years from now, when the original developers have moved on, new team members can still understand the codebase quickly. For shorter projects or projects with stable teams, CUBE CSS's flexibility and lighter HTML might be more valuable.

Technical Trade-offs

BEM produces more verbose HTML but simpler CSS. Every element gets a class, and every class has a clear purpose. This makes HTML longer but also makes finding and modifying styles straightforward. Search for the class name, and you find exactly one set of styles that apply.

CUBE CSS produces cleaner HTML but more complex CSS. You use fewer classes, but the CSS requires more thought to write effectively. The layered architecture means understanding how styles interact across composition, utilities, blocks, and exceptions. This complexity is manageable for experienced developers but can trip up those newer to CSS.

Framework Integration

Modern CSS frameworks like Tailwind CSS take a different approach entirely, using utility-first CSS with minimal custom components. Understanding both BEM and CUBE CSS helps you appreciate why frameworks make the choices they do. Tailwind is essentially an extreme version of CUBE CSS utilities, while component libraries like Bootstrap historically followed BEM-like naming for their components.

When you understand these methodologies, you can work effectively with any framework. You recognize the patterns and principles even when the specific implementation differs.

Making the Choice

Choosing between BEM and CUBE CSS depends on your specific context. Use BEM when you need strict isolation, have a large team, are building a component library, or want searchability and explicitness. Use CUBE CSS when you want to leverage modern CSS, have a team comfortable with the cascade, are building content-heavy sites, or prefer flexible composition patterns.

Remember that many companies use neither pure BEM nor pure CUBE CSS. They create their own variations that take principles from both. The important thing is not which methodology you choose but that you choose one consistently. A well-applied methodology, even an imperfect one, is better than no methodology at all.

Check Your Understanding

Test your understanding of BEM and CUBE CSS by refactoring a component. You will see a navigation menu written with generic class names. Refactor it using both BEM and CUBE CSS approaches, then reflect on the differences. This exercise helps you internalize how each methodology structures code and makes different trade-offs.


          <!-- Original navigation with generic classes -->
          <nav class="nav">
              <div class="container">
                  <a href="/" class="logo">Brand</a>
                  <ul class="menu">
                      <li class="item active">
                          <a href="/">Home</a>
                      </li>
                      <li class="item">
                          <a href="/products">Products</a>
                      </li>
                      <li class="item">
                          <a href="/about">About</a>
                      </li>
                  </ul>
                  <button class="toggle">Menu</button>
              </div>
          </nav>
  
          <!-- TODO: Refactor using BEM -->
          <nav>
              <!-- Your BEM implementation here -->
          </nav>
  
          <!-- TODO: Refactor using CUBE CSS -->
          <nav>
              <!-- Your CUBE CSS implementation here -->
          </nav>
      

Key Concepts Summary

CSS design patterns emerged to solve real problems: conflicting styles, unclear relationships, and unmaintainable codebases. BEM provides explicit relationships through strict naming conventions, using block__element--modifier syntax to make every dependency clear. CUBE CSS embraces the cascade through a layered architecture, organizing styles into Composition, Utility, Block, and Exception layers that work together predictably.

Both methodologies encourage component-based thinking, where you break interfaces into reusable pieces. The difference lies in how they achieve isolation and reusability. BEM isolates through naming; CUBE CSS isolates through thoughtful organization. Understanding both approaches prepares you for working in any codebase and helps you understand the principles behind modern CSS frameworks.

Remember that many companies use variations of these methodologies or create their own approaches. The specific syntax matters less than the underlying principles: make relationships clear, organize systematically, and choose consistency over perfection. As you build more projects, you will develop intuition for which patterns work best in different contexts.

Explore Further

To deepen your understanding of CSS architecture and naming conventions, explore these topics independently:

As you explore, pay attention to the trade-offs each approach makes. No methodology is perfect for every situation. The goal is to build your architectural intuition so you can make informed decisions about CSS organization in your own projects.