背景介绍:当我们在从事大项目或团队开发工作时,我们经常会发现我们写的代码,凌乱、难以阅读并且难以扩展。尤其是当一段时候后我们回头再看自己的代码,必须回想起当初自己写的时候的思路才能看懂。
因此,人们尝试在代码风格上保持统一,然而,最大的困难是:修改一个较小的问题,都可能创建更多丑陋的hack,也可能css的小改变会影响javascript的功能。但是这些问题能在我们的项目开始的时候精心规划,就能很大程度上避免这些问题。今天就来讨论一下如何写一份不错的css代码
要保持良好的css代码,首先需要订立一致的css团队规范,这就必须从css架构讲起。
css架构目前css主要有以下五种设计架构
1.oocss面向对象的css,
结构和主题分离–减少对html结构的依赖主题和主题分离–增加样式的复用性在oocss的基础上,出现了另一种设计模式
2.bem也可以被当成一种命名规范,本质上使页面结构清晰
块(block)、元素(element__)、修饰符(modifier–)
有以下几个规则
block元素应该以元素本身的属性为主element则以元素位置和形状为主modifier则修饰当前的状态和主题element一定是在block之中,而不能独立于block之外modifier则更多的表示当前组件的形状和状态可以明显发现
结构清晰定位迅速功能明确在面对组件化的场景时,block代表逻辑上和功能上独立的页面组件。element封装了行为(javascript)、模板、样式(css)和其他实现技术。
举个例子
<header><img><form><input><button></button></form><ul><li><ahref="url">en</a></li><li><ahref="url">ru</a></li></ul></header>block-name__element-name–modifier-name–modifier-value在react当中,也采用了这样的命名方式
bemnaming工具[1],提供bem命名的检测
然而在面对大型的项目时css的凌乱也很难让开发者愿意在茫茫多的代码中寻找可复用的代码
3.smacss(what’ssmacss)[https://smacss.com/]
设计的主要规范有三点:
categorizingcssrules(为css分类)namingrules(命名规范)minimizingthedepthofapplicability(最小化适配深度)为了实现清晰的css结构,将css分为
base–全局样式,如global-reset、normalize.csslayout–页面布局,如gridmodule–组件布局state–元素状态,如visible、hiddenthemeorskin–更多是具体主题的配置样式javascript勾子(javascripthooks)其中尤其建议javascript解除和样式的耦合
<button></button>命名规范上出现了一些差异
.layout-header.is-hidden.theme-nav最小化适配深度,减少html和css的耦合度,避免html的变动增加对css的影响
.sidebarulh3{}.side{}4.itcss对css进行了更加详细的分层
如果从功能的角度上看呢,是将base分成了settings、tools、generic和base,而objects、components和trumps则分别对应layout、module、(state、theme),而这样设计的好处在于可以将代码的复用性进一步提升
5.acss一个样式属性一个类,其中的典型代表就是tailwindcss[2],缺点则是破坏了语义化
.block{display:block;}.hidden{display:none;}.p-2{padding:0.75rem;}.flex{display:flex;}.text-base{font-size:1rem;}.bg-green-200{background-color:#123456}<divclassname="m-2p-2text-2xltext-gray-500">iamok</div>而上述的架构思想,更多则是需要团队成员的一致性认同,才能实现在代码风格上的统一。
除了这些开发自律性上的代码规范外,还有什么其他的方式来提升css质量呢?
css预处理器在预处理器中,同样提供了众多的方法来简化与控制css代码,以stylus为例
1.变量font-size=14pxbodyfontfont-sizearial,sans-serifpad(types=padding,n=5px)ifpaddingintypespaddingnifmarginintypesmarginnbodypad()bodypad(margin)bodypad(paddingmargin,10px)//yields:body{padding:5px;}body{margin:5px;}body{padding:10px;margin:10px;}2.函数add(a,b=a)a+badd(10,5)//=>15get(hash,key)returnpair[1]ifpair[0]==keyforpairinhashhash=(one1)(two2)(three3)get(hash,two)//=>2get(hash,three)//=>3get(hash,something)//=>null3.内建函数//提取颜色分量red(#c00)//=>204red(#000,255)//=>#f004.插值//属性插值vendor(prop,args)-webkit-{prop}args-moz-{prop}args{prop}argsborder-radius()vendor('border-radius',arguments)box-shadow()vendor('box-shadow',arguments)buttonborder-radius1px2px/3px4px//yields:button{-webkit-border-radius:1px2px/3px4px;-moz-border-radius:1px2px/3px4px;border-radius:1px2px/3px4px;}//选择器插值tableforrowin12345tr:nth-child({row})height:10px*row//yields:tabletr:nth-child(1){height:10px;}tabletr:nth-child(2){height:20px;}tabletr:nth-child(3){height:30px;}tabletr:nth-child(4){height:40px;}tabletr:nth-child(5){height:50px;}myselectors='#foo,#bar,.baz'{myselectors}background:#000yields:#foo,#bar,.baz{background:#000;}//对象插值foo={width:10px,height:20px,'&:hover':{padding:0}}.bar{foo}yields://=>.bar{//width:10px;//height:20px;//}//.bar:hover{//padding:0;//}5.@extendforminput[type=text]padding:5pxborder:1pxsolid#eeecolor:#dddtextarea@extendsforminput[type=text]padding:10px//yielding:forminput[type=text],textarea{padding:5px;border:1pxsolid#eee;color:#ddd;}textarea{padding:10px;}对于维护一份高质量的css代码,注释和间隔必不可少以下是一种比较建议的注释和间隔方式,可以自行取用。
/*------------------------------------*#a-section*------------------------------------*/.selector{}/*------------------------------------*#another-section*------------------------------------*//***comment*/.another-selector{}除了缩进,我们还可以通过在规则集之间自由而明智地使用空格来提供大量信息。我们用:
密切相关的规则集之间的一(1)条空行。松散相关的规则集之间的两(2)条空行。全新部分之间的五(5)行空行。//goodcase/*------------------------------------*#foo*------------------------------------*/.foo{}.foo__bar{}.foo--baz{}//badcase.foo{}.foo__bar{}.foo--baz{}同理,在html结构中,也可以使用同样的规则。
除了以上这些,还有众多的规范和优化可以继续探索,如选择器性能,css嵌套,有兴趣的读者可以继续探索
你会认为css规范是一个有点宏大和不必要的概念:为什么这么简单、这么直接的东西需要像架构一样被设计成非常复杂的东西?!
正是因为css的简单性、松散性和不守规矩的性质意味着在任何合理规模上管理(阅读、驯服)它的最佳方式是通过严格和特定的架构。坚实的架构可以帮助我们控制我们的特殊性,强制执行命名约定,管理我们的源代码顺序,创建一个健全的开发环境,并且通常使我们的css项目管理更加一致和舒适。
总的来说,可以依照一下几个规则订立团队/个人代码规范,保证代码的一致性
建议的几个原则单一职责原则:每个css实现都必须有一个单一的责任。correct:.button{font-family:arial,sans-serif;border:1pxsolidblack;background:#fff;}.header__button{margin:30px;position:relative;}incorrect:.header__button{font-family:arial,sans-serif;position:relative;border:1pxsolidblack;margin:30px;}开闭原则:元素应该通过修饰符扩展,而不是直接在原有基础上修改。original:<button>...</button>.button{font-family:arial,sans-serif;text-align:center;font-size:11px;line-height:20px;}extend<button>...</button>.button{font-family:arial,sans-serif;text-align:center;font-size:11px;line-height:20px;}.button_size_s{font-size:13px;line-height:24px;}dry原则:将有意义的重复规范化和抽象化巧用mixin和extend@mixinmy-web-font(){font-family:"mywebfont",sans-serif;font-weight:bold;}.btn{display:inline-block;padding:1em2em;@includemy-web-font();}.foo{color:red;}.bar{@extend.foo;}组合优于继承和关注点分离//将写js的方式同样适用在css上<div><div><section>...</section></div><div><section>...</section></div></div>参考文献bem简介[3]
oocss介绍[4]
探索smacss:可扩展的模块化css框架[5]
编写高效的css选择器[6]
css的单一原则[7]
思考css架构[8]
参考资料[1]bemnaming工具:
https://github.com/bem/bem-sdk#naming
[2]tailwindcss: https:///
[3]bem简介:
https://en.bem.info/methodology/quick-start/
[4]oocss介绍: http://oocss.org/
[5]探索smacss:可扩展的模块化css框架:
https://zhuanlan.zhihu.com/p/44851489
[6]编写高效的css选择器:
https://csswizardry.com/2011/09/writing-efficient-css-selectors/
[7]css的单一原则:
https://csswizardry.com/2012/04/the-single-responsibility-principle-applied-to-css/
[8]思考css架构:
https://zhuanlan.zhihu.com/p/32952130