css的困惑

- 1 min

最近在项目中使用React比较多,components的组织方式使前端整个的开发思路更加清晰,在多人项目中,也会减少很多沟通的成本(需要什么组件,直接去找就可以了),但是由此也产生了一些困惑。

不过这里不会讨论React本身,只会讨论由Components方式引发的一些css写法的变化

在我刚参加工作时,那时候前端开发还基本处在刀耕火种的阶段,加上我加入的第一家公司又不是一个以技术擅长的公司,所以当时前端开发工程师还被昵称为页面仔 (也就是只写页面样式,甚至很多时候是连js也不用写的)。

当时好像也没有听说过Bootstrap这样的东西,更不用说less,sass这些东西,components更是完全不知道是什么意思。全部 css 都是人肉写,class命名完全靠个人习惯,比如有人就很喜欢这样的命名方式:

.box {
	...
}
.box .hd {
	...
}
.bod .bd {
	...
}

也有人喜欢这样的命名方式:

.box {
	...
}
.box-hd {
	...
}
.box-bd {
	...
}

怎么说呢,这两种命名方式各有优劣,第一种结构更加清晰,在日后的各种可编译css语法(比如sass)中用的基本都是这种写法。

但是也有问题,就是如果嵌套层级过多的话,会影响页面的渲染速度。

第二种呢,命名只有一层,所以css选择器可以很快的找到对应的样式,渲染速度会略快,但是写起来确实不太方便。

除了这两种写法各自的优劣之外,其实这两种方法还有个共同的弱点,就是样式容易被覆盖

样式覆盖可以算 css 最主要的特性之一了,各种优先级的组合以及!important的运用,可以衍生出各种灵活的样式变化。样式覆盖的特性是一把双刃剑,给予了css灵活性的同时也使覆盖bug几乎是无法避免的。

尤其是在维护一个老项目的时候,由于css本身很难以表达出完整的逻辑性,但样式的命名又是全局的,所以在修改样式时,很容易就不小心改动了或覆盖了本来正确的样式,相信很多人都有这种经历。到最后为了不影响之前的样式,只能不停的对要修改的部分进行覆盖,或者更干脆直接为要修改的部分重新定义样式。

这个问题一直困扰了我很长时间,直到有一天我看到了 facebook 页面上的class命名:

<div class="_1dwg">
	<div class="_4r_y">
		...		
	</div>
	<div class="clearfix _5x46">
		...
	</div>
	<div class="_5pb8 _5v9u _29h _303">
		...
	</div>
</div>

基本上所有的 className 都是一个混淆过的名字,在控制台里看也发现很少有样式一个接一个覆盖的问题。

className 的混淆可以理解为减少 className 命名的长度,减少网络请求的size(不过其实重点并不在这里)。同时多层的嵌套应该也会被混淆成为一个 className,从而大大减少命名冲突(最直观的体现就是央视被覆盖)的几率。这在大型项目中是很有用的,再不用担心自己的那条 className 不小心跟前人的有所重复,不小心就把样式给搞乱了。

再后来,前端开发逐渐进入components阶段,从 css 到 scss ,样式模块的复用和 css 的逻辑性有了很大的提升,但是仍然没能解决我上面所说的问题。因为最终编译出来的还是 css 文件,所有的变量还是全局的,命名冲突还是会在所难免的发生。

直到后来我看到了这样一篇文章The End of Global CSS

在这篇文章里,提出了一个local scope的概念,大意就可以理解成给css代码添加了作用域,具体的实现就是将 className 编译为一个哈希串,从而避免了命名冲突(和facebook的做法很像)。

通过local scope相当于给 css 添加了作用域的概念,从而可以笑消除全局的 className。看上去很美好,完美的解决了命名冲突的问题,但同时也使丢到了可覆盖带来的灵活性。但不论怎样,css 又离宇宙最好的语言进了一步。

为了解决上面所说的问题,在The End of Global CSS中,作者也提出了一些解决方案,例如使用:local:global的方式来规定哪些 className 可以被暴露给全局对象,通过可预见的方式暴露一些变量到全局作用域中,虽然不是很完美,但是也算是一条路。(灵活和严谨本来就是一对矛盾,所以只能选择一条折中的方案)


说到这里,要说的基本已经说完了,再来说点题外话。

现在大家都用component的方式进行开发,所谓component的不仅仅是使用React作为前端的模板,更重要的是所谓模块化的思路。关于模块化这里就不展开了,着重说一下模块化思路下的 css 开发。

通常情况下,不论使用 sass或者less 或者其他的什么css语法,我们所做的都是

compiler => bundle.js + bundle.css

将 css 和 js 独立打包。

使用 webpack 的话,我们可以使用很多插件来完成这个工作。 例如:

总而言之,到现在为止,css 开发早已脱离了当初的刀耕火种的年代,从可编译的lesssass,再到radiumCSS Modules的思路,css 的开发越来越工程化,不过到目前为止,还难以有一个令人十分满意的解决方案出现。


参考资料:

CSS Modules:

radium:

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora