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

有以下幾個規(guī)則
Block元素應該以元素本身的屬性為主 Element則以元素位置和形狀為主 Modifier則修飾當前的狀態(tài)和主題 Element一定是在Block之中,而不能獨立于Block之外 Modifier則更多的表示當前組件的形狀和狀態(tài)
可以明顯發(fā)現(xiàn)
結構清晰 定位迅速 功能明確
在面對組件化的場景時,Block 代表邏輯上和功能上獨立的頁面組件。Element封裝了行為(JavaScript)、模板、樣式(CSS)和其他實現(xiàn)技術。
舉個例子
<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">ena>
????????li>
????????<li?class="lang-switcher__item">
????????????<a?class="lang-switcher__link--active"?href="url">rua>
????????li>
????ul>
header>block-name__element-name--modifier-name--modifier-value
在React當中,也采用了這樣的命名方式

BEMnaming工具[1],提供BEM命名的檢測
然而在面對大型的項目時CSS的凌亂也很難讓開發(fā)者愿意在茫茫多的代碼中尋找可復用的代碼
3. SMACSS
(What’s Smacss)[https://smacss.com/]
設計的主要規(guī)范有三點:
Categorizing CSS Rules(為css分類) Naming Rules(命名規(guī)范) Minimizing the Depth of Applicability(最小化適配深度)
為了實現(xiàn)清晰的CSS結構,將CSS分為
Base - 全局樣式,如global-reset、normalize.css Layout - 頁面布局,如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的變動增加對css的影響
.sidebar?ul?h3?{}
.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?}
<div?className="m-2?p-2?text-2xl?text-gray-500">I?am?Okdiv>而上述的架構思想,更多則是需要團隊成員的一致性認同,才能實現(xiàn)在代碼風格上的統(tǒng)一。
除了這些開發(fā)自律性上的代碼規(guī)范外,還有什么其他的方式來提升CSS質量呢?
CSS預處理器
在預處理器中,同樣提供了眾多的方法來簡化與控制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. 內建函數(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;
}??
//?對象插值
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;
????}對于維護一份高質量的CSS代碼,注釋和間隔必不可少
以下是一種比較建議的注釋和間隔方式,可以自行取用。
/*------------------------------------*\
??#A-SECTION
*------------------------------------*/
.selector?{?}
/*------------------------------------*\
??#ANOTHER-SECTION
*------------------------------------*/
/**
?*?Comment
?*/
.another-selector?{?}除了縮進,我們還可以通過在規(guī)則集之間自由而明智地使用空格來提供大量信息。我們用:
密切相關的規(guī)則集之間的一 (1) 條空行。 松散相關的規(guī)則集之間的兩 (2) 條空行。 全新部分之間的五 (5) 行空行。
//?good?case
/*------------------------------------*\
??#FOO
*------------------------------------*/
.foo?{?}
??.foo__bar?{?}
.foo--baz?{?}
//?bad?case
.foo?{?}
??.foo__bar?{?}
.foo--baz?{?}同理,在html結構中,也可以使用同樣的規(guī)則。
除了以上這些,還有眾多的規(guī)范和優(yōu)化可以繼續(xù)探索,如選擇器性能,CSS嵌套,有興趣的讀者可以繼續(xù)探索
你會認為 CSS規(guī)范是一個有點宏大和不必要的概念:為什么這么簡單、這么直接的東西需要像架構一樣被設計成非常復雜的東西?!
正是因為CSS 的簡單性、松散性和不守規(guī)矩的性質意味著在任何合理規(guī)模上管理(閱讀、馴服)它的最佳方式是通過嚴格和特定的架構。堅實的架構可以幫助我們控制我們的特殊性,強制執(zhí)行命名約定,管理我們的源代碼順序,創(chuàng)建一個健全的開發(fā)環(huán)境,并且通常使我們的 CSS 項目管理更加一致和舒適。
總的來說,可以依照一下幾個規(guī)則訂立團隊/個人代碼規(guī)范,保證代碼的一致性
建議的幾個原則
單一職責原則: 每個 CSS 實現(xiàn)都必須有一個單一的責任。
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;
????}開閉原則: 元素應該通過修飾符擴展,而不是直接在原有基礎上修改。
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原則:將有意義的重復規(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)于繼承和關注點分離
//?將寫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>參考文獻
BEM簡介[3]
OOCSS介紹[4]
探索 SMACSS:可擴展的模塊化 CSS 框架[5]
編寫高效的 CSS 選擇器[6]
CSS的單一原則[7]
思考CSS架構[8]
參考資料
BEMnaming工具:?https://github.com/bem/bem-sdk#naming
[2]?TailwindCSS:?https://www.tailwindcss.cn/
[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
?? 謝謝支持
以上便是本次分享的全部內容,希望對你有所幫助^_^
喜歡的話別忘了?分享、點贊、收藏?三連哦~。
歡迎關注公眾號?全棧前端精選?收貨大廠一手好文章~
我們來自字節(jié)跳動,是旗下大力教育前端部門,負責字節(jié)跳動教育全線產(chǎn)品前端開發(fā)工作。
我們圍繞產(chǎn)品品質提升、開發(fā)效率、創(chuàng)意與前沿技術等方向沉淀與傳播專業(yè)知識及案例,為業(yè)界貢獻經(jīng)驗價值。包括但不限于性能監(jiān)控、組件庫、多端技術、Serverless、可視化搭建、音視頻、人工智能、產(chǎn)品設計與營銷等內容。
字節(jié)跳動校/社招內推碼: 3DDR5K9
投遞鏈接: https://jobs.toutiao.com/s/dxqGR6p
