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

推荐订阅源

T
Tenable Blog
博客园_首页
Vercel News
Vercel News
WordPress大学
WordPress大学
美团技术团队
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Y
Y Combinator Blog
博客园 - 【当耐特】
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
The Cloudflare Blog
T
The Blog of Author Tim Ferriss
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
云风的 BLOG
云风的 BLOG
腾讯CDC
M
MIT News - Artificial intelligence
爱范儿
爱范儿
Recent Announcements
Recent Announcements
雷峰网
雷峰网
Last Week in AI
Last Week in AI
宝玉的分享
宝玉的分享
The Register - Security
The Register - Security
Jina AI
Jina AI
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog
P
Privacy & Cybersecurity Law Blog
Recorded Future
Recorded Future
Help Net Security
Help Net Security
N
News and Events Feed by Topic
博客园 - Franky
P
Proofpoint News Feed
L
LINUX DO - 热门话题
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
D
Docker
Google DeepMind News
Google DeepMind News
有赞技术团队
有赞技术团队
IT之家
IT之家
Security Latest
Security Latest
L
LangChain Blog
V
V2EX
阮一峰的网络日志
阮一峰的网络日志
J
Java Code Geeks

Philip Walton

The State of ES5 on the Web Dynamic LCP Priority: Learning from Past Visits Performant A/B Testing with Cloudflare Workers My Challenge to the Web Performance Community Smaller HTML Payloads with Service Workers Cascading Cache Invalidation Using Native JavaScript Modules in Production Today KV Storage: the Web's First Built-in Module Idle Until Urgent Page Lifecycle API First Input Delay Responsive Components: a Solution to the Container Queries Problem Why Web Developers Need to Care about Interactivity Deploying ES2015+ Code in Production Today How We Track Pageviews Is All Wrong The Google Analytics Setup I Use on Every Site I Build The Dark Side of Polyfilling CSS Loading Polyfills Only When Needed Untangling Deeply-Nested Promise Chains Learning How to Set Up Automated, Cross-browser JavaScript Unit Testing Houdini: Maybe the Most Exciting Development in CSS You've Never Heard Of Why I'm Excited About Native CSS Variables Do We Actually Need Specificity In CSS? How to Become a Great Front-End Engineer Extending Styles Side Effects in CSS Normalizing Cross-browser Flexbox Bugs Measuring Your Site's Responsive Breakpoint Usage The Dangers of Stopping Event Propagation Stop Copying Social Code Snippets Implementing Private and Protected Members in JavaScript How to Find Qualified Developers Interviewing as a Front-End Engineer in San Francisco Solved by Flexbox Decoupling Your HTML, CSS, and JavaScript Why I Test Private Functions In JavaScript How to Unit Test Private Functions in JavaScript Introducing HTML Inspector CSS: Everything is Global and How to Deal With It Defending Presentational Class Names The Future of OOCSS: A Proposal What No One Told You About Z-Index CSS Architecture
Dynamic Selectors
2013-02-21 · via Philip Walton

When creating a new CSS library or framework, developers typically take one of two approaches with component naming: the Bootstrap approach or the jQueryUI approach.

Bootstrap tries to be as simple and basic as possible, calling a component exactly what it is. If something is a tooltip, why not use the class selector .tooltip to define how it looks? This approach keeps things simple, clean, and easy to remember, but it has one big disadvantage. If you’re trying to incorporate Bootstrap into an existing project, the chances are pretty high it will conflict with your existing selectors.

jQueryUI, on the other hand, takes the opposite approach. They prefix every class name with the string ui- greatly reducing the possibility of conflict, but at the cost of being more verbose.

Choosing between these two paths isn’t always easy. Namespacing might be better for compatibility, but what should your prefix be? A longer, more unique prefix will lead to fewer conflicts at the cost of a lot more typing. But if you pick a simple prefix, another library might already be using it. And many of the short and sweet prefixes are already taken (like ui- by jQuery and x- by ExtJS).

What if there were a third option? One with all the benefits of clean and simple names like Bootstrap, but without any of the possible conflicts?

