前端進階(1) - CSS 模塊化

CSS 模塊化

CSS(Cascading Style Sheets),從降生之初就決議了它沒法編程,甚至連解釋性言語都算不上,只能作為一種簡樸的層疊款式表,對 HTML 元素舉行格式化。

但跟着前端的生長,前端項目已變得愈來愈龐大和龐雜,社區也一直在探究如何故一種有用的體式格局去治理前端的代碼(js/css/html)和資本(images, fonts, ...)。

在這個過程當中,社區探究出了 js 的模塊化(amd, commonjs, es6),如今用 js 開闢大工程已游刃有餘,而 css 的模塊化卻還沒有迥殊的深入人心。

1. 分組式模塊化

這是最早對 css 模塊化的完成,也是最重要的一種體式格局,包含如今許多組件和開闢者都是用這類體式格局開闢的。

分組式模塊化就是用定名的體式格局,以差別的前綴代表差別的寄義,完成款式分組,文件分塊,到達模塊化的目標。

比方:

# 目次構造
|-- one/page/css/ 某個頁面的 css 目次
    |-- common.css 通用的 css
    |-- page1/ 單頁面1
        |-- section1.css 地區1 css
        |-- section2.css 地區2 css
    |-- page2/ 單頁面2
    |-- ...
    
# common.css 文件
.c-el-1 {
    ...
}
.c-el-2 {
    ...
}    
...    
    
# page1/section1.css 文件
.page1-section1 {
    ...
}
.page1-section1 .el-1 {
    ...
}    
.page1-section1 .el-2 {
    ...
}    
...

# page1/section2.css 文件
.page1-section2 {
    ...
}
.page1-section2 .el-1 {
    ...
}    
.page1-section2 .el-2 {
    ...
}    
...

這類體式格局並非真正意義上的模塊化,由於沒法防止全局爭執的題目,但原生 css 並不具有編程的才,所以這個題目是沒法防止的。只管分組式不算真正意義上的模塊化,然則這類體式格局沒有離開 css 原生的機制,所以尤其是第三方組件在導出 css 文件時,許多都運用的是這類體式格局。

比方,ant-design 導出的 css 中運用 ant- 前綴標識,mui 導出的 css 中運用 mui- 前綴標識等等。

1.1 最好實踐

css 定名分組實踐的時候很長,從 css 降生之初就有了,所以社區已生長很成熟了,比方網易的 css 範例框架 NECH-ui

補充:
  • 一個 css 文件不宜過大,能夠運用 @import 舉行文件分塊;
  • 款式襯着只管不要運用 #id [attr],應只管運用 .class
  • 運用 js 庫操縱 dom 時,只管不要用 .class,應只管用 #id data-set,如 $('#main'), $('[data-tab="1"]')
<ul>
    <li data-tab="1">tab1</li>
    <li data-tab="2">tab2</li>
</ul>
<div data-tab-container="1"></div>
<div data-tab-container="2"></div>

1.2 css 言語擴大

由於 css 不是編程言語,所以不能聲明變量、函數,不能做推斷、輪迴和盤算,也不能嵌套,所以這就使得寫款式是一個效力底下且又死板的活兒。

為了處置懲罰這個題目,社區在探究中重要衍生出了兩種拓展言語 lesssass,它們兼容 css,而且拓展了編程的功用,重假如帶來了以下的特徵:

  • 能夠聲明變量、函數,能夠舉行一些簡樸的盤算、推斷、輪迴;
  • 能夠嵌套選擇器,如許節省了謄寫的內容,也更具瀏覽性;
.page1-section1 {
    ...
    
    .el-1 {
        ...
        
        .el-1-1 {
            ...
        }
    }
        
    .el-2 {
        ...
    }   
} 
  • @import 防止反覆導入題目,因而能夠放心大膽的導入其他文件。

從模塊化的角度來說,lesssass 只是擴大了 css 的功用,但並沒有在言語的層面做模塊化,由於全局定名爭執的題目依舊還在。

2. 模塊化(導出為 js 對象)

想要讓 css 具有真正意義上的模塊化功用,臨時還不能從言語的層面來斟酌,所以只能從東西的角度來完成。

現在比較好的體式格局是運用 js 來加載 css 文件,並將 css 的內容導出為一個對象,運用 js 來襯着全部 dom 樹和婚配響應的款式到對應的元素上,在這個過程當中,我們便有機會對 css 做分外的處置懲罰,來到達模塊化的目標。

比方:

源文件

# style.css 文件
.className {
  color: green;
}

# js 文件
import styles from "./style.css";

element.innerHTML = '<div class="' + styles.className + '">Hello!</div>';

現實結果

