如何寫一份不錯(cuò)的CSS代碼?
大廠技術(shù) 堅(jiān)持周更 精選好文
背景介紹:當(dāng)我們?cè)趶氖麓箜?xiàng)目或團(tuán)隊(duì)開發(fā)工作時(shí),我們經(jīng)常會(huì)發(fā)現(xiàn)我們寫的代碼,凌亂、難以閱讀并且難以擴(kuò)展。尤其是當(dāng)一段時(shí)候后我們回頭再看自己的代碼,必須回想起當(dāng)初自己寫的時(shí)候的思路才能看懂。
因此,人們嘗試在代碼風(fēng)格上保持統(tǒng)一,然而,最大的困難是:修改一個(gè)較小的問(wèn)題,都可能創(chuàng)建更多丑陋的 hack,也可能 CSS 的小改變會(huì)影響 JavaScript 的功能。但是這些問(wèn)題能在我們的項(xiàng)目開始的時(shí)候精心規(guī)劃,就能很大程度上避免這些問(wèn)題。今天就來(lái)討論一下如何寫一份不錯(cuò)的CSS代碼
一個(gè)好的css代碼是什么樣的呢
保持樣式表可維護(hù) 保持代碼可讀性 保持樣式表的可擴(kuò)展性
要保持良好的CSS代碼,首先需要訂立一致的CSS團(tuán)隊(duì)規(guī)范,這就必須從CSS架構(gòu)講起。
CSS架構(gòu)
目前CSS主要有以下五種設(shè)計(jì)架構(gòu)
1. OOCSS
面向?qū)ο蟮腃SS,
結(jié)構(gòu)和主題分離 - 減少對(duì) HTML 結(jié)構(gòu)的依賴 主題和主題分離 - 增加樣式的復(fù)用性
在OOCSS的基礎(chǔ)上,出現(xiàn)了另一種設(shè)計(jì)模式
2. BEM
也可以被當(dāng)成一種命名規(guī)范,本質(zhì)上使頁(yè)面結(jié)構(gòu)清晰
塊(Block)、元素(Element__)、修飾符(Modifier--)

有以下幾個(gè)規(guī)則
Block元素應(yīng)該以元素本身的屬性為主 Element則以元素位置和形狀為主 Modifier則修飾當(dāng)前的狀態(tài)和主題 Element一定是在Block之中,而不能獨(dú)立于Block之外 Modifier則更多的表示當(dāng)前組件的形狀和狀態(tài)
可以明顯發(fā)現(xiàn)
結(jié)構(gòu)清晰 定位迅速 功能明確
在面對(duì)組件化的場(chǎng)景時(shí),Block 代表邏輯上和功能上獨(dú)立的頁(yè)面組件。Element封裝了行為(JavaScript)、模板、樣式(CSS)和其他實(shí)現(xiàn)技術(shù)。
舉個(gè)例子
<header class="header">
<img class="logo">
<form class="search-form">
<input class="input">
<button class="button"></button>
</form>
<ul class="lang-switcher">
<li class="lang-switcher__item">
<a class="lang-switcher__link" href="url">en</a>
</li>
<li class="lang-switcher__item">
<a class="lang-switcher__link--active" href="url">ru</a>
</li>
</ul>
</header>block-name__element-name--modifier-name--modifier-value
在React當(dāng)中,也采用了這樣的命名方式