With the help of a CSS preprocessor like Sass, this is possible.

Define Selectors with a Variable

Imagine I have a website that’s been around for a while and already defines styles for .tooltip and .alert. Then I decide I want to start using Bootstrap, but I don’t have the time to convert all of my legacy code to the Bootstrap format.

Given the current state of Bootstrap, I’m pretty much out of luck.

But what if there were a way to tell Bootstrap that I wanted to use its .alert component, but call it something else, perhaps .notice. With dynamic selectors, you can do exactly that.

Selectors don’t have to be static. If you build your components with a predictable naming convention, it becomes easy to abstract that name into a variable.

The convention I use is to give each component a name and add that name to the root element of the component. Each sub-element of the component that needs styling defines a class with the component name as a prefix.

Here’s a basic example of a messagebox component taken from an imaginary library called Flux:

<!-- the markup for the messagebox component -->
<div class="messagebox">
  <h1 class="messagebox-title">...</h1>
  <p class="messagebox-body">...</p>
</div>
/* and the corresponding styles */
.messagebox { }
.messagebox-title { }
.messagebox-body { }

A predictable convention like this allows you to easily replace the static names in the selector with a Sass variable like so:

$flux-messagebox-name: "messagebox" !default;

.#{$flux-messagebox-name} { }
.#{$flux-messagebox-name}-title { }
.#{$flux-messagebox-name}-body { }

This technique has all the pros of a clean naming system like Bootstrap with almost none of the potential conflicts. If a project wants to include the messagebox styles above, but its CSS already has .messagebox defined, there’s no problem. All they’d have to do is assign the $flux-messagebox-name variable to something else before including the messagebox’s Sass file, and the conflict is solved.

/* first override the messagebox's class name */
$flux-messagebox-name: "some-other-name";

/* then import flux normally */
@import "flux";

Note: I’m prefixing the class name variables with the flux namespace for an extra level of protection since Sass variables live in the global scope. Doing this isn’t 100% necessary, but I recommend it.

JavaScript Plugins

Most component libraries come with a least some JavaScript that dynamically creates its own markup. If these components offer Sass variables for dynamic selectors, they’ll also need to offer JavaScript variables to change the class names there as well.

Since components typically expose a defaults object, the class name variable could be a property on that object, allowing users of the library to change it globally in one place.

For example, if messagebox is a jQuery plugin, you might use code like this to dynamically change the class name:

$.fn.messagebox.defaults.className = "some-other-name";

What about static markup?

At this point I’m sure some readers are wondering whether I’ve overlooked half the problem. Dynamically building selectors is one thing, but what if the old class name is in hundreds of places in the HTML, how do you deal with that?

The truth is I don’t think that situation would be very common. The typical use case for dynamic selectors is when you want to start using a third party library, haven’t written any code for it yet, and realize there would be conflicts. In this use case, you’re picking a class name that isn’t in the HTML precisely to avoid conflict.

The only time I could see dynamic selectors leading to a lot of find-and-replace in the HTML is if you change your mind and suddenly decide you want to name your classes something else, in which case it’s not really the library author’s fault. Also, if you’re repeating a lot of the same markup for each component and you think it’s likely you’ll change your mind later, this is a perfect place to abstract that markup into templates, partials, or helpers.

Summary

All component libraries that use preprocessors should offer the option of dynamic selectors. It allows for a short and simple name for the majority of users and only requires extra effort for the ones who need it. It doesn’t impose a verbose prefix on anyone and keeps the barrier to entry low. Those who want to make changes can dive into the Sass file, and those who just want to use it out of the box can simply grab the compiled CSS. Everybody wins.

I’d love to see libraries like Bootstrap adopt this approach. Bootstrap already uses a jQuery-like noConflict() method in each of its JavaScript plugins. Dynamic selectors wouldn’t be much harder and would go a long way to increase its compatibility.

I believe that website authors should be able to write their markup however they want. They should be able to choose whatever names they want without the fear that someday those names will conflict with a third party library. It should be the responsibility of library and framework authors to make their code as compatible as possible.