关于如何写类名,网上已经有很多讨论了:
总结来说,BEM
命名法更好,下面就以自己的实际例子来讨论,为什么更好。
先来看两段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <ul class="news"> <li class="news__item news__item--hot">news 1</li> <li class="news__item">news 2</li> <li class="news__item">news 3</li> <li class="news__item">news 4</li> </ul> <style> .news__item { color: #eee; } .news__item--hot { color: red; } </style>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <ul class="news"> <li class="hot">news 1</li> <li>news 2</li> <li>news 3</li> <li>news 4</li> </ul> <style> .news li { color: #eee; } .news .hot { color: red; } </style>
|
两段代码的作用都是相同的,即渲染新闻列表,颜色为#eee
,并且第一条新闻颜色为red
。不过可以看到两者的选择器不同,前者给每一个li
标签添加了类名,而后者直接使用标签选择器li
。
性能
如果搜索关于网页渲染性能的文章,几年前(2011~2013 左右)都会提到选择器的优化。简单来说就是浏览器渲染样式,选择器是从右向左进行查找的,所以:
1 2 3
| .news li { color: #eee; }
|
该段代码,会先找到所有的li
标签,再筛选出在.news
下的li
标签,所以性能不如直接给li
标签添加类名,使用类选择器。
同时给出了效率列表,从高至低排序:
- id选择器(#myid)
- 类选择器(.myclassname)
- 标签选择器(div,h1,p)
- 相邻选择器(h1+p)
- 子选择器(ul > li)
- 后代选择器(li a)
- 通配符选择器(*)
- 属性选择器(a[rel=”external”])
- 伪类选择器(a:hover,li:nth-child)
来源 - CSS选择器的优化
但是,在现代浏览器下,使用标签选择器或者类选择器之间的差别已经可以忽略了。经过测试存在 10000 个标签时,可能只有 200ms 左右的渲染时间差别,如果考虑给li
标签加类名导致增加了html
文件字节数,总时间其实真的差不多。
易于维护
不过,从易于维护的角度来考虑,更建议使用类名选择器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <div class="goods"> <h1>商品标题</h1> <small>商品子标题</small> <div class="info"></div> </div> <style> .goods h1 { color: #eee; } .goods small { font-size: 14px; } .goods .info { margin-top: 10px; } </style>
|
这是一个商品页面,有商品标题、子标题以及商品信息,需要给商品标题设置颜色,给子标题设置文字大小,上面的样式实现了该需求。
之后由另一个人来维护,需要给子标题设置一个颜色,所以要先在html
文件内找到子标题对应的节点,而我们的html
文件可能是这样的:
1 2 3 4 5
| <div class="goods"> <h1></h1> <small></small> <div class="info"></div> </div>
|
因为数据往往是通过ajax
请求后填充到页面中。到底哪个是子标题呢,从语义化的角度,能够猜测出small
可能是,那怎么确定呢,可以在浏览器打开页面右键审查元素,或者看看js
文件,在填充数据的时候是将子标题填充到了哪个标签中:
1 2
| var subTitle = data.subTitle; $('.news').find('small').text(subTitle);
|
这两种方式都能够确定到底哪个标签是子标题,但是有没有更好的方式呢?如果直接给类名呢?
1 2 3 4 5
| <div class="goods"> <h1 class="title__main"></h1> <small class="title__sub"></small> <div class="info"></div> </div>
|
只要看了html
,就知道要在样式文件中搜索title_sub
就能够准确找到对应的样式。
组件化
还有一个理由就是,现在组件化的开发方式,要求我们将页面上的元素拆分为一个一个组件,尽可能通过组件的组合实现页面。
举个例子,一个新闻列表板块,可以分为Title
、List
、Item
三个组件:

这样划分是考虑到Title
很可能在其他地方也要使用,封装为组件便于复用。
样式,同样可以依照这个思路,所以样式会这样写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| .title { line-height: 30px; } .title__main { font-size: 20px; color: #999; } .title__sub { margin-top: 10px; font-size: 12px; } .list { padding: 10px; background: #eee; } .item { overflow: hidden; padding: 4px; line-height: 16px; } .item__title { display: inline-block; font-size: 14px; } .item__icon { display: inline-block; margin-left: 100px; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <body> <div class="news"> <div class="title"> <h1 class="title__main">新闻列表</h1> <small class="title__sub">看天下新闻</small> </div> <ul class="list"> <li class="item"> <h2 class="item__title">新闻列表一</h2> <i class="item__icon">*</i> </li> <li class="item"> <h2 class="item__title">新闻列表二</h2> <i class="item__icon">*</i> </li> <li class="item"> <h2 class="item__title">新闻列表三</h2> <i class="item__icon">*</i> </li> <li class="item"> <h2 class="item__title">新闻列表四</h2> <i class="item__icon">*</i> </li> </ul> </div> </body>
|

重点是,在另一个地方同样需要相同样式的Title
,只是文字不同,就可以将html
结构复制,就能够快速得到相同样式的板块。
1 2 3 4 5 6 7 8 9 10
| <div class="goods"> <div class="title"> <h1 class="title__main">商品介绍</h1> <small class="title__sub">特色商品介绍</small> </div> <li class="item"> <h2 class="item__title">商品</h2> <i class="item__icon">$</i> </li> </div>
|

同时可以注意到,.news
与.goods
都是和页面,或者说和业务有关的,这些无法“复用”的组件,就负责最终的布局,一般是设置位置与大小。
如果是react
或者Vue
,代码可能会是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <div class="news"> <Title title = "新闻列表" subTitle = "看天下新闻" /> <List> <Item title = "新闻列表一" icon = "*" /> <Item title = "新闻列表二" icon = "*" /> </List> </div> <div class="goods"> <Title title = "商品介绍" subTitle = "特色商品介绍" /> <Item title = "商品" icon = "$" /> </div>
|
总结
写代码的过程中,不只是实现功能,更多的要有自己的思考,总结出如何更好更快的写代码,就能够节省更多时间做其他的事情了。