CSS 基本规范
命名规范
历史原因及个人习惯引起的 DOM 结构、命名不统一,导致不同成员在维护同一页面时,效率低下,迭代、维护成本极高。所以,使用统一的命名规范非常必要。
01. 目录命名
1234 1、项目文件夹:projectname2、样式文件夹:css3、脚本文件夹:js4、样式类图片文件夹:img02. 图片命名(建议以以下顺序命名)
(m_)图片功能类别(必选)+ 图片模块名称(可选) + 图片精度(可选)
m_表示是否公共,可选。
1234567891011121314151617181920212223 【图片功能类别】icon:模块类固化的图标logo:LOGO类spr:单页面各种元素合并集合btn:按钮bg:可平铺或者大背景pic :表示当前内容或业务的图片【图片模块名称】goodslist:商品列表goodsinfo:商品信息userportrait:用户头像【图片精度】普清:@1xRetina:@2x | @3x//公共模块:m_btn_goodlist@2x.pngm_btn_goodlist.png//非公共模块:wx_btn_goodlist@2x.pngwx_btn_goodlist.pngbtn_goodlist.png03. 文件命名
确保文件命名总是以字母开头而不是数字,且字母一律小写,以下划线连接且不带其他标点符号。
12345678 <!-- HTML -->connect.htmlconnect_list.htmlconnect_detail.html<!-- CSS -->connect.cssconnect_list.cssconnect_detail.css
命名实践
关于CSS命名的规范,市面上有不少,如OOCSS、SMACSS、BEM和MVCSS等。其中,最火的应该算BEM了。
01. 主流命名
1234567891011121314151617181920212223242526272829303132333435363738394041 【BEM】说起CSS命名,当然要提到BEM。BEM的意思是B模块(block)、E元素(element)、M修饰符(modifier)。模块和子元素之间用两个下划线分隔,子元素和修饰符之间用两个中划线分隔。关于子元素E,有两种写法。一种是按照层级嵌套来写,如block-ele1-son-inner,但是这样写会导致命名过长;另一种是扁平化,一个模块B下的所有子元素,无论相互层级如何,都直接连接B,如block-inner,但是这样就无法表示层级关系,命名时也可能会出现冲突。BEM的命名是很好的,不然也不能成为最流行的命名方法。但是,BEM对子元素的命名,无论是层级长命名还是扁平化短命名,都有缺陷。【NEC】相较于BEM以模块B为顶级元素,子元素类名中包含继承关系的命名,网易NEC规范使用后代选择器方式。NEC将元素分为了5类:布局(grid)(.g-);模块(module)(.m-);元件(unit)(.u-);功能(function)(.f-);皮肤(skin)(.s-);状态(.z-)。而后代选择器不需要完整表现结构树层级,尽量能短则短。.m-list{margin:0;padding:0;}.m-list .itm{margin:1px;padding:1px;}.m-list .cnt{margin-left:100px;}// 网易对于元素分类的做法很好。关于一些全局可复用的功能性的模块进行区分,结构更为清晰。但是,对于使用后代选择器的方式,并不是很理想。当嵌套层级较深时,命名冲突依旧是一个问题。【JD】京东的命名规则采用表示层级嵌套关系的长命名。当子孙模块超过4级或以上的时候,考虑在祖先模块内具有识辨性的独立缩写作为新的子孙模块。这种因子元素名字过长而采用首字母缩写的做法非常赞,至今市面上没有其他更好的解决长命名的方案。<div class="modulename"><div class="modulename_cover"></div><div class="modulename_info"><div class="modulename_info_user"><div class="modulename_info_user_img"><img src="" alt=""><!-- 这个时候 miui 为 modulename_info_user_img 首字母缩写--><div class="miui_tit"></div><div class="miui_txt"></div>...</div></div><div class="modulename_info_list"></div></div></div>
02. 命名方式
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 【后代选择器还是类名】关于CSS命名,最大的争论就是使用后代选择器还是使用类名。<ul class="list"><li class="list-item"></li><li class="list-item"></li><li class="list-item"></li></ul>如果采用第一种长类名的方式,为<li>元素设置样式,只需如下设置即可:.list-item{}这种方式的选择器效率最高,因为.list-item这个类型页面中只出现一次,可类比于id选择器的解析速度。由于使用长类名的方式,可以完全不使用后代选择器,则无需考虑选择器特殊性较低,样式无法生效的情况,也不会出现选择器层级过长,因为它仅有一级。但是,相应地,它最大的缺点是类名较长,大大地增加了HTML文件大小。于是,可借鉴京东,当子孙模块超过3级时,采用首字母缩写,并将缩写后首字母大写的做法,在如将.list-item-link-title缩写为.Lil-title// 选择可缩写的长类名作为CSS命名的主要方式。<ul class="list"><li class="item"></li><li class="item"></li><li class="item"></li></ul>如果采用第二种短类名的方式,则为<li>元素设置样式,需如下设置:.list .item{}1、选择器解析效率比第三种方式好,毕竟.item比li的范围小很多2、短类名.list .item同样存在依赖HTML结构的情况,很可能出现选择器层级过长3、使用较简易,在sass中书写容易,且起名也较简单4、由于给li增加了类名,于是增加了HTML文件大小<ul class="list"><li></li><li></li><li></li></ul>如果采用第三种后代选择器的方式,则为<li>元素设置样式,需如下设置:.list li{}// 如果从简易角度来看,第三种后代选择器的方式最简单,无需花时间去给子元素起名。但是,它有一个很严重的问题,就是如果HTML结构层级较深,往往出现选择器层级过长,如.list li span a{}。而且,因为后代选择器强烈地依赖HTML结构,为了避免因为少写一层结构,导致选择器特殊性降低,样式无法生效的情况,也不得不这样写。一个不得不提的问题是,CSS选择器的解析顺序是从右到左。而使用后代选择器.list li{},浏览器需要遍历出所有的li,再找出.list下的li,效率是最低的。【分隔符】一般地,classname分隔符有3种,中划线-,下划线_,以及首字母大写,以分隔list和item为例。//中划线list-item//下划线list_item//首字母大写listItem1. 中划线:可以用来表示层级关系<div class="box"><ul class="box-list"><li class="box-list-item"></li><li class="box-list-item"></li><li class="box-list-item"></li></ul></div>2. 下划线可以用来表示不同的状态<div class="box"><button class="box-btn box-btn_default" type="button"></button><button class="box-btn" type="button"></button></div>3、首字母大写首字母大写可以用来表示因为样式的需要,而不得不增加的HTML结构。一般地,如果在外层增加结构,可以增加Wrap,在内层增加结构,可以增加Inner,且不影响原先的classname的命名。<div class="boxWrap"><section class="box"><h2 class="box-title"></h2><p class="box-content"></p></section></div>【组件】通过上面的长命名方式和分隔符的使用,解决了基础结构的命名。但是,在页面中,很可能出现一些组件的应用,这些组件可以复用到页面的多个位置。这时,再使用上面的方式就不太合适。 于是,可以以m-为前缀,来表示这是一个组件。<div class="box"><button class="m-btn m-btn_error" type="button"></button><button class="m-btn" type="button"></button></div>
03. 命名推荐
有了合适的命名方式,还需要语义化命名,且有不影响语义的情况下,可以简写。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 【布局】文档 doc头部 header(hd)主体 body尾部 footer(ft)主栏 main侧栏 side容器 box/container【通用部件】列表 list列表项 item表格 table表单 form链接 link标题 caption/heading/title菜单 menu集合 group条 bar内容 content结果 result【组件】按钮 button(btn)字体 icon下拉菜单 dropdown工具栏 toolbar分页 page缩略图 thumbnail警告框 alert进度条 progress导航条 navbar导航 nav子导航 subnav面包屑 breadcrumb(crumb)标签 label徽章 badge巨幕 jumbotron面板 panel洼地 well标签页 tab提示框 tooltip弹出框 popover轮播图 carousel手风琴 collapse定位浮标 affix【语义化小部件】品牌 brand标志 logo额外部件 addon版权 copyright注册 regist(reg)登录 login搜索 search热点 hot帮助 help信息 info提示 tips开关 toggle新闻 news广告 advertise(ad)排行 top下载 download【功能部件】左浮动 fl右浮动 fr清浮动 clear【状态】前一个 previous后一个 next当前的 current显示的 show隐藏的 hide打开的 open关闭的 close选中的 selected有效的 active默认的 default反转的 toggle禁用的 disabled危险的 danger主要的 primary成功的 success提醒的 info警告的 warning出错的 error大型的 lg小型的 sm超小的 xs
04. 实践
关于CSS命名,并没有最佳实践之说,根据项目的复杂程序进行合适的命名才是可取的。
12345678910111213141516171819202122232425262728293031 <header class="hd"><nav class="hd-navbar m-navbar m-varbar_primary"><div class="hd-navbar-tel">联系方式:400-123-4567</div><ul class="hd-navbar-nav"><li class="Hnn-itm m-btn m-btn_info"><a href="#">登录</a></li><li class="Hnn-itm m-btn"><a href="#">快速注册</a></li><li class="Hnn-itm m-btn"><a href="#">关于</a></li><li class="Hnn-itm m-btn"><a href="#">帮助</a></li></ul></nav>...</header>【幻灯片】<div class="carousel"><div class="carousel-banner"><a class="carousel-banner-item Cbi_slide1 Cbi_active" href="#"></a><a class="carousel-banner-item Cbi_slide2" href="#"></a><a class="carousel-banner-item Cbi_slide3" href="#"></a><a class="carousel-banner-item Cbi_slide4" href="#"></a></div><a class="carousel-control carousel-control_prev" href="javascript:;"><</a><a class="carousel-control carousel-control_next" href="javascript:;">></a><div class="carousel-indicators"><span class="carousel-indicators-item Cii_active"></span><span class="carousel-indicators-item"></span><span class="carousel-indicators-item"></span><span class="carousel-indicators-item"></span></div></div>
代码规范
代码规范能够使CSS代码风格保持一致,使得CSS更容易理解和维护。
01. 代码风格
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 【选择器】1、选择器 与 { 之间包含空格.selector {}2、>、+、~ 选择器的两边各保留一个空格/* good */main > nav{}/* bad */main>nav {}【属性风格】1、属性名 与之后的 : 之间不包含空格, : 与 属性值 之间包含空格margin: 0;2、对于以逗号分隔的属性值,每个逗号后面都应该插入一个空格font-family: Arial, sans-serif;3、对于只包含一条声明的样式,为了易读性和便于快速编辑,建议将语句放在同一行。对于带有多条声明的样式,应当将声明分为多行。.selector {margin: 0;padding: 0;}.selector { margin: 0;}4、最后一个属性值也以分号结尾,这样可以减少修改、添加和维护代码时不必要的失误和麻烦/* good */.selector {margin: 0;padding: 0;}/* bad */.selector {margin: 0;padding: 0}【引号】1、文本内容用双引号包围html[lang|="zh"] q:before {font-family: "Microsoft YaHei", sans-serif;content: "“";}2、url() 函数中的路径不加引号body {background: url(bg.png);}【省略】1、对于属性值或颜色参数,省略小于 1 的小数前面的 0panel {opacity: .8}2、省略值为0时的单位,为节省不必要的字节同时也使阅读方便,将0px、0em、0%等值缩写为0.m-box{margin:0 10px;background-position:50% 0;}【缩写】1、尽量使用简写形式的十六进制值,例如,用 #fff 代替 #ffffff2、十六进制值应该全部小写,例如,#fff。在扫描文档时,小写字符易于分辨,因为他们的形式更易区分3、在可以使用缩写的情况下,尽量使用属性缩写,它最大的好处就是节省了字节,便于维护,并使阅读更加一目了然/* good */.post {font: 12px/1.5 arial, sans-serif;}/* bad */.post {font-family: arial, sans-serif;font-size: 12px;line-height: 1.5;}【媒体查询】将媒体查询@media放在尽可能相关规则的附近。不要将它们打包放在一个单一样式文件中或者放在文档底部。 如果把它们分开了,将来更容易被遗忘。.element { ... }.element-avatar { ... }.element-selected { ... }@media (min-width: 480px) {.element { ...}.element-avatar { ... }.element-selected { ... }}02. 注释
123456789101112131415161718192021222324 【单行注释】星号与内容之间保留一个空格,以确保即使在编码错误的情况下也可以正确解析样式/* 单行注释 */【块状注释】在必要的情况下,可以使用块状注释,块状注释保持统一的缩进对齐。星号要一列对齐,星号与内容之间保留一个空格。/*** 多行注释1* 多行注释2*/【文件注释】文件顶部必须包含文件注释,星号要一列对齐,星号与内容之间保留一个空格,标识符冒号与内容之间保留一个空格。用 @name 标识文件说明,@author标识作者,@description为文件或模块描述,@update为可选项,建议每次改动都更新一下。/*** @name: 文件名或模块名* @description: 文件或模块描述* @author: author-name(mail-name@qq.com)* author-name2(mail-name2@qq.com)* @update: 2017-07-14 00:00*/03. 声明顺序
123456789101112131415161718192021222324252627282930313233343536373839 1、私有在前,标准在后,即先写带有浏览器私有标志的,后写W3C标准的.m-box {-webkit-box-shadow: 0 0 0 #000;-moz-box-shadow: 0 0 0 #000;box-shadow: 0 0 0 #000;}2、相关的属性声明应当归为一组,并按照(布局类属性->盒模型属性->文本类属性->修饰类属性)顺序排列布局属性处在第一位,是因为它可以使一个元素脱离正常文本流,并且覆盖盒模型相关的样式。盒模型紧跟其后,因为它决定了一个组件的大小和位置。其他属性只在组件内部起作用或者不会对前面两种情况的结果产生影响,所以它们排在后面。布局类属性 position / top / right / bottom / left / float / display / overflow 等盒模型属性 border / margin / padding / width / height 等文本类属性 font / line-height / text-align / word-wrap 等修饰类属性 background / color / transition / list-style 等另外,如果包含 content 属性,应放在最前面.sidebar {/* formatting model */position: absolute;top: 50px;left: 0;overflow-x: hidden;/* box model */width: 200px;padding: 5px;border: 1px solid #ddd;/* typographic */font-size: 14px;line-height: 20px;/* visual */background: #f5f5f5;color: #333;-webkit-transition: color 1s;-moz-transition: color 1s;transition: color 1s;}04. 避免使用
12345678910111213141516171819 1、尽量不使用 !important 声明。当需要强制指定样式且不允许任何场景覆盖时,通过标签内联和 !important 定义样式。2、避免耗性能的属性,如express和filter。不过有时候需求大于一切/* expression */.class {width: expression(this.width>100?'100px':'auto');}/* filter */.class {filter: alpha(opacity=50);}3、避免使用 @import,与 link 标签相比,@import 指令要慢很多,不光增加了额外的请求次数,还会导致不可预料的问题。4、避免sass中不必要的嵌套,这是因为虽然可以使用嵌套,但是并不意味着应该使用嵌套。只有在必须将样式限制在父元素内(也就是后代选择器),并且存在多个需要嵌套的元素时才使用嵌套。5、尽量避免使用hack,由于浏览器自身缺陷,无法避开的时候,可以允许使用适当的Hack。统一使用“*”和“_”分别对IE7和6进行Hack/* IE7会显示灰色#888,IE6会显示白色#fff,其他浏览器显示黑色#000 */.m-list{color:#000;*color:#888;_color:#fff;}
编码技巧
以下从DRY、currentColor、inherit和合理使用简写几方面来简单介绍CSS编码技巧。
01. DRY
DRY,即don`t repeat yourself,尽量减少代码重复。
在软件开发中,保持代码的DRY和可维护性是最大的挑战之一,而这句话对CSS也是适用的。在实践中,代码可维护性的最大要素是尽量减少改动时要编辑的地方。灵活的CSS通常更容易扩展。在写出基础样式之后,只用极少的代码就可以扩展出不同的变体,因为仅需覆盖一些变量就可以了。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 下面这段代码在可维护性方面存在一些问题:<style>div{width:100px;padding:6px 16px;border:1px solid #446d88;background:#58a linear-gradient(#77aebb,#58a);border-radius:4px;box-shadow:0 1px 5px gray;color:white;text-shadow:0 -1px 1px #335166;font-size:20pxline-height 30px;}</style><div>YES</div>下面来对上面糟糕的代码一一修复 :1、如果决定改变字号,就得同时调整行高,因为这两个属性都写成了绝对值。当某些值相互依赖时,它们的相互关系要用代码表达出来。font-size:20px;line-height:1.5;2、如果把这些长度值都改成em单位,那这些效果的值就可以都变成可缩放的了,而且是依赖字号进行缩放。padding:.3em .8em;border:1px solid #446d88;background:#58a linear-gradient(#77aebb,#58a);border-radius:.2em;box-shadow:0 .05em .25em gray;color:white;text-shadow:0 -.05em .05em #335166;font-size:125%;line-height:1.5;3、颜色是另一个重要的变数。如果要改变颜色,可能需要覆盖四条声明:(border-color、background、box-shadow和text-shadow)。其实只要把半透明的黑色或白色叠加在主色调上,即可产生主色调的亮色和暗色变体,这样就能简单地化解这个难题了。padding:.3em .8em;border:1px solid rgba(0,0,0,0.1);background:#58a linear-gradient(hsla(0,0%,100%,.2),transparent);border-radius:.2em;box-shadow:0 .05em .25em rgba(0,0,0,0.5);color:white;text-shadow:0 -.05em .05em rgba(0,0,0,0.5);font-size:125%;line-height:1.5;现在只需要覆盖background-color属性,就可以得到不同颜色版本的按钮了!.no{background-color: #c00;}.ok{background-color: #6b0;}【代码易维护vs代码量少】有时候,代码易维护和代码量少不可兼得。比如,为一个元素添加一道10px宽的边框,但左侧不加边框。border-width : 10px 10px 10px 0;只要这一条声明就可以搞定了,但如果日后要改动边框的宽度,需要同时改三个地方。如果把它拆成两条声明的话,改起来就容易多了,而且可读性或许更好一些。border-width: 1px;border-left-width: 0;
02. currentColor
在CSS3中,得到了一个特殊的颜色关键字currentColor,它是从SVG那里借鉴来的。这个关键字并没有绑定到一个固定的颜色值,而是一直被解析为color。实际上,这个特性让它成为了CSS中有史以来的第一个变量。虽然功能很有限,但它真的是个变量。
12 如,让所有的水平分割线自动与文本的颜色保持一致。有了currentcolor之后,只需要这样写:hr{background:currentColor;}
03. inherit(继承)
inherit可以用在任何CSS属性中,而且它总是绑定到父元素的计算值(对伪元素来说,则会取生成该伪元素的宿主元素)。
1234 如,把表单元素的字体设定为与页面其他部分相同,并不需要重复指定字体属性,只需利用inherit特性即可。input,select,button{font:inherit;}与此类似,要把超链接的颜色设定为页面中其他文本相同,也是用inherit。a{color:inherit;}
04. 合理使用简写
1234567891011121314 以下两行CSS代码并不是等价的background : rebeccapurplebackground-color : rebeccapurple不要害怕使用简写属性。合理使用简写是一种良好的防卫性编码方式,可以抵御未来的风险。当然,如果要明确地去覆盖某个具体的展开式属性并保留其他相关样式,那就需用展开式属性。background: url(tr.png) no-repeat top right / 2em 2em,url(br.png) no-repeat bottom right / 2em 2em,url(b1.png) no-repeat bottom left / 2em 2em;可以简写为:background : ur1(tr.png) top right,url(br.png) bottom right,url(b1.png) bottom left;background-size : 2em 2em;background-repeat : no-repeat;