自從開始做前端開發以來,我發現在開發頁面的時候,總是有一個問題十分影響自己的開發效率,這個問題就是css的命名,主要是指css類選擇器的命名。這個問題主要體現在:第一,有的內容你壓根想不出用什么名字來給它命名,因為一般命名總是考慮語義化,好讓其他人看到這個css類的名字就知道它是作用於哪一個內容的,但是由於網頁內容的復雜性和多樣性,你很難保證每個部分都能起一個合適的名字,即使你最終迫不得已想出了一個名字,也會有這個名字是否是最合適的這種糾結存在,而且最要命的是,這個命名的過程是一項非常辛苦的腦力活動,會耗費掉很多腦細胞,這一件很不值得的事情;第二,由於命名的時候是語義化的命名,這一點可能會阻礙css代碼的重用,比如說某一個網頁的內容用.title來描述它的樣式,這個title包含了2條規則,{font-size: 14px; line-height: 20px},此時網頁的另一個內容可能需要跟這個title具有一模一樣的樣式,但是從另一個內容所處的網頁位置來說,可能用.desc來命名才是更合適的選擇,這個時候,我相信喜歡語義化命名的人肯定會把那個內容再單獨起一個css類desc,然后把title的樣式復制過來,結果就導致css文件中會存在兩份相同的樣式規則,只是命名不同而已,這樣代碼就重復了。
解決這個問題的方法就是采用面向屬性的css命名,把那些我們實在想不出名字的,而且沒有必要起名字的,並且可以只用單一的css屬性或者組合的單一css屬性來描述的部分,通通都用面向屬性的css類來控制樣式,讓你從煩亂的css命名的漩渦中徹底解放出來,除了提高你的工作效率,最重要的是減少你腦細胞的損耗,讓你不會那么辛苦。
首先要聲明,面向屬性的css命名這個思想不是我的原創,它來自於張鑫旭的博客。我是當時比較糾結於css的命名問題,然后找到了他的兩篇文章,對我重新認識css的命名以及如何組織全站的css有很多的幫助,這兩篇文章分別是:
精簡高效的CSS命名准則/方法
我是如何對網站CSS進行架構的
你可以先去通過他的文章了解這個命名思想的起源,再回來看我的一些總結跟應用。
命名方法
這個方法,簡單來說,就是直接以css屬性簡寫作為css的類名,在使用的時候,通過使用一個或組合多個這樣的簡寫形式的css類來達到控制樣式的目的。比如說網頁中有一個網頁內容,是一段居中的文本,大小為12px,行高為20px,段前后間距分別為10px和15px,那么就可以定義一下這些簡單的屬性類:
.tc {text-align: center;} .f12 {font-size: 12px;} .lh20 {line-height: 20px;} .mt10 {margin-top: 10px;} .mtb15 {margin-bottom: 15px;}
在頁面中使用的時候,直接組合以上這些css屬性類即可:
<p class="tc f12 lh20 mt10 mb15">…</p>
這就是這種屬性命名方法的具體使用方式。
css中有很多的屬性都可以采用這種方法來命名。在張鑫旭的博客中,他把自己的這套方法總結成了一個開源的css庫:https://github.com/zhangxinxu/zxx.lib.css/blob/master/zxx.lib.css。我們可以先從他這個庫來了解他本人是如何組織這些不同的css屬性類的,然后再來討論這其中的一些問題。
這是他的開源庫中,采用面向屬性命名的全部css類(以下代碼僅是為了閱讀本文方便才引用,如果是想在實際工作中使用,最好是關注張鑫旭本人的github或者博客,因為他會不斷地優化自己的東西):
/* display */ .dn{display:none;} .di{display:inline;} .db{display:block;} .dib{display:inline-block;} div.dib{*display:inline; *zoom:1;}/* other block level tag(eg. p, li, h1~h6), using 'inline_any' instead */ /* height */ .h0{height:0;} .h16{height:14px;} .h16{height:16px;} .h18{height:18px;} .h20{height:20px;} .h22{height:22px;} .h24{height:24px;} .h30{height:30px;} /* width */ /* fixed width value */ .w20{width:20px;} .w50{width:50px;} .w70{width:70px;} .w100{width:100px;} .w120{width:120px;} .w140{width:140px;} .w160{width:160px;} .w180{width:180px;} .w200{width:200px;} .w220{width:220px;} .w250{width:250px;} .w280{width:280px;} .w300{width:300px;} .w320{width:320px;} .w360{width:360px;} .w400{width:400px;} .w460{width:460px;} .w500{width:500px;} .w600{width:600px;} .w640{width:640px;} .w700{width:700px;} /* percent width value */ .pct10{width:10%;} .pct15{width:15%;} .pct20{width:20%;} .pct25{width:25%;} .pct30{width:30%;} .pct33{width:33.3%;} .pct40{width:40%;} .pct50{width:50%;} .pct60{width:60%;} .pct66{width:66.6%;} .pct70{width:70%;} .pct75{width:75%;} .pct80{width:80%;} .pct90{width:90%;} .pct100{width:100%;} /* line-height */ .lh0{line-height:0;} .lh16{line-height:14px;} .lh16{line-height:16px;} .lh18{line-height:18px;} .lh20{line-height:20px;} .lh22{line-height:22px;} .lh24{line-height:24px;} .lh30{line-height:30px;} /* margin */ .m0{margin:0;} .ml1{margin-left:1px;} .ml2{margin-left:2px;} .ml5{margin-left:5px;} .ml10{margin-left:10px;} .ml15{margin-left:15px;} .ml20{margin-left:20px;} .ml30{margin-left:30px;} .mr1{margin-right:1px;} .mr2{margin-right:2px;} .mr5{margin-right:5px;} .mr10{margin-right:10px;} .mr15{margin-right:15px;} .mr20{margin-right:20px;} .mr30{margin-right:30px;} .mt1{margin-top:1px;} .mt2{margin-top:2px;} .mt5{margin-top:5px;} .mt10{margin-top:10px;} .mt15{margin-top:15px;} .mt20{margin-top:20px;} .mt30{margin-top:30px;} .mb1{margin-bottom:1px;} .mb2{margin-bottom:2px;} .mb5{margin-bottom:5px;} .mb10{margin-bottom:10px;} .mb15{margin-bottom:15px;} .mb20{margin-bottom:20px;} .mb30{margin-bottom:30px;} /* margin negative */ .ml-1{margin-left:-1px;} .mr-1{margin-right:-1px;} .mt-1{margin-top:-1px;} .mb-1{margin-bottom:-1px;} .ml-3{margin-left:-3px;} .mr-3{margin-right:-3px;} .mt-3{margin-top:-3px;} .mb-3{margin-bottom:-3px;} .ml-20{margin-left:-20px;} .mr-20{margin-right:-20px;} .mt-20{margin-top:-20px;} .mb-20{margin-bottom:-20px;} /* padding */ .p0{padding:0;} .p1{padding:1px;} .pl1{padding-left:1px;} .pt1{padding-top:1px;} .pr1{padding-right:1px;} .pb1{padding-bottom:1px;} .p2{padding:2px;} .pl2{padding-left:2px;} .pt2{padding-top:2px;} .pr2{padding-right:2px;} .pb2{padding-bottom:2px;} .pl5{padding-left:5px;} .p5{padding:5px;} .pt5{padding-top:5px;} .pr5{padding-right:5px;} .pb5{padding-bottom:5px;} .p10{padding:10px;} .pl10{padding-left:10px;} .pt10{padding-top:10px;} .pr10{padding-right:10px;} .pb10{padding-bottom:10px;} .p15{padding:15px;} .pl15{padding-left:15px;} .pt15{padding-top:15px;} .pr15{padding-right:15px;} .pb15{padding-bottom:15px;} .p20{padding:20px;} .pl20{padding-left:20px;} .pt20{padding-top:20px;} .pr20{padding-right:20px;} .pb20{padding-bottom:20px;} .p30{padding:30px;} .pl30{padding-left:30px;} .pt30{padding-top:30px;} .pr30{padding-right:30px;} .pb30{padding-bottom:30px;} /* border-color name rule: border(b)-position(l/r/t/b/d)-width(null/2)-style(null/sh)-color(first one letter/first two letter) |-> All colors are safe color*/ .bdc{border:1px solid #ccc;} .blc{border-left:1px solid #ccc;} .brc{border-right:1px solid #ccc;} .btc{border-top:1px solid #ccc;} .bbc{border-bottom:1px solid #ccc;} .bdd{border:1px solid #ddd;} .bld{border-left:1px solid #ddd;} .brd{border-right:1px solid #ddd;} .btd{border-top:1px solid #ddd;} .bbd{border-bottom:1px solid #ddd;} .bde{border:1px solid #eee;} .ble{border-left:1px solid #eee;} .bre{border-right:1px solid #eee;} .bte{border-top:1px solid #eee;} .bbe{border-bottom:1px solid #eee;} /* background-color name rule: bg - (key word/Hex color) |-> All colors are safe color */ .bgwh{background-color:#fff;} .bgfb{background-color:#fbfbfb;} .bgf5{background-color:#f5f5f5;} .bgf0{background-color:#f0f0f0;} .bgeb{background-color:#ebebeb;} .bge0{background-color:#e0e0e0;} /* safe color */ .g0{color:#000;} .g3{color:#333;} .g6{color:#666;} .g9{color:#999;} .gc{color:#ccc;} .wh{color:white;} /* font-size */ .f0{font-size:0;} .f12{font-size:12px;} .f13{font-size:13px;} .f14{font-size:14px;} .f16{font-size:16px;} .f18{font-size:18px;} .f20{font-size:20px;} .f24{font-size:24px;} .f28{font-size:28px;} /* font-family */ .fa{font-family:Arial;} .ft{font-family:Tahoma;} .fv{font-family:Verdana;} .fs{font-family:Simsun;} .fl{font-family:'Lucida Console';} .fw{font-family:'Microsoft Yahei';} /* font-style */ .n{font-weight:normal; font-style:normal; white-space: normal;} .b{font-weight:bold;} .i{font-style:italic;} /* text-align */ .tc{text-align:center;} .tr{text-align:right;} .tl{text-align:left;} .tj{text-align:justify;} /* text-decoration */ .tdl{text-decoration:underline;} .tdn,.tdn:hover,.tdn a:hover,a.tdl:hover{text-decoration:none;} /* letter-spacing */ .lt-1{letter-spacing:-1px;} .lt0{letter-spacing:0;} .lt1{letter-spacing:1px;} /* white-space */ .nowrap{white-space:nowrap;} /* word-wrap */ .bk{word-wrap:break-word;} /* vertical-align */ .vm{vertical-align:middle;} .vtb{vertical-align:text-bottom;} .vb{vertical-align:bottom;} .vt{vertical-align:top;} .v-1{vertical-align:-1px;} .v-2{vertical-align:-2px;} .v-3{vertical-align:-3px;} .v-4{vertical-align:-4px;} .v-5{vertical-align:-5px;} /* float */ .l{float:left;} .r{float:right;} /* clear */ .cl{clear:both;} /* position */ .rel{position:relative;} .abs{position:absolute;} /*z-index*/ .zx1{z-index:1;} .zx2{z-index:2;} /* cursor */ .poi{cursor:pointer;} .def{cursor:default;} /* overflow */ .ovh{overflow:hidden;} .ova{overflow:auto;} /* visibility */ .vh{visibility:hidden;} .vv{visibility:visible;} /* opacity */ .opa0{opacity:0; filer:alpha(opacity=0);} /* zoom */ .z{*zoom:1;}
首先他這部分代碼里面,包含了我們在網頁開發中大部分常用的css屬性,如display,height,margin,padding,border,color,font-size等。在屬性類的命名上,基本上都是采取屬性跟屬性值的縮寫。其他可說明的是:
1)width除了有固定值的屬性類定義外,還包含了百分比的屬性類定義,畢竟這個在實際工作中也時有用到;
2)margin,border,padding由於包含上下左右相關的屬性,所以他還提供了針對上下左右單邊的屬性類,方便單獨使用。
另外他的代碼都有瀏覽器兼容性方面的考慮,所以要是在自己的工作中用的話,最好是參考着他的來。
這種方法在我使用之前,我比較顧慮的是它的可維護性。因為這些屬性類很多都包含屬性值,比如.f12{font-size: 12px},所以在html元素的class屬性值就肯定會包含f12這樣的css屬性類名,假如要修改的對應的屬性值該怎么辦呢?那么就需要修改三個地方才行:首先是屬性值定義的地方,第二是屬性類名定義的地方,最后就是在html中使用的地方。當時想到這個問題的時候,我覺得這種方法不可行,因為在實際工作中,尼瑪UI崗位的同事改設計的情況太多了,那樣的話,頁面上用到這種屬性命名類的地方都要經常改來改去。
但是后來我發現,即使不用這種命名方法,我還是改變不了UI調整設計圖的情況,而且只要設計圖一改,甚至我的html結果以及我那些采用語義化命名的css類都要改,那個麻煩程度其實比用屬性命名類的方法更厲害,所以我最后就開始在項目中嘗試這個方法。結果發現,其實特別好用,尤其是做些文本類的排版,垂直布局,分欄布局,以及百分比布局等特別簡單高效,前面提到的那個維護的問題也很小。我有兩個方法來解決來那個問題:
1)假如原先用f12,后來設計把font-size改成14px,那么我只用再增加一個f14即可,再把原先html中需要把f12替換成f14的地方,換成f14即可。如果f12沒有別的地方用到了,我會考慮把f12再刪掉。
2)假如原先用f54,由於這種屬性類並不具備通用性,所以我可能考慮直接把f54替換成我需要的屬性類,比如f52。
在本文本部分的最后,我還會給出自己關於這種使用方法的建議以及對維護問題的處理補充。現在先回來再看看張鑫旭的這些代碼,我從個人的角度,結合自己在項目中的實際情況,來說下需要我們改善下的地方。
1)有些采用固定值的屬性類有多余的,也有缺少的;比如沒有.h28表示height: 28px的,.w100到.w700可能都是用不到的
2)跟顏色相關的可能大部分都不一定符合項目需求,尤其是那種做出來完全沒有任何規范的設計圖,肉眼看上去相同的顏色,實際上卻是不一樣的顏色;相同的版本,在不同的頁面,有可能也使用了不同的顏色;甚至是那種色系比較豐富的設計。這些屬性類包括border,background,color。當然純黑色和純白色還是可以統一起來的,畢竟這兩個顏色基本上各個網站都會用到。
3)還有些屬性類也是多余的,比如font-family,因為我在項目中有用less,font-family是在別的地方定義的,所以這里就不需要了。當然你要是覺得這個還是有用得着的話,可以考慮留下。
4)還可以考慮增加些其它的css屬性類,比如border-radius以及flex等。border-radius現在用的已經很普遍了,flex在移動端也有可以用的到的地方。這個就得根據自己的項目實際情況,慢慢增加了。
綜合以上這些內容,我對於這種面向屬性命名的方法建議如下:
1)首先肯定是得以張鑫旭的這套代碼為基礎;
2)對於height,line-height,font-size這三個屬性,划分屬性類的時候,盡量以步長為2的等差分布來定義,如:
.h0 , .h18 , .h20 , .h22 , .h24 , .h26 , .h28 , .h30 , .h32 , .h34 , .h36 , .h38 , .h40;
.lh18 , .lh20 , .lh22 , .lh24 , .lh26 , .lh28 , .lh30 , .lh32 , .lh34 , .lh36 , .lh38 , .lh40 ;
.f12 , .f14 , .f16 , .f18 , .f20 , .f22 , .f24 , .f26 , .f28 , .f30 ;
一來是為了保證這些小范圍的的尺寸都能覆蓋到;二是為了保證各個尺寸都是偶數,方便布局。
3)對於width,100以內的固定值,可以考慮以10為步長定義一個等差分布序列:
.w0 , .w10 , .w20 , .w30 , .w40 , .w50 , .w60 , .w70 , .w80 , .w90 , .w100
其它的固定值的屬性類可以等到實際用到的時候再追加;
對於百分比的width,可以把10%到100%的值都定義出來,然后針對1/3 , 1/4 , 1/5, 1/6 也單獨定義出來,因為這些都屬於常用的一些布局比例,所以可以考慮提前定義。
4)margin跟padding的屬性類有的可能是多余的,也有可能有缺少的,但是不能提前定義太多,可以考慮在實際用的過程中再追加;
5)border,background-color以及color可以考慮留下。由於這幾個跟顏色有關,所以可以把設計圖中最常用的幾種顏色也抽出來分別定義追加進去,假如設計師比較有經驗的話,做出來的東西就會比較規范,尤其是在通用的顏色這一塊,不會搞出很多的顏色出來。在zxx.lib.css中,已定義的border,background-color還有color都是安全色,如果是設計師的顏色,其實也能定義成屬性類,比如#7c7c7c,就可以定義成.c7c,bg7c,bd7c。
6)可以根據項目的實際情況增加border-radius以及flex等屬性類。定義方式完全跟其它屬性一樣,如flex的:
.df { display: flex; } .dif { display: inline-flex; } .fdr { flex-direction: row; } .fdrr { flex-direction: row-reverse; } .fdc { flex-direction: column; } .fdcr { flex-direction: column-reverse; } .fwn { flex-wrap: nowrap; } .fww { flex-wrap: wrap; } .fwr { flex-wrap: wrap-reverse; } .jcfs { justify-content: flex-start; } .jcfe { justify-content: flex-end; } .jcc { justify-content: center; } .jcsb { justify-content: space-between; } .jcsa { justify-content: space-around; } .aifs { align-items: flex-start; } .aife { align-items: flex-end; } .aic { align-items: center; } .aib { align-items: baseline; } .ais { align-items: stretch; } .acfs { align-content: flex-start; } .acfe { align-content: flex-end; } .acc { align-content: center; } .acsb { align-content: space-between; } .acsa { align-content: space-around; } .acs { align-content: stretch; } .fxa { flex: auto; } .fxn { flex: none; } .fx1 { flex: 1; } .fx2 { flex: 2; } .fx3 { flex: 3; } .fx4 { flex: 4; } .fx5 { flex: 5; } .fx6 { flex: 6; }
以上這部分flex的屬性類需結合auto-prefix這種工具來使用,因為有兼容性問題,需要統一添加前綴。
7)關於這些面向屬性的css類組織:
第一,按照前面的這些建議,在張鑫旭的代碼的基礎上,調整成自己的項目所需之后,就應該把這個代碼單獨存放起來,作為一個像bootstrap這樣的單獨的庫來使用;
第二,在實際工作過程中,如果要增加新的css屬性類,只有在這個屬性類有公用的價值,才能添加到第一步的公共屬性類庫里面去,否則的話,就只能在當前頁面的main css里面去寫。
8)最后,就是在堅持沒有重復的代碼前提下,根據實際情況去追加相關的css屬性類。有公用性的就加到單獨的庫里,沒公用性的話就追加到頁面的main css里。
這些建議,也只是我個人的使用經驗總結,有比較多的個人想法,如果覺得不對或者有疑問的話,歡迎私信或者評論交流。本文最重要的目的是分享這種面向屬性的命名方法,我相信肯定會有朋友能夠看到這個方法的價值的。
最后在張鑫旭的代碼中,還有一部分代碼,定義了很多簡單常用的css類,比如浮動,浮動清除等等:
/* 塊狀元素水平居中 */ .auto{margin-left:auto; margin-right:auto;} /* 清除浮動*/ .fix{*zoom:1;} .fix:after{display:table; content:''; clear:both;} /* 基於display:table-cell的自適應布局 */ .cell{display:table-cell; *display:inline-block; width:2000px; *width:auto;} /* 雙欄自適應cell部分連續英文字符換行 */ .cell2{overflow:hidden; _display:inline-block;} /* 單行文字溢出虛點顯 示*/ .ell{text-overflow:ellipsis; white-space:nowrap; overflow:hidden;} /* css3過渡動畫效果 */ .trans{ -webkit-transition:all .15s; transition:all .15s; } /* 大小不定元素垂直居中 */ .dib_vm{display:inline-block; width:0; height:100%; vertical-align:middle;} /* 加載中背景圖片 - 如果您使用該CSS小庫,務必修改此圖片地址 */ .loading{background:url(about:blank) no-repeat center;} /* 無框文本框文本域 */ .bd_none{border:0; outline:none;} /* 絕對定位隱藏 */ .abs_out{position:absolute; left:-999em; top:-999em;} .abs_clip{position:absolute; clip:rect(0 0 0 0);} /* 按鈕禁用 */ .disabled{outline:0 none; cursor:default!important; opacity:.4; filer:alpha(opacity=40); -ms-pointer-events:none; pointer-events:none;} /*inline-block與float等寬列表*/ .inline_box{font-size:1em; letter-spacing:-.25em; font-family:Arial;} .inline_two, .inline_three, .inline_four, .inline_five, .inline_six, .inline_any{display:inline-block; *display:inline; letter-spacing:0; vertical-align:top; *zoom:1;} .float_two, .float_three, .float_four, .float_five, .float_six{float:left;} .inline_two, .float_two{width:50%; *width:49.9%;} .inline_three, .float_three{width:33.33333%; *width:33.3%;} .inline_four, .float_four{width:25%; *width:24.9%;} .inline_five, .float_five{width:20%; *width:19.9%;} .inline_six, .float_six{width:16.66666%; *width:16.6%;} .inline_fix{display:inline-block; width:100%; height:0; overflow:hidden;}
這些代碼也可以根據實際情況稍微調整,大部分在實際工作中都有使用到的場景,這里僅作引用介紹,因為使用起來也很簡單的。
應用實踐
為了說明這個命名方法的作用,我做了一個demo,以博客園博客列表頁來說明如何應用這種命名方法。先來看博客列表頁的結構:
可以看到這個列表頁其實是用到了很多語義化的命名的css類的,假如要用面向屬性的命名方法來定義,就會變成下面這個樣子:
實際效果如下:
相關源碼可訪問以下鏈接查看:
http://liuyunzhuge.github.io/blog/css_name/html/demo.html
在以上這個實踐過程中,並沒有所有的樣式都使用這種命名方法,主要的原因是單純的屬性命名對無法對偽類或者偽元素進行很好的樣式控制,而正好博客園列表頁中的每個鏈接的樣式都不一樣,所以沒辦法統一。這也正是面向屬性的命名方法的一種限制情形。
注意事項
雖然本文的目的是在推崇這種面向屬性的命名方法,但是你從文中的內容也可以看到,這種方法是有針對性的,前面一開始介紹的時候就說過:
采用面向屬性的css命名,把那些我們實在想不出名字的,而且沒有必要起名字的,並且可以只用單一的css屬性或者組合的單一css屬性來描述的部分,通通都用面向屬性的css類來控制樣式
使用這個方法的最大前提就是沒有必要起名字,並且能夠用組合的單一屬性來描述的內容,就可以這種方法來加速頁面布局的工作。像前面應用實踐介紹過的那種情形一樣,當你需要配合偽類,偽元素或者背景圖片的時候,就不太適合用這種方法。
在面向屬性的命名方法不能使用的時候,有另外兩種css的命名或者說組織方式可以使用:
1)語義化的命名,在整個頁面,語義化的css命名還是不可獲缺的一部分,尤其是那些划分頁面模塊的,比如.header .footer .logo等等,抽象公共樣式或者公共組件的,如.dropdown,.btn,.tab等等。這些是css模塊化,代碼重用的比較大的組織單位,如果把它們也拆分了,會使得整個站點的css結構非常的復雜,那樣的話還不如直接用style呢;
2)采用層級來命名,而且要多用直接子元素選擇器,雖然在張鑫旭的博客中不建議css有層級,但是有的時候如果不想命名,又無法用面向屬性的命名方法來解決的設計,可以考慮用層級來解決,在bootstrap的源碼中很多的css組件,比如nav,dropdown,tab等等,都是通過層級來控制的,一來是起到命名空間的作用,二來是減少對層數較深的子孫元素產生影響。但是層數也不能太深,最好不要超過3層,否則html結構變化之后,就會影響css代碼的結構。
本文總結
本文主要是傳播面向屬性的css命名方法這種思想,由於它在我實際工作中幫助我減少了很多不必要的css命名,所以我專門寫了這篇文章把它分享出來。這個里面也包含了很多自己在工作中產生的想法,不一定符合你自己的實際需求,要是感興趣的話,可以去研究下張鑫旭的那2篇文章,相信你自己也能夠總結出一些屬於自己的東西。感謝閱讀:)