# style.css 文件
._23_aKvs-b8bW2Vg3fwHozO {
  color: green;
}

# DOM
<div class="_23_aKvs-b8bW2Vg3fwHozO">Hello!</div>

在這個轉換過程當中,依據文件的位置、內容天生一個全局唯一的 base64 字符串,替代本來的稱號,防止了全局定名爭執的題目,如許便到達了模塊化的目標。所以,開闢的過程當中便無全局款式爭執的題目。

# common.css 文件
.container {
    ...
}
.el1 {
    ...
}
.el2 {
    ...
}    
...    
    
# page1/section1.css 文件
.container {
    ...
}
.title {
    ...
}    
.content {
    ...
}    
...

# page2/section1.css 文件
.container {
    ...
}
.title {
    ...
}    
.content {
    ...
}
...

對 css 模塊化的定義拜見 css-modules,个中對 css 謄寫需求重假如:

  1. 應當用 .class,而非#id [attr](由於只要 .class 才導出為對象的屬性);
  2. 引薦用 .className 謄寫,而非 .class-name(前者能夠經由過程 styles.className 接見,後者須要經由過程 styles['class-name'] 才接見)。

更多功用能夠檢察 css-modules

固然這個功用須要構建東西的支撐,假如你是運用 webpack 構建工程的話,能夠運用 css-loader,並設置 options.modulestrue, 便可運用模塊化的功用了。

3. 模塊化(內置 js,綁定組件)

跟着前端組件化的生長,組件化框架的更新,如 reactvue,逐步的生長為把全部組件的資本舉行封裝,並只對外暴露一個對象,而挪用者無需體貼組件的內部完成和資本,直接挪用這個對象就夠了。

比方(以 react 為例),一個 Welcome 組件,包含一個 js 文件、一個 css 文件、圖片:

# Welcome 組件
|-- welcome.js
|-- welcome.css
|-- images/

welcome.js 中便可以下加載(運用“導出為 js 對象”的 css 模塊化):

import styles from './welcome.css';
import image1 from './images/1.jpg';

實在,另有別的一種思緒,就是將 css 內置 js 中,成為 js 的一部分。

如許做的目標,一是 css 的模塊化,二是直接綁定到組件上。

比方,material-uistyled-jsxjssvue style scoped 就是運用的這類體式格局。

這類體式格局的完成有許多種,這裏重要引見一下 styled-jsx

3.1 styled-jsx

styled-jsx 的道理是依據當前文件的位置、內容天生一個全局唯一的標識,然後把這個標識追加到組件每個元素上,每個款式選擇器上,到達模塊化的目標。

能夠參考官方文檔,檢察細緻的用法,我在這裏給個例子:

3.1.1 裝置東西(babel 轉碼所需)

npm install --save styled-jsx

3.1.2 設置 babel plugins(如 .babelrc

{
  "plugins": [
    "styled-jsx/babel"
  ]
}

3.1.3 增加源文件代碼

hello.js

export default () => (
    <div className={'container'}>
        <p className={'hello'}>Hello! Hello!</p>
        <div id={'hi'}>Hi!</div>
        <style jsx>{`
          .container {
            color: blue;
          }
          p:first-child {
            color: red;
          }
          .hello {
            color: yellow;
          }
          #hi {
            color: green;
          }
        `}</style>
    </div>
)

3.1.4 轉碼

babel path/to/hello.js -d target/dir

轉碼后的文件

import _JSXStyle from 'styled-jsx/style';

export default () => (
    <div className={'jsx-234963469' + ' ' + 'container'}>
        <p className={'jsx-234963469' + ' ' + 'hello'}>Hello! Hello!</p>
        <div id={'hi'} className={"jsx-234963469"}>Hi!</div>
        <_JSXStyle styleId={"234963469"} css={".container.jsx-234963469{color:blue;}p.jsx-234963469:first-child{color:red;}.hello.jsx-234963469{color:yellow;}#hi.jsx-234963469{color:green;}"} />
    </div>
);

3.1.5 運轉

現實襯着結果

<style type="text/css" data-styled-jsx="">
.container.jsx-234963469{
  color:blue;
}
p.jsx-234963469:first-child{
  color:red;
}
.hello.jsx-234963469{
  color:yellow;
}
#hi.jsx-234963469{
  color:green;
}
</style>



<div class="jsx-234963469 container">
  <p class="jsx-234963469 hello">Hello! Hello!</p>
  <div id="hi" class="jsx-234963469">Hi!</div>
</div>

4. 後續

更多博客,檢察 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版權聲明:自在轉載-非商用-非衍生-堅持簽名(創意同享3.0許可證

    原文作者:senntyou
    原文地址: https://segmentfault.com/a/1190000015403363
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