CSS 选择器命名是一个哲学问题。--- 张鑫旭 《CSS 选择器世界》css
首先,须要你们思考一下这个问题。vue
。。。 一分钟后。react
在我看来命名的究极目的,只有一个样式复用。你品,你细品。git
一个项目一般不是只有咱们一我的在开发,而且咱们也会引入一些第三方的库。因此命名冲突是一个很是容易发生的事情。解决命名冲突的方案我知道有三种:github
一般咱们写一些但愿被别人复用的第三方组件的时候会采用,私有做用域前缀的方案。好比:ant-design .ant-*
, material-ui 的 .Mui*
。编辑器
然而这并不能 100% 的解决命名冲突问题。好比你的团队以前约定了 .ant-
做为通用前缀,此时又须要引入 and.design 的组件。又或者你同时引用的两个不一样的第三方库,采用了相同的前缀。此时就会显得比较的尴尬了。固然这个几率其实也不大啦。工具
私有做用域前缀,还有一种方法就是约定一些前缀来约束不一样选择器的功能。好比网页NEC 里面 :布局(grid)(.g-);模块(module)(.m-);元件(unit)(.u-)... 若是团队里面你们都承认这个那么这甚是极好的。可是可能须要思考的点就在于。若是这些约定的过多或者过于复杂的时候,团队其它成员是否可以接受或者达成一致。布局
CSS-module 是一个我认为很是赞的发明。它妙就妙在,我能够在个人组件里面用 .header
, 你也能够在你的组件里面用 .header
。可是咱们却不用彻底不用担忧命名冲突的问题。ui
一个优秀的解决方案就应该是这样:在不改变我自身习惯的状况下,还帮我解决个人痛点。spa
固然它仍是有它的代价的,原来咱们写代码:
import "../styles/global.css";
import "./header1.css";
import "./header2.css";
<h2 className="header1">标题1</h2>
<h2 className="header2 float-left">标题2</h2>
复制代码
引入 CSS-module 写代码:
import "../styles/global.css";
import _header1 from "./header1.module.css";
import _header2 from "./header2.module.css";
<h2 className={_header1.header}>标题1</h2>
<h2 className={`${_header2.header} float-left`}>标题2</h2>
复制代码
首先咱们须要用构建工具去构建 CSS-module(特别是在非 react 和 vue 构建的项目中)。
在使用的时候,咱们须要还须要给咱们的 CSS 文件,取一个额外的做用域名称,告诉构建工具这个选择器是来自哪儿(这个做用域名称自己也会命名冲突的问题)。
更尴尬的是,若是咱们全局有一些通用样式和 CSS-module 混用的时候,还得借用字符串模版的能力去拼接 className
,这很容易致使咱们的代码编辑器的对于 CSS 选择器的提示失效(不知道小伙伴们有什么方案能够解决这个问题)。
在我以前的文章当中,我屡次提到不用命名就是最好的命名。连名字都没有就不用纠结命名的问题。对于不用命名的方案我知道也是有三种方案:
直接用别人取好的名字。
目前可能最流行的就是 tailwind 这应该是 github 上 star 数最多的 CSS 项目了。这个方案其实不是不用命名,而是预制好了能涵盖咱们大多数业务场景的一些 CSS 类。因而咱们就基本上能够是不多,或者是不用从新去给 CSS 命名了。
可是这么多预制的规则上手是一个成本,而且也一样有须要说服同项目的小伙伴使用的问题。
定义 style 规则,每一个人经过这个命名规则只能产生相同的名称
Atomic css 是一种比 tailwind 原子化更加极致的方案。
Atomic css 并无预制 CSS hooks,它更像是从新定义了一套 style-inline 的编写方式。由于没有 CSS-hooks 因此也就不存在命名冲突的问题。
老实说,Atomic css 输就输在它的那套晦涩难懂的命名规则。可是你也不得不认可,若是整站都是用这个去编写 style,确实能够 100% 的解决命名的问题。而且你整站的 CSS 代码至少能够减小 50% 以上。
直接写 style
当咱们进入到 js 盛行的时代,css-in-js 可让咱们在不须要理解 Atomic CSS 那套命名规则的状况下,而直接使用咱们最熟悉的 style 的方式,100% 的解决 CSS 命名的问题。
这里说 100% 的解决 CSS 命名是不许确的。更确切的说,咱们是直接把样式附着在了组件上,在复用组件的时候达到了样式复用的目的。而非 CSS-in-js 的方式,是咱们在拥有组件命名的同时还要在组件内部为样式再建立一套命名规则。
尴尬的是,若是咱们有不少样式须要复用的时候,咱们就须要建立不少的样式组件。但是当咱们一旦开始建立样式组件的时候,这又回到了咱们命名冲突的问题。由于组件的名称也会容易冲突。只是相对来讲,JS 能有比 CSS 更好的解决命名冲突的能力更好一些。
什么是好的命名?在我看来就是大多数人都能很天然理解的名字就是比较的好的名字。
.btn-s
: 小按钮.btn-m
: 中号按钮.btn-l
: 大按钮.btn-xl
: 超大按钮好比咱们借用生活中表示衣物 size 的缩写 s,m,l,xl 来表示一些元素的大小就是一个比较不错的方案。既能保持可读性,又精简了咱们 CSS 名称的长度。
.cs-radio
: radio 元素.cs-menu
: menu 元素.active
: 元素能够用状态.disabeld
: 元素不可用状态再好比张鑫旭老师 《CSS 选择器世界》中提到的 “从 HTML 标签中寻找灵感” 我也是很是赞同的。
借用大多数人了解或者熟知的东西去命名,显然比按照咱们本身的习惯去建立名称要好得多。好比我喜欢跳舞,我用舞蹈里面的专有名字去做为我 CSS 的名称,这显然是要被其它同事怼死的。
命名规范的意义在于,经过一些约定,减小团队成员的命名决策时间,以及统一团队的命名风格。在咱们的团队,有两条比较有意思的规则这里分享给你们:
_
(下滑线) 开头的类名不能直接建立样式;_
带下滑线的类名表示全局样式;/* ❌ */
._disabled{ background-color:#f5f5f5; }
/* ✅ */
.btn._disabled{ background-color:#f5f5f5; }
/* ❌ */
.header ._disabled{ background-color:#f5f5f5; }
/* ✅ */
.header._disabled .btn{ background-color:#f5f5f5; }
复制代码
一般须要采用这种方式建立的类名都是表示某些状态的类名。这样作的好处在于,咱们就有了不少不用担忧命名冲突的公用类名。
.select._disabled{ /* */ }
.input._disabled{ /* */ }
.dialog._open{ /* */ }
.modal._open{ /* */ }
复制代码
这样咱们均可以放心的维护本身组件的状态了,而不用担忧个人 *._disabled
会影响到你的 *._dsiabled
。固然维护状态更好的方式应该是:
.select:disabled{ /* */ }
.input:disabled{ /* */ }
.dialog[open]{ /* */ }
.modal[open]{ /* */ }
复制代码
_
带下滑线的类名表示全局样式
对于这条规则,缘由在于咱们想要有简单的方式来区分全局样式和局部样式。后面咱们想到了用_
和 -
来区分这两个状态。
/* 全局header */
.g_header{}
/* 局部header */
.news-header{}
复制代码
照理来讲咱们用.g_
来表示全局样式可读性会更强。可是后面发现这样的话就会发生这样的状况:
/* 全局加号图标 */
.g_i_add{ }
/* 局部加号图标 */
.i-add{ }
复制代码
这明显没有直接用
/* 全局加号图标 */
.i_add{ }
/* 局部加号图标 */
.i-add{ }
复制代码
这样的方式来的简单干净,而且这样还能拓展出其它的全局做用域。因此索性咱们就直接利用这个符号自己来区分全局和局部的样式。
对于命名来讲,每每难的不是命名自己,而是在于你这个命名是否能被团队中大多数人接受和认知。你有可能发现或者发明了一种,各方面都看起来天衣无缝的命名方案,但是团队里面的其它小伙伴就是不买帐,那也是徒劳无功。
重点仍是要看本身团队的痛点是什么。不论是什么样的命名,只要团队里面你们都能理解的就算是不错的命名了。