惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

月光博客
月光博客
人人都是产品经理
人人都是产品经理
C
Check Point Blog
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 聂微东
Help Net Security
Help Net Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LINUX DO - 最新话题
Cloudbric
Cloudbric
博客园 - Franky
阮一峰的网络日志
阮一峰的网络日志
O
OpenAI News
V2EX - 技术
V2EX - 技术
H
Hacker News: Front Page
Hacker News: Ask HN
Hacker News: Ask HN
Google DeepMind News
Google DeepMind News
PCI Perspectives
PCI Perspectives
爱范儿
爱范儿
Hacker News - Newest:
Hacker News - Newest: "LLM"
Martin Fowler
Martin Fowler
S
Schneier on Security
Webroot Blog
Webroot Blog
Know Your Adversary
Know Your Adversary
云风的 BLOG
云风的 BLOG
H
Help Net Security
I
InfoQ
Simon Willison's Weblog
Simon Willison's Weblog
雷峰网
雷峰网
J
Java Code Geeks
V
Visual Studio Blog
MyScale Blog
MyScale Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
C
CERT Recently Published Vulnerability Notes
Google Online Security Blog
Google Online Security Blog
Spread Privacy
Spread Privacy
有赞技术团队
有赞技术团队
The GitHub Blog
The GitHub Blog
Engineering at Meta
Engineering at Meta
V
V2EX
Apple Machine Learning Research
Apple Machine Learning Research
www.infosecurity-magazine.com
www.infosecurity-magazine.com
A
About on SuperTechFans
S
SegmentFault 最新的问题
H
Hackread – Cybersecurity News, Data Breaches, AI and More
TaoSecurity Blog
TaoSecurity Blog
WordPress大学
WordPress大学
S
Securelist
P
Proofpoint News Feed

CSS Wizardry

Front-End’s Missing Metric: The TBT Window Meet Your Users Where They Are with Obs.js Better Browser Caching with No-Vary-Search font-family Doesn’t Fall Back the Way You Think What Is CSS Containment and How Can I Use It? When All You Can Do Is All or Nothing, Do Nothing Obs.js: Context-Aware Web Performance for Everyone Low- and Mid-Tier Mobile for the Real World (2025) The Fastest Site in the Tour de France Making Sense of the Performance Extensibility API Why Do We Have a Cache-Control Request Header? HTML Is Not a Programming Language… Build for the Web, Build on the Web, Build with the Web Licensing Code on CSS Wizardry A Layered Approach to Speculation Rules Designing (and Evolving) a New Web Performance Score Core Web Vitals Colours The Ultimate Contract Templates for Tech Consultants: Protect Your Business and Get Paid Optimising for High Latency Environments Cache Grab: How Much Are You Leaving on the Table? blocking=render: Why would you do that?! Correctly Configure (Pre) Connections The Three Cs: 🤝 Concatenate, 🗜️ Compress, 🗳️ Cache What Is the Maximum max-age? How to Clear Cache and Cookies on a Customer’s Device The Ultimate Low-Quality Image Placeholder Technique Core Web Vitals for Search Engine Optimisation: What Do We Need to Know? The HTTP/1-liness of HTTP/2 In Defence of DOM­Content­Loaded Site-Speed Topography Remapped Why Not document.write()? Speeding Up Async Snippets Critical CSS? Not So Fast! Measure What You Impact, Not What You Influence Optimising Largest Contentful Paint Measuring Web Performance in Mobile Safari Site-Speed Topography Speed Up Google Fonts Real-World Effectiveness of Brotli Performance Budgets, Pragmatically Lazy Pre-Browsing with Prefetch Making Cloud.typography Fast(er) Time to First Byte: What It Is and How to Improve It Self-Host Your Static Assets Tips for Technical Interviews Cache-Control for Civilians Bandwidth or Latency: When to Optimise for Which ITCSS × Skillshare What If? CSS and Network Performance The Three Types of Performance Testing Getting to Know a Legacy Codebase Image Inconsistencies: How and When Browsers Download Images Identifying, Auditing, and Discussing Third Parties My Digital Music Setup Measuring the Hard-to-Measure Finding Dead CSS The Fallacies of Distributed Computing (Applied to Front-End Performance) Ten Years Old Relative Requirements Airplanes and Ashtrays Performance and Resilience: Stress-Testing Third Parties Refactoring Tunnels Little Things I Like to Do with Git Writing Tidy Code Configuring Git and Vim Base64 Encoding & Performance, Part 2: Gathering Data Base64 Encoding & Performance, Part 1: What’s Up with Base64? Code Smells in CSS Revisited Typography for Developers Moving CSS Wizardry onto HTTPS and HTTP/2 Ack for CSS Developers A New Year, a New Focus Preparing Vim for Apple’s Touch Bar Choosing the Correct Average CSS Shorthand Syntax Considered an Anti-Pattern CSS Wizardry Newsletter Nesting Your BEM? Improving Perceived Performance with Multiple Background Images Continue Normalising Your CSS Pure CSS Content Filter Pragmatic, Practical, and Progressive Theming with Custom Properties Refactoring CSS: The Three I’s Speaker’s Checklist: Before and After Your Talk Improving Your CSS with Parker The Importance of !important: Forcing Immutability in CSS Mixins Better for Performance Managing Typography on Large Apps White October Events Workshop Partnership BEMIT: Taking the BEM Naming Convention a Step Further Travelling Like You Want to, When You Have To Contextual Styling: UI Components, Nesting, and Implementation Detail Subtleties with Self-Chained Classes Cyclomatic Complexity: Logic in CSS Immutable CSS Can CSS Be Too Modular? More Transparent UI Code with Namespaces When to use @extend; when to use a mixin The Specificity Graph CSS Wizardry Ltd.: Year 1 in review
MindBEMding – getting your head ’round BEM syntax
Harry Roberts · 2013-01-26 · via CSS Wizardry

