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 範例框架 NEC,H-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 不是編程言語,所以不能聲明變量、函數,不能做推斷、輪迴和盤算,也不能嵌套,所以這就使得寫款式是一個效力底下且又死板的活兒。
為了處置懲罰這個題目,社區在探究中重要衍生出了兩種拓展言語 less 與 sass,它們兼容 css,而且拓展了編程的功用,重假如帶來了以下的特徵:
- 能夠聲明變量、函數,能夠舉行一些簡樸的盤算、推斷、輪迴;
- 能夠嵌套選擇器,如許節省了謄寫的內容,也更具瀏覽性;
.page1-section1 {
...
.el-1 {
...
.el-1-1 {
...
}
}
.el-2 {
...
}
}
-
@import
防止反覆導入題目,因而能夠放心大膽的導入其他文件。
從模塊化的角度來說,less 與 sass 只是擴大了 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 謄寫需求重假如:
- 應當用
.class
,而非#id
[attr]
(由於只要.class
才導出為對象的屬性); - 引薦用
.className
謄寫,而非.class-name
(前者能夠經由過程styles.className
接見,後者須要經由過程styles['class-name']
才接見)。
更多功用能夠檢察 css-modules。
固然這個功用須要構建東西的支撐,假如你是運用 webpack 構建工程的話,能夠運用 css-loader,並設置 options.modules
為 true
, 便可運用模塊化的功用了。
3. 模塊化(內置 js,綁定組件)
跟着前端組件化的生長,組件化框架的更新,如 react、vue,逐步的生長為把全部組件的資本舉行封裝,並只對外暴露一個對象,而挪用者無需體貼組件的內部完成和資本,直接挪用這個對象就夠了。
比方(以 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-ui、styled-jsx、jss、vue 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
版權聲明:自在轉載-非商用-非衍生-堅持簽名(創意同享3.0許可證)