CSS也有作用域?—"css-modules"說它為什么要這么做!

把問題的結論放在開頭,關于我的故事,感興趣的同學或者覺得會對自己有幫助的同學慢慢欣賞吧,這樣可以節(jié)省另外部分同學的時間。

1. css-modules是什么?

css-modules是將css賦予作用域概念的一種樣式模塊化解決方案。通過給樣式名加hash字符串后綴的方式,實現(xiàn)特定作用域語境中的樣式編譯后的樣式在全局唯一。

2. css-modules解決了什么問題?

當項目經(jīng)由多位技術背景和水平參差不齊的開發(fā)者接手過后,項目的樣式已經(jīng)不能乖乖的被后面的同學搞了,不斷的重構重構重構...... 嗯,是時候要有人拿小皮鞭來規(guī)范開發(fā)秩序了。css-modules的出現(xiàn)解決了全局樣式污染,龐大的頁面dom節(jié)點取名字的問題。

3. css-modules的科學實踐

組件容器內樣式作用域弱約束,頁面區(qū)域間作用域強隔離。
例如頁面結構為 header、main、aside、footer 這四個區(qū)域。header和aside共同使用了Navbar組件,Navbar的組件是復用了,樣式一致,但是在header和aside中要有兩種視覺效果。這時候把header和aside可以分別看做Navbar的兩個實例容器,header和aside是用css-module管理的local作用域,在他們的local作用域中聲明一個global作用域,通過.header :global .nav-bar{...}的方式覆寫組件樣式,實現(xiàn)同一組件在同一頁面不同區(qū)域的樣式自定義。

4. 對css-modules出現(xiàn)背景所做的反思

css對于專業(yè)前端來說是很熟悉的,通過命名前綴,結構化命名來描述頁面結構。但這些都是人為經(jīng)驗去做的代碼管理,在團隊開發(fā)資源緊張的情況下,很多不熟悉css的后端同學也需要盡快完成前端的任務,導致大量的樣式?jīng)_突和冗余。于是乎,標準化組件給大家更少的選擇,更少的關注css...

當然以上是出于許許多多后端、客戶端發(fā)者對web前端的理解基礎上給出的解決方案。語言之間的思想是會互相影響的,就那這個模塊化的方案結合es6來說,我感覺就很像python了。

下面是關于我對css-modules使用經(jīng)歷的小故事:

不久前換了工作,開始使用React來開發(fā)web。早先就聽聞過React的大名,之前的工作是團隊中就我一只前端,考慮到效率問題,工作中一直在用Angular 1.X 來霸道的進行開發(fā),功能大而全,即使是一個人來同時做前后端,也可以很快的開發(fā)出可維護性的系統(tǒng)。那么現(xiàn)在開始用了React,初次的開發(fā)體驗我選擇了"ant-design"。

根據(jù)ant-design的快速上手教程,我搭建起來一個初始化的項目結構。但是當我需要按照設計圖去還原視覺效果的時候,我懵逼了。jsx的語法,加上模塊化的React組件,在開發(fā)界面功能的時候很方便,有種類似客戶端的控件引入方式。不過在我需要按照視覺設計圖去覆寫組件樣式的時候,我發(fā)現(xiàn)竟然沒有對應的css樣式!

經(jīng)過調試發(fā)現(xiàn),項目結構中引入了css-modules,在瀏覽器的開發(fā)者工具中會看到,頁面中節(jié)點的className被加上了hash字符串,這也就意味著css有了作用域的概念。后來查css-modules的文檔,如果是全局作用域的樣式需要在樣式前面包一層 :global,代碼如下:

:global {  
  html, body, #root {    
    height: 100%;  
  }    
  body { background: #fafafa; }
}

在沒有:global包裹的樣式,編譯后的結果是一下這種:
MainLayout.less

.main{...}

index.html

<div id="root">
  <div class="main"></div>
</div>

編譯后的index.html

<div id="root">
  <div class="main___1gjAI"></div>
</div>

MainLayout.jsx

import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { DatePicker, message } from 'antd';
import styles from './MainLayout.less';

ReactDOM.render(
  <div className={styles.main}>
    <DatePicker onChange={value => this.handleChange(value)} />
  </div>, 
  document.getElementById('root')
);

這里想要讓css樣式生效,必須在對應的節(jié)點使用 "module.style"(模
塊.樣式屬性)的方式綁定樣式。這里就沒辦法通過外部容器的選擇器來定位組件節(jié)點了。因為組件是在自定義渲染部分引入使用,組件節(jié)點是自動渲染的,如果組件沒有開放子節(jié)點的className字段,是無法修改組件樣式的。

不過,如果在組件沒有使用css-modules的情況下,我們可以通過在頁面節(jié)點-組件容器的css作用域來創(chuàng)建一個組件容器的全局作用域(該作用域存在于頁面節(jié)點的local作用域內,頁面其他區(qū)域的css作用域是隔離的),代碼如下:

.main{
  :global{
    .ant-calendar-picker{
      /*這里可以覆寫 DatePicker組件的樣式了*/
    }  
  }
}

在經(jīng)過一陣驚訝和反思后,結合我之前的工作經(jīng)歷不禁開始贊嘆css-modules的牛逼。
說他牛逼并不是因為他在技術上的實現(xiàn)有多么復雜,而是他可以讓項目的不確定性大大降低,代碼的可維護性得以提升。

以前也跟朋友吐槽過,相信前端同學有的也有過這樣的經(jīng)歷,入職后發(fā)現(xiàn)自己是唯一的前端,而且接手的項目之前是后臺的同學開發(fā)的。素質高點的js不會亂引的太嚴重,然而大多數(shù)后臺的同學是不熟悉css的,樣式不僅冗余,而且很多因為優(yōu)先級而相互覆蓋的問題。

換個角度想想就發(fā)現(xiàn)了css-modules的價值,就是tmd讓不熟css的同學乖乖的不要給人家挖坑。如果說真的需要接手這類的項目,即便是損失了css的靈活性,我也是會開心的笑出眼淚吧(畢竟比反復重構人家寫的頁面要好很多)。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 最近學習到CSS的繼承屬性,正好看到這篇文章,便將它翻譯出來。作者的思想,在平時的項目中或多或少都有用過,但是從來...
    hershin閱讀 985評論 0 1
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,082評論 25 709
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 15,397評論 4 61
  • 有一段時間很極端,覺得不應該隨便給人貼標簽,尤其愛說,不要給孩子隨便貼標簽。 隨著認知的變化,更加理性。 家長不給...
    信時光閱讀 183評論 0 0
  • 夜色溫柔,是在一個人內心溫柔,感動了自己,用無限柔情和寬容去看待周圍的一切的時候。 它也許是晚歸時,公交車窗外滑過...
    會游走的魚閱讀 884評論 0 0

友情鏈接更多精彩內容