Written by on CSS Wizardry.

Table of Contents

Independent writing is brought to you via my wonderful Supporters.

  1. Featured case study: NHS

One of the questions I get asked most frequently is what do -- and __ mean in your classes?

The answer is thanks to BEM and Nicolas Gallagher


BEM – meaning block, element, modifier – is a front-end naming methodology thought up by the guys at Yandex. It is a smart way of naming your CSS classes to give them more transparency and meaning to other developers. They are far more strict and informative, which makes the BEM naming convention ideal for teams of developers on larger projects that might last a while.

It is important to note that I use a naming scheme based on BEM, but honed by Nicolas Gallagher. The naming techniques covered in this post are not the original BEM ones, but are improved versions that I much prefer. Whatever the actual notation used, they are all based on the same BEM principles.

The naming convention follows this pattern:

.block {}
.block__element {}
.block--modifier {}
  • .block represents the higher level of an abstraction or component.
  • .block__element represents a descendent of .block that helps form .block as a whole.
  • .block--modifier represents a different state or version of .block.

The reason for double rather than single hyphens and underscores is so that your block itself can be hyphen delimited, for example:

.site-search {} /* Block */
.site-search__field {} /* Element */
.site-search--full {} /* Modifier */

The point of BEM is to tell other developers more about what a piece of markup is doing from its name alone. By reading some HTML with some classes in, you can see how – if at all – the chunks are related; something might just be a component, something might be a child, or element, of that component, and something might be a variation or modifier of that component. To use an analogy/model, think how the following things and elements are related:

.person {}
.person__hand {}
.person--female {}
.person--female__hand {}
.person__hand--left {}

The top-level block is a ‘person’ which has elements, for example, ‘hand’. A person also has variations, such as female, and that variation in turn has elements. This again, but written in ‘normal’ CSS:

.person {}
.hand {}
.female {}
.female-hand {}
.left-hand {}

These all make sense, but are somewhat disconnected. Take .female for example; female what? What about .hand; a hand of a clock? A hand in a game of cards? By using BEM we can be more descriptive but also a lot more explicit; we tie concrete links to other elements of our code through naming alone. Powerful stuff.

Featured case study: NHS

How I helped the NHS rapidly build a brand new product.

Read case study…

Taking the previous .site-search example again, with ‘regular’ naming:

<form class="site-search  full">
    <input type="text" class="field">
    <input type="Submit" value ="Search" class="button">
</form>

These classes are fairly loose, and don’t tell us much. Even though we can work it out, they’re very inexplicit. With BEM notation we would now have:

<form class="site-search  site-search--full">
    <input type="text" class="site-search__field">
    <input type="Submit" value ="Search" class="site-search__button">
</form>

We can see that we have a block called .site-search which has an element which lives inside it called .site-search__field. We can also see that there is a variation of the .site-search called .site-search--full.

Let’s take another example…

If you are familiar with OOCSS then you will no doubt be familiar with the media object. In BEM form, the media object would now read:

.media {}
.media__img {}
.media__img--rev {}
.media__body {}

From the way this CSS is written we can already glean that .media__img and .media__body must live inside .media and that .media__img--rev is a slight variation on .media__img. All that information gathered from the names of our CSS selectors alone!

Another benefit is the combatting of the following situation. If we take the media object again:

<div class="media">
    <img src="logo.png" alt="Foo Corp logo" class="img-rev">
    <div class="body">
        <h3 class="alpha">Welcome to Foo Corp</h3>
        <p class="lede">Foo Corp is the best, seriously!</p>
    </div>
</div>

From looking at this, we can’t see how the classes .media and .alpha are related to each other? Are they? What about .body and .lede or .img-rev and .media? From that HTML (unless we’re very familiar with the media object) we have no idea what makes up that component and what else is optional. If we were to rework it with BEM:

<div class="media">
    <img src="logo.png" alt="Foo Corp logo" class="media__img  media__img--rev">
    <div class="media__body">
        <h3 class="alpha">Welcome to Foo Corp</h3>
        <p class="lede">Foo Corp is the best, seriously!</p>
    </div>
</div>

We can now instantly see that .media is the block, .media__img--rev is an element of .media that has a modifier applied and .media__body is an unmodified element of .media. All through the names of their classes. That is incredibly useful.

Uuuugly!

A common argument against BEM is that it’s ugly; I dare say that if you shy away from code based purely on its looks then you’re often missing the point. Unless the code becomes unnecessarily difficult to maintain, or genuinely more difficult to read, then perhaps you do need to think twice before using it, but if it ‘just looks odd’ but has a valid purpose, then it should definitely be fully considered before writing it off.

I agree that BEM does look weird, but the power it brings far outweighs any negatives to do with its appearance by an order of magnitude…

BEM may look a little funny – and it might require more typing (most text editors have autocomplete, and gzip will negate any differences in filesize) – but it is so powerful.

To BEM or not to BEM?

I use BEM notation on everything I build now as its usefulness has proved itself over and over. I’d strongly encourage others to consider adopting it as well because it just makes everything a lot tighter and more connected, making code easier to maintain by teams, or even just by yourself a few months down the line.

When you are using BEM, though, it is important to remember that you don’t need to use it for everything. Take for example:

.caps { text-transform: uppercase; }

This CSS would never fall into any BEM category, it’s merely a standalone rule.

Another example of code which isn’t BEM:

Here we have our logo; it could be BEMmed up like so:

.header {}
.header__logo {}

But that is unnecessary. The trick with BEM is knowing when something falls into a relevant category. Just because something happens to live inside a block it doesn’t always mean is is actually a BEM element. In the case of our site logo it lives in the .header purely coincidentally; it could just as easily be in our sidebar or footer. An element’s scope can start in any context, so you need to make sure you only apply BEM as far as you need to. Another example:

<div class="content">
    <h1 class="content__headline">Lorem ipsum dolor...</h1>
</div>

Here we might be able to just call the second class .headline; it depends on if it is styled that way because it’s in .content, or whether it just happens to live in .content. If it is the latter then we do not need BEM.

Everything is potentially open to moving into BEM territory, though. Taking our .site-logo example again, imagine that we want to have a festive version of the logo for our Christmassy site design. We could have:

.site-logo {}
.site-logo--xmas {}

We can quickly build variations of things by using the -- modifier notation.

One of the hardest parts of BEM is deciding when to start and stop scope, and when (or not) to use it. It’s a case of ‘you’ll just know when you know’.

Final word

So that’s BEM (or a slight variation thereof); a highly useful, powerful and simple naming convention to make your front-end code easier to read and understand, easier to work with, easier to scale, more robust and explicit and a lot more strict.

For all BEM looks a little odd, it as a hugely valuable addition to the front-end developer’s toolbox, no matter the project.