BEMnaming工具[1],提供BEM命名的檢測(cè)
然而在面對(duì)大型的項(xiàng)目時(shí)CSS的凌亂也很難讓開發(fā)者愿意在茫茫多的代碼中尋找可復(fù)用的代碼
3. SMACSS
(What’s Smacss)[https://smacss.com/]
設(shè)計(jì)的主要規(guī)范有三點(diǎn):
Categorizing CSS Rules(為css分類) Naming Rules(命名規(guī)范) Minimizing the Depth of Applicability(最小化適配深度)
為了實(shí)現(xiàn)清晰的CSS結(jié)構(gòu),將CSS分為
Base - 全局樣式,如global-reset、normalize.css Layout - 頁(yè)面布局,如grid Module - 組件布局 State - 元素狀態(tài),如visible、hidden Theme or Skin - 更多是具體主題的配置樣式 JavaScript 勾子 (JavaScript hooks)
其中尤其建議JavaScript解除和樣式的耦合
<button class="btn btn--buy js-buy-now"></button>命名規(guī)范上出現(xiàn)了一些差異
.layout-header
.is-hidden
.theme-nav最小化適配深度,減少html和css的耦合度,避免html的變動(dòng)增加對(duì)css的影響
.sidebar ul h3 {}
.side {}4. ITCSS
對(duì)CSS進(jìn)行了更加詳細(xì)的分層

如果從功能的角度上看呢,是將Base分成了Settings、Tools、Generic和Base,而Objects、Components和Trumps則分別對(duì)應(yīng)Layout、Module、(State、Theme),而這樣設(shè)計(jì)的好處在于可以將代碼的復(fù)用性進(jìn)一步提升
5. ACSS
一個(gè)樣式屬性一個(gè)類,其中的典型代表就是TailwindCSS[2],缺點(diǎn)則是破壞了語(yǔ)義化
.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 }
<div className="m-2 p-2 text-2xl text-gray-500">I am Ok</div>而上述的架構(gòu)思想,更多則是需要團(tuán)隊(duì)成員的一致性認(rèn)同,才能實(shí)現(xiàn)在代碼風(fēng)格上的統(tǒng)一。
除了這些開發(fā)自律性上的代碼規(guī)范外,還有什么其他的方式來(lái)提升CSS質(zhì)量呢?
CSS預(yù)處理器
在預(yù)處理器中,同樣提供了眾多的方法來(lái)簡(jiǎn)化與控制CSS代碼,以stylus為例
1. 變量
font-size = 14px
body
font font-size Arial, sans-serif
pad(types = padding, n = 5px)
if padding in types
padding n
if margin in types
margin n
body
pad()
body
pad(margin)
body
pad(padding margin, 10px)
// Yields:
body {
padding: 5px;
}
body {
margin: 5px;
}
body {
padding: 10px;
margin: 10px;
}2. 函數(shù)
add(a, b = a)
a + b
add(10, 5)
// => 15
get(hash, key)
return pair[1] if pair[0] == key for pair in hash
hash = (one 1) (two 2) (three 3)
get(hash, two)
// => 2
get(hash, three)
// => 3
get(hash, something)
// => null3. 內(nèi)建函數(shù)
// 提取顏色分量
red(#c00)
// => 204
red(#000, 255)
// => #f004. 插值
// 屬性插值
vendor(prop, args)
-webkit-{prop} args
-moz-{prop} args
{prop} args
border-radius()
vendor('border-radius', arguments)
box-shadow()
vendor('box-shadow', arguments)
button
border-radius 1px 2px / 3px 4px
// Yields:
button {
-webkit-border-radius: 1px 2px / 3px 4px;
-moz-border-radius: 1px 2px / 3px 4px;
border-radius: 1px 2px / 3px 4px;
}
// 選擇器插值
table
for row in 1 2 3 4 5
tr:nth-child({row})
height: 10px * row
// Yields:
table tr:nth-child(1) {
height: 10px;
}
table tr:nth-child(2) {
height: 20px;
}
table tr:nth-child(3) {
height: 30px;
}
table tr:nth-child(4) {
height: 40px;
}
table tr:nth-child(5) {
height: 50px;
}
mySelectors = '#foo,#bar,.baz'
{mySelectors}
background: #000
Yields:
#foo,
#bar,
.baz {
background: #000;
}
// 對(duì)象插值
foo = {
width: 10px,
height: 20px,
'&:hover': {
padding: 0
}
}
.bar
{foo}
Yields:
// => .bar {
// width: 10px;
// height: 20px;
// }
// .bar:hover {
// padding: 0;
// }5. @EXTEND
form
input[type=text]
padding: 5px
border: 1px solid #eee
color: #ddd
textarea
@extends form input[type=text]
padding: 10px
//Yielding:
form input[type=text],
textarea {
padding: 5px;
border: 1px solid #eee;
color: #ddd;
}
textarea {
padding: 10px;
}對(duì)于維護(hù)一份高質(zhì)量的CSS代碼,注釋和間隔必不可少
以下是一種比較建議的注釋和間隔方式,可以自行取用。
/*------------------------------------*\
#A-SECTION
*------------------------------------*/
.selector { }
/*------------------------------------*\
#ANOTHER-SECTION
*------------------------------------*/
/**
* Comment
*/
.another-selector { }除了縮進(jìn),我們還可以通過(guò)在規(guī)則集之間自由而明智地使用空格來(lái)提供大量信息。我們用:
密切相關(guān)的規(guī)則集之間的一 (1) 條空行。 松散相關(guān)的規(guī)則集之間的兩 (2) 條空行。 全新部分之間的五 (5) 行空行。
// good case
/*------------------------------------*\
#FOO
*------------------------------------*/
.foo { }
.foo__bar { }
.foo--baz { }
// bad case
.foo { }
.foo__bar { }
.foo--baz { }同理,在html結(jié)構(gòu)中,也可以使用同樣的規(guī)則。
除了以上這些,還有眾多的規(guī)范和優(yōu)化可以繼續(xù)探索,如選擇器性能,CSS嵌套,有興趣的讀者可以繼續(xù)探索
你會(huì)認(rèn)為 CSS規(guī)范是一個(gè)有點(diǎn)宏大和不必要的概念:為什么這么簡(jiǎn)單、這么直接的東西需要像架構(gòu)一樣被設(shè)計(jì)成非常復(fù)雜的東西?!
正是因?yàn)镃SS 的簡(jiǎn)單性、松散性和不守規(guī)矩的性質(zhì)意味著在任何合理規(guī)模上管理(閱讀、馴服)它的最佳方式是通過(guò)嚴(yán)格和特定的架構(gòu)。堅(jiān)實(shí)的架構(gòu)可以幫助我們控制我們的特殊性,強(qiáng)制執(zhí)行命名約定,管理我們的源代碼順序,創(chuàng)建一個(gè)健全的開發(fā)環(huán)境,并且通常使我們的 CSS 項(xiàng)目管理更加一致和舒適。
總的來(lái)說(shuō),可以依照一下幾個(gè)規(guī)則訂立團(tuán)隊(duì)/個(gè)人代碼規(guī)范,保證代碼的一致性
建議的幾個(gè)原則
單一職責(zé)原則: 每個(gè) CSS 實(shí)現(xiàn)都必須有一個(gè)單一的責(zé)任。
Correct:
.button {
font-family: Arial, sans-serif;
border: 1px solid black;
background: #fff;
}
.header__button {
margin: 30px;
position: relative;
}
Incorrect:
.header__button {
font-family: Arial, sans-serif;
position: relative;
border: 1px solid black;
margin: 30px;
}開閉原則: 元素應(yīng)該通過(guò)修飾符擴(kuò)展,而不是直接在原有基礎(chǔ)上修改。
Original:
<button class="button">...</button>
.button {
font-family: Arial, sans-serif;
text-align: center;
font-size: 11px;
line-height: 20px;
}
Extend
<button class="button button_size_s">...</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原則:將有意義的重復(fù)規(guī)范化和抽象化
巧用mixin和extend
@mixin my-web-font() {
font-family: "My Web Font", sans-serif;
font-weight: bold;
}
.btn {
display: inline-block;
padding: 1em 2em;
@include my-web-font();
}
.foo {
color: red;
}
.bar {
@extend .foo;
}組合優(yōu)于繼承和關(guān)注點(diǎn)分離
// 將寫js的方式同樣適用在css上
<div class="layout">
<div class="layout__item two-thirds">
<section class="content">
...
</section>
</div>
<div class="layout__item one-third">
<section class="sub-content">
...
</section>
</div>
</div>參考文獻(xiàn)
BEM簡(jiǎn)介[3]
OOCSS介紹[4]
探索 SMACSS:可擴(kuò)展的模塊化 CSS 框架[5]
編寫高效的 CSS 選擇器[6]
CSS的單一原則[7]
思考CSS架構(gòu)[8]
參考資料
BEMnaming工具: https://github.com/bem/bem-sdk#naming
[2]TailwindCSS: https://www.tailwindcss.cn/
[3]BEM簡(jiǎn)介: https://en.bem.info/methodology/quick-start/
[4]OOCSS介紹: http://oocss.org/
[5]探索 SMACSS:可擴(kuò)展的模塊化 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架構(gòu): https://zhuanlan.zhihu.com/p/32952130
?? 謝謝支持
以上便是本次分享的全部?jī)?nèi)容,希望對(duì)你有所幫助^_^
喜歡的話別忘了 分享、點(diǎn)贊、收藏 三連哦~。
歡迎關(guān)注公眾號(hào) 前端Sharing 收貨大廠一手好文章~
