【CSS】1203- 分享 20 個防御式 CSS 開發(fā)經(jīng)驗
本文原作者為阿里巴巴克軍,轉(zhuǎn)載請注明原作者
本文已獲得原作者授權(quán)
0.前言
當(dāng)前CSS開發(fā)的現(xiàn)狀不容樂觀,掃了一圈,發(fā)現(xiàn)各種問題。前端開發(fā)更多關(guān)注點還是在JavaScript上,技術(shù)性相對更強。
但從前端技術(shù)的根本價值出發(fā),實現(xiàn)高可用性的產(chǎn)品用戶界面,是用戶體驗的第一道關(guān),這就跟CSS開發(fā)的專業(yè)性緊密相關(guān)了。輕易改變一下窗囗大小,放大一下字體,頁面就被拉垮,這樣的產(chǎn)品品質(zhì)高嗎?
本文將涉及一些響應(yīng)式開發(fā)內(nèi)容,TOB產(chǎn)品同樣需要響應(yīng)式開發(fā)。以云安全中心為例,用戶屏幕分辯率占比中1920x1080和2560x1440加起來達到52%。平時開發(fā)的15寸的本物理分辯率是1440x900只占9%。說明我們的企業(yè)用戶大多用PC或用外接顯示器。請注意:屏幕物理分辨率≠瀏覽器窗囗大小(如下圖)。平時用外接顯示器會有各種用法,橫著用,堅著用,分屏顯示窗囗等等(如封面)。因此,不能簡單的依據(jù)屏幕分辨率進行設(shè)計和開發(fā)。我認為體現(xiàn)CSS開發(fā)專業(yè)性看的就是防御式CSS開發(fā)。


(數(shù)據(jù)來自css-tricks)
“防御性編程(Defensive programming)是防御式設(shè)計的一種具體體現(xiàn),它是為了保證,對程序的不可預(yù)見的使用,不會造成程序功能上的損壞。它可以被看作是為了減少或消除墨菲定律效力的想法。”(引自wiki)?
現(xiàn)在前端開發(fā)還是契約式的,也就是還原設(shè)計稿,這是遠遠不夠的。設(shè)計稿往往只體現(xiàn)出UI的理想態(tài)。防御式CSS開發(fā)一部分是為了實現(xiàn)響應(yīng)式設(shè)計,同時還包括適配動態(tài)內(nèi)容,在各種情景下保持UI的完美性和健壯性。
1. 采用扁平化的HTML結(jié)構(gòu),用CSS控制布局
1-1. 避免用“布局組件”
這樣會把模塊限死在HTML結(jié)構(gòu)中,不利于靈活的適配。

HTML的結(jié)構(gòu)設(shè)計是基本前提,避免“表格思維”,避免多余的行 / 列元素(過度包裝元素)。
如,這樣設(shè)計:
<div?class="overview-content">
??<div?class="sky-card?overview-card">...div>
??<div?class="sky-card?overview-card?security-defense-card">...div>
??<div?class="sky-card?overview-card">...div>
??<div?class="sky-card?overview-card">...div>
div>
1-2. 不要用JavaScript控制布局
線上問題:

用CSS實現(xiàn)同樣的效果:

2. 避免用float / position: absolute / display: table等方式布局
所有布局和對齊需求,無一例外用 Flexbox / Grids 實現(xiàn)。
3. 避免定高/定寬,用min-width/min-height替代
固定寬/高最容易出現(xiàn)的問題是內(nèi)容溢出。沒必要通過定寬高對齊,可以利用Flexbox的位伸/收縮特性。可以定義最小寬/高。
4. 避免侵入性(損人利自己)的寫法
避免影響全局樣式,如: * { ... }、:root {...}、div { ....}等。避免影響通用組件樣式,如: .next-card {...},如果要定制單加一個class名。不要直接修改全局CSS變量,把自己的CSS變量定義在模塊的范圍內(nèi)。 不要寫z-index:999。一般1~9,防止被遮擋10~99,絕對夠用了。 不要在標(biāo)簽上定義style屬性。不要在JS代碼中做樣式微調(diào),這樣今后無法統(tǒng)一升級CSS樣式。 只有完全不可修改的樣式才能用!important,利用選擇器優(yōu)先級調(diào)整樣式。
5. 避免CSS代碼的誤改 / 漏改
將選擇器拆開寫,如 .card-a, .card-b { ... },寫時方便,改時難,修改時容易影響其它元素,不如分開寫(除非像css reset這種特別確定的情況)。將樣式集中在一起,容易改錯。保持CSS代碼和文件在相應(yīng)的層級上,同一模塊的放一起。避免混入通用樣式中,為了避免改錯,允許適當(dāng)冗余。 用@media時,會集中覆寫一批元素的樣式,更新樣式時非常容易遺漏。所以必須拆開寫,和對應(yīng)模塊的樣式放在一起。不要集中放在文件底部,或是集中放在某一個文件里。 及時清除“死代碼”。 定義樣式要寫全,微調(diào)樣式要寫具體,如:
.mod?{
??margin:?0;
}
/*?其它地方需要微調(diào)時?*/
.biz-card?.mod?{
??margin-bottom:?16px;
}
6. 避免CSS樣式?jīng)_突
限定作用范圍。如, .my-module .xxx { ... }。業(yè)務(wù)代碼中的樣式要加前綴,或借鑒BEM命名方式。如: .overview-card-title { ... }。用CSS Module也可以。注意選擇器的精確性。級層過長過于復(fù)雜的CSS選擇器會影響性能,但要注意:有時需要精確選擇某些元素,如僅選擇一級子元素, .overview-card-content > .item { ... }。
7. 防止內(nèi)容不對齊
受字體、行高等因素影響(如圖),用Flexbox實現(xiàn)對齊最可靠:
height / line-height 不可靠。 display:inline-block / vertical-align:middle 不可靠。


用Flexbox實現(xiàn)對齊


8. 防止內(nèi)容溢出
包括文字/圖表等內(nèi)容在寬度變化時或是英文版下容易出現(xiàn)溢出(如圖)。

圖表要支持自動 resize。 圖片要限制大小范圍,如:max-width、max-height min(100px, 100%)、max(100px, 100%)
注意:min() / max() 兼容性:chrome 79+ / safari 11 / firefox 75

不能固定寬/高。(見規(guī)則3) 不要在容器元素定義overflow:hidden
9. 防止內(nèi)容過度擁擠
為了防止內(nèi)容過長時緊帖到后面的內(nèi)容,水平排列元素之間要設(shè)置間距,一般是8px。

如果用flexbox要加上gap。考慮到gap的兼容性:chrome 84,穩(wěn)定起見用margin。

.item?{
??margin:?0?8px?0?0;
}
.item:last-child?{
??margin-right:?0;
}
10. 防止內(nèi)容被遮擋
定義負值時(負margin / top / left),小心內(nèi)容被遮擋,避免這么定義。定義margin統(tǒng)一朝一個方向,向下和向右定義,再重置一下:last-child。position: relative 平時很常用,發(fā)生遮擋時會造成鏈接無法點擊(如圖)。

11. 防止可點擊區(qū)域過小
小于32x32像素的可點擊元素,通過下面的方式擴大可點擊區(qū)域:

.btn-text?{
??position:?relative;
}
/*?比?padding?副作用小?*/
.btn-text::before?{
??content:?'';
??position:?absolute;
??top:?-6px;
??left:?-8px;
??right:?-8px;
??bottom:?-6px;
}
12. 防止內(nèi)容顯示不全 / 被截斷
在定義 overflow:hidden時,就要考慮內(nèi)容是否有被截斷的可能。一般不要加在容器元素上。防止長文字被生生截斷(如圖),加省略號。

overflow:?hidden;?
text-overflow:?ellipsis;?
white-space:?nowrap;
不想折行,溢出加省略號,這都沒問題。但忽略了對inline元素?zé)o效,所以要再加一條display: block
13. 防止該折行不折行 / 不該折行的折行
首先必須理解UI,有3種情況:哪些需要折行,哪些不能折行,哪些不能從中間斷行。
大部分情況需要折行,不能為了保持UI美觀而損失內(nèi)容的完整性。
一般用overflow-wrap,盡量不要用word-wrap(不符CSS標(biāo)準(zhǔn)):overflow-wrap: break-word配合overflow-wrap,可再加上hyphens: auto(目前兼容性不夠)
限定多行:-webkit-line-clamp: 3
不能折行,如標(biāo)題 / 列頭 / 按鈕等。開發(fā)中要理解內(nèi)容,哪些元素不應(yīng)該折行。

