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

推荐订阅源

K
Kaspersky official blog
小众软件
小众软件
Engineering at Meta
Engineering at Meta
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Google DeepMind News
Google DeepMind News
Security Archives - TechRepublic
Security Archives - TechRepublic
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Check Point Blog
aimingoo的专栏
aimingoo的专栏
罗磊的独立博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
MongoDB | Blog
MongoDB | Blog
L
LINUX DO - 热门话题
酷 壳 – CoolShell
酷 壳 – CoolShell
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
H
Help Net Security
Martin Fowler
Martin Fowler
G
GRAHAM CLULEY
Simon Willison's Weblog
Simon Willison's Weblog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - Franky
V
Vulnerabilities – Threatpost
云风的 BLOG
云风的 BLOG
博客园_首页
C
Cybersecurity and Infrastructure Security Agency CISA
量子位
Stack Overflow Blog
Stack Overflow Blog
Recent Announcements
Recent Announcements
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
I
Intezer
Scott Helme
Scott Helme
A
About on SuperTechFans
博客园 - 司徒正美
Hacker News: Ask HN
Hacker News: Ask HN
The GitHub Blog
The GitHub Blog
Forbes - Security
Forbes - Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Spread Privacy
Spread Privacy
T
Tailwind CSS Blog
S
Security Affairs
宝玉的分享
宝玉的分享

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
Keep your CSS selectors short
Harry Roberts · 2012-05-16 · via CSS Wizardry

Written by on CSS Wizardry.

Table of Contents

Independent writing is brought to you via my wonderful Supporters.

  1. Increases Selector Efficiency
  2. Reduces Location Dependency
  3. Increases Portability
  4. Reduces Chances of Selector Breakage
  5. Decreases Specificity
  6. Can Make Code More Forgiving
  7. Final Word

One thing I believe, as a very, very general rule of thumb, is that as sites get bigger, selectors should get shorter.

By this I mean that if you want to create extensible and maintainable, flexible and predictable websites, you should really take care to make your CSS selectors as dev-friendly as possible; i.e. short.

Keeping CSS selectors short helps with a lot of things:

  • Increases selector efficiency
  • Reduces location dependency
  • Increases portability
  • Reduces chances of selector breakage
  • Decreases specificity
  • Can make code more forgiving

This is a very vague list, so I’m going to address each in order. You will find that there is a lot of crossover between each point (e.g. reducing location dependency inherently means your selectors are more portable) but I feel they are all points in their own right.

Increases Selector Efficiency

I have written before about CSS selector efficiency. I’m going to gloss over a lot of the intricacies in this post so for a full background understanding I recommend you read Writing efficient CSS selectors first.

If we ignore actual types of selector (* {} is typically the slowest, depending on how it’s being used, IDs are the fastest followed by classes, descendants are comparably quite slow followed by pseudo-selectors) then in general it is safe to say that shorter selectors are faster.

This stands to reason, if we compare these two selectors:

html body .header .nav {}
.nav {}

There we can see pretty clearly that in the first example, the browser has to look out for four things, the .nav class, then the .header class, then the body element and then, finally, the html element (browsers read selectors right-to-left).

With the second example the browser only needs to look for one thing; the .nav class. The browser has four times less work to do to match that selector. Every time you write a selector try and trim as much losable stuff from it as possible. Instead of ul.nav {} (two checks) write .nav {} (one check). Instead of .nav li a {} (three) write .nav a {} (two).

Now, CSS selector performance is—by-and-large—not something we really need to worry about any more, but that doesn’t mean we should be wasteful. I’m sure none of us would miss a lost £5 but that doesn’t mean we go slipping banknotes into paper shredders… Selector efficiency does exist and you might as well improve it where you very easily can.

Reduces Location Dependency

By keeping selectors short you are likely to be reducing the amount of descendant (e.g. .sidebar .promo {}) and child (e.g. .sidebar > .promo {}) selectors. By removing these descending types of selectors you are reducing the necessity for an element to live inside another one. Let’s reuse the .sidebar .promo {} example…

By having a selector like .sidebar .promo {} we are saying we want to target any promotional item that lives in an element with the class of .sidebar. This means that we are tied to always using that styling inside a certain element; we have a dependency on location.

By replacing .sidebar .promo {} with something like .secondary-promo {} we can now place the element in question anywhere we wish. In the sidebar—as before—but now also in the footer, or in the header, or after an article.

By reducing descendants we can really reduce dependency and make things a lot more portable…

Increases Portability

So now that we’re not tied to locationally dependant selectors, we find that our components are a lot more portable. We can move things a lot more easily because our CSS doesn’t care where a thing lives, it just cares that it exists. Awesome!

Another way to increase portability is to not qualify selectors. A qualified selector is one like ul.nav {} or a.button {} or div.content {}.

Qualified selectors are bad because they reduce efficiency (more checks than we really need) but—more importantly—because they tie us to specific elements. We can’t now use that .button class on an <input> or a <button>, for example. We can’t apply .nav to an <ol> to make a breadcrumb.

Selectors should be element-agnostic. Your CSS shouldn’t care what element you’re wanting to apply styling to.

Another way to make selectors more portable is to drop elements altogether. Take this, for example:

/* Base widget styling */
.widget {}

/* Style up widget titles */
.widget > h2 {}

Here we have a troublesome selector; what if that <h2> needs to become a <h3>? What if we need to add another, non-titling <h2> as a child of .widget? We’ve made ourselves a very rigid and unportable selector here. Instead we should have:

/* Base widget styling */
.widget {}

/* Style up widget titles */
.widget-title {}

Now we can apply .widget-title to any element—let’s say a <h4>—and can now also have any number of unclassed <h4>s in the widget without them adopting any title styling. Ossom!

Reduces Chances of Selector Breakage

The longer a selector is, the more things the browser has to satisfy before it can match it. The more checks there are then—naturally—the more chance there is for something to go wrong.

A (very exaggerated) selector like body > div:nth-of-type(2) > article:first-child > p:first-child {}—borrowed from my talk Breaking Good Habits—has ten checks; ten things that must be satisfied in order for the browser to make that match.

All that needs to happen is the location of the div:nth-of-type(2) to change or the p:first-child to become a blockquote or the article:first-child to no longer be a child of the div:nth-of-type(2) or any manner of things before that selector will break. Simply replacing that with a class of .intro {} means that there is only one thing that could possibly break, and the chances of that happening are pretty much zero (you’d have to explicitly delete the class from your HTML to prevent a match).

Shorter selectors mean there is statistically less chance for things to go wrong.

Decreases Specificity

This is the big one! This is where it really matters!

Longer selectors have a higher specificity. Specificity is a nightmare and you should keep specificity as low as possible all of the time. We already know that we do not use IDs in CSS but a chain of selectors are often just as bad (though not quite).

A selector like .widget > h2 {} has a higher specificity (as well as the other problems we discussed) than a selector like .widget-title {}.

.nav li a {} has a higher specificity than .nav a (and is also less efficient). Reducing selector length reduces selector specificity and that is very important. High specificity leads to self-induced specificity battles that can only be won by making subsequent selectors more specific (or using !important, shame on you). This is a terrible thing. The easiest way to reduce specificity (after dropping IDs from your CSS completely) is to keep your selectors short.

Can Make Code More Forgiving

This is a very specific but very decent example of how short selectors can make code more forgiving. However, I will warn you, you can argue two sides of what I’m about to tell you; you can argue that it makes your code a lot more flexible and can gracefully handle breakages or you could argue that it allows breakages in the first place by being too lenient. Anyway, here’s a true story…

In working on a pretty huge project at Sky I stuck to my own rules and coded a (vertical) nav bar CSS like so:

.nav { /* Nav styles */ }

/* Note NO .nav li styles as this was a vertically stacking nav. */

.nav a { display:block; /* More styles */ }

Now, there was a CMS error which went undetected where the markup getting spat out was:

<ul class=nav>
    <a href=#></a>
    <a href=#></a>
    <a href=#></a>
    <a href=#></a>
</ul>

Spot the problem? No <li>s! This is really not cool but, as I had used .nav a {} instead of .nav li a {} nothing broke. My code was a lot more forgiving than if I’d had that third check in there.

Now, this doesn’t make the markup right, and it does actually allow poorer markup than a more verbose selector, but you can see how the CSS was very forgiving of a markup error.

Now I said you could argue both sides here, a more verbose selector means that we’d have spotted the CMS error immediately as no styles would have hit the <a>s. But! In the same breath, our CSS was flexible enough to be okay with that. Make of it what you will, because I too am sat on the fence and a little disappointed that the error wasn’t spotted, but here is a very specific example of how shorter selectors can lead to more forgiving CSS.

Final Word

I did mention that this is a rule I’ve applied to larger sites but, honestly, you should apply this everywhere. The things we’ve discussed tend to really come into their own (and their absence painfully aware) on larger builds, but they will definitely, definitely help you on builds of all sizes; small or large.

So, by using more classes and less descendants, keeping selectors short and portable, keeping selectors element-agnostic and generally considering maintenance and chance-of-change when writing our CSS, we can really easily improve the quality of our code infinitely. We can make things more efficient, more forgiving, more flexible and more reusable just by revisiting one of the most simple and fundamental aspects of CSS; our selectors.