overflow:?hidden;?
text-overflow:?ellipsis;?
white-space:?nowrap;
表格列數(shù)過多(>5列)時,會要求鎖列,此時,th 定義 white-space: nowrap 強制不折行
不能從中間斷行的情況(如圖)

14. 防止?jié)L動鏈問題
浮層的場景下需要避免滾動鏈問題:子元素可滾動,如果父元素也有滾動區(qū)域,在子元素上滾動時,觸頂/觸底后,會影響父元素滾動。關(guān)掉浮層后,用戶會發(fā)現(xiàn)頁面滾到了其它位置。
| 優(yōu)化前 | 優(yōu)化后 |
|---|---|
![]() |
|
overscroll-behavior:?contain;
overflow-y:?auto;
overflow-x:?hidden;
注意:避免出現(xiàn)同時出現(xiàn)水平/垂直滾動條 兼容性:chrome 63+ / firefox 59+ / safari和edge不支持
15. 防止圖片變形
圖片被置于特定比例的容器中時,固定寬/高和約束最大寬/高,都可能會導(dǎo)致圖片變形。

.head?img?{
??width:?100%;
??height:?100%;
}

.head?img?{
??width:?100%;
??height:?100%;
??object-fit:?cover;
}
在Flexbox容器內(nèi),圖片高度會被自動拉伸。因為不定義align-items,默認是stretch。


16. 防止圖片加載失敗
需要考慮圖片加載慢或加載失敗的情景。在圖片的容器上加邊或加底色。


.head?{
??background:?#eee;
??box-shadow:?inset?0?0?0?1px?#aaa;
}
17. 防止CSS變量未引入
在標(biāo)準(zhǔn)化開發(fā)中,我們提倡使用全局的CSS變量。業(yè)務(wù)代碼中,利用CSS變量也可以方便的進行全局的控制。在使用CSS變量時要加上缺省值。
font-size:?var(--tab-item-text-size-s,?12px);
18. 防止CSS兼容性問題
不要加瀏覽器廠商前綴,讓CSS預(yù)編譯自動處理,像-webkit-、-moz-。 不要用僅特定瀏覽器廠商支持的屬性。
19. Flexbox常見防御性寫法
Flexbox的默認表現(xiàn)比較多,不能簡單的定義display:flex,或是flex:1。
Flexbox容器元素通常要做如下定義:要支持多行(默認是單行),交叉軸上垂直居中(默認是stretch),主軸上采用space-between,將自由空間分配到相鄰元素之間。
display:?flex;
flex-wrap:?wrap;
justify-content:?space-between;
align-items:?center;
Flexbox的盒子元素,不要固定寬/高,更不要指定百分比的值。Flexbox會自動拉伸/收縮盒子元素,能夠精確到浮點數(shù),指定具體值會破壞原本的“彈性”。
Flexbox的盒子元素要定義間距。
案例分析:

優(yōu)化后:

參考代碼,總結(jié)用法:
.new-overview-v2-center-box?.left?.top?{
??/*?position:?relative;?*/
??display:?flex;
??flex-wrap:?wrap;
??align-items:?center;
??justify-content:?space-between;
??/*?height:?100%;?*/
}
.new-overview-v2-center-box?.left?.top?.item?{
??/*?width:?25%;?*/
??flex:?1;
??min-width:?max-content;
??margin:?0?8px?8px?0;
}
20. Grid常見防御性寫法
不固定網(wǎng)格的寬度,用minmax(最小值,1fr)。 定義間距grid-gap: 8px。 不固定列數(shù), 利用auto-fit / auto-fill自動適配(如圖)。

.wrapper?{
??display:?grid;
??grid-template-columns:?repeat(auto-fit,?minmax(100px,?1fr));
??grid-gap:?8px;
}
.item?{
??border:?2px?solid?#aaa;
??box-sizing:?border-box;
??min-height:?128px;
}

回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~
點擊“閱讀原文”查看 130+ 篇原創(chuàng)文章


