React中的css到底該怎麼寫?這一直是個飽受爭論的話題。本文將結合React CSS的發展史,分別敘述CSS in js與CSS module兩種風格中的最佳實踐。css
首先,facebook提出CSS in js
的概念,這很奇怪。 咱們多年來所學的知識都在宣揚關注點分離的重要性,不該該將標記和css混在一塊兒。可是React行內樣式的提出,試圖改變關注點分離這一律念。使其從技術分離向組件分離轉變。html
經過CSS in js
,有如下兩個優勢:webpack
好比這樣(先忽略直接將style對象傳入帶來的性能問題)web
render(){
return (
<div style={{fontWeight: this.props.weight ? 'bold' : 'normal'}}>hello world</div>
)
}
複製代碼
行內樣式也有缺點:設計模式
!important
來實現了事實證實,雖然行內樣式解決了目標問題,卻引起了更多的問題。bash
若是你認爲行內樣式的方案不適合本身的團隊,但仍然但願儘可能緊密結合樣式與組件,那麼webpack
的css-loader
就幫了你大忙! 關於webpack
和詳細配置,本文再也不贅述。咱們看一下本文主要用到的loader
和plugin
:antd
const HTMLWebpackPlugin = require('html-webpack-plugin')
module.exports = {
...
module: {
rules: [
...
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
},
plugins: [
new HTMLWebpackPlugin()
]
}
複製代碼
如上配置完之後,在終端啓動項目後,就能夠在網頁中訪問了。接下來咱們開始編寫具體代碼。架構
首先定義一個普通的css文件函數
.button {
background-color: blue;
color: #fff;
padding: 10px 20px;
}
複製代碼
而後在js文件中引入工具
import styles from './index.css'
複製代碼
import語句會導入一個樣式對象,其全部屬性就是index.css中定義的類,這時候運行一下console,開發者工具會輸出一個形如這樣的對象。這個key是根據文件散列值和其餘一些參數生成的。
{
button: "_2wpxM3yizfwbWee6k0U1D4"
}
複製代碼
接着,咱們能夠用這個對象去設置按鈕的className屬性
const Button = () => (
<button className={styles.button}>Click it</button>
)
複製代碼
這樣,按鈕的樣式就設置完成了。 咱們打開開發者工具能夠看到,button的類名就是上面的_2wpxM3yizfwbWee6k0U1D4
。若是查看頁面頭部,咱們還會發現相同的類名已經注入到頁面中了。
css-loader
容許你在js模塊中導入css文件,而且啓用modules
標記時,全部類名都只做用於導入它們的模塊。最後,style-loader
接收css-loader
轉換的結果,並將樣式注入到頁面頭部。
這種用法很是強大,由於咱們擁有了css的完整能力及表現性,又結合了局部做用域類名與顯示依賴的優勢。咱們還能夠像這樣配置localIdentName
參數,解決調試時信息不清晰的問題。
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
}
}
]
}
]
}
複製代碼
生產環境不須要這樣的類名,更注重性能,所以咱們想要更簡短的類名和散列值。 咱們能夠在生產環境下使用MiniCssExtractPlugin
將樣式提取到單獨的css文件,並將其放入CDN
,從而得到更好的性能。
css-loader還支持一些關鍵詞。
第一個就是global
關鍵詞。給任何類添加:global
前綴,意味着請求CSS模塊不要爲當前選擇器加上局部做用域。
例如:
:global .button {
...
}
複製代碼
這樣,你能夠應用不須要局部做用域的樣式。好比第三方組件。
第二個就是composes
,有了它,就能夠從同個文件或外部依賴中引用類名,將其它類的全部樣式應用於一個元素。
例如:
.text-red{
color: red;
}
.button {
composes: text-red;
background-color: blue;
color: #fff;
padding: 10px 20px;
}
複製代碼
最終,button類的全部規則以及composes聲明的全部規則都能做用於元素。
這個特性很是強大,並且原理很巧妙。你可能覺得它和SASS
的@extend
方法同樣,只是將組合類複製到引用它們的位置,其實不是這樣。簡單來說,全部組合類名都是逐個應用到DOM中的組件上。
以咱們的示例來講,代碼以下:
<button class="_2wpxM3yizfwbWee6k0U1D4 Sf8w9cFdQXdRV_i9dgcOq">Click it</button>
複製代碼
注入頁面的css以下所示:
.Sf8w9cFdQXdRV_i9dgcOq {
color: red;
}
._2wpxM3yizfwbWee6k0U1D4 {
background-color: blue;
color: #fff;
padding: 10px 20px;
}
複製代碼
原子級CSS又稱函數式CSS,是CSS的一種使用方式,即每一個類只有一條規則。
例如,能夠用一個類來設置底部外邊距爲0:
.mb0 {
margin-bottom: 0;
}
複製代碼
而後用另外一個類設置font-weight爲bold
.fwb {
font-weight: bold;
}
複製代碼
而後將這些原子類用在元素上:
<span class="mb0 fwb">Hello World</span>
複製代碼
這種技巧存在爭議,但很高效。一方面,類是在CSS文件中定義,卻在視圖層組合,每次修改元素的樣式都要同時修改兩個地方;另外一方面,它能夠超快地搭建頁面。
其實,只要全部基本規則都定好,將這些類應用於元素或者用它們生成新的樣式都很是快,這是一大優勢。其次,使用原子級CSS能夠控制css文件的大小,由於建立新組建時能夠複用已有類的樣式,不須要編寫新樣式,這對性能頗有好處。
咱們能夠將CSS Module與原子級CSS結合起來使用。
查看如下示例:
.title {
composes: mb0 fwb;
}
<span class="title">Hello World</span>
複製代碼
這種作法很是好,由於樣式邏輯仍然保留在CSS中,同時CSS模塊利用composes將全部單個類聚合到一個類中。
上述代碼的渲染結果以下所示:
<span class="title--3JCJR mb0--21SyP fwb--1JRhZ">Hello World</span>
複製代碼
此處的title
、mb0
以及fwb
都是自動加到元素上的。而且它們都只做用於局部。這樣,咱們就用上了CSS Module的全部優點。
最後,讓咱們看一下CSS in js中的王者——styled-components。 這個庫能夠說考慮到了其餘組件樣式庫遇到的全部問題。
在安裝styled-components以後,咱們能夠這樣使用它:
import styled from 'styled-components'
const Button = styled.button` background-color: blue; color: #fff; padding: 10px 20px; `
複製代碼
能夠看到它使用了模板字符串,這意味着它能夠用js的所有能力爲元素添加樣式。 這種看似奇怪的語法會返回普通的React組件Button,它渲染了一個按鈕元素,並加上了模板中定義的樣式。先建立惟一的類名,再將它加到元素上,最後向頁面文檔頭部注入相應的樣式。至此,樣式生效了。
渲染的組件以下所示:
<button class="kYvFOg">Click it</button>
複製代碼
頁面上添加的樣式以下:
.kYvFOg {
background-color: blue;
color: #fff;
padding: 10px 20px;
}
複製代碼
這個庫的優勢以下在於支持幾乎全部的css特性。好比,它支持SASS
風格的僞類語法:
const Button = styled.button` background-color: blue; color: #fff; padding: 10px 20px; &:hover { background-color: #fff; color: blue; } `
複製代碼
它也支持媒體查詢:
const Button = styled.button` background-color: blue; color: #fff; padding: 10px 20px; &:hover { background-color: #fff; color: blue; } @media (max-width: 480px) { padding: 10px 10px; } `
複製代碼
它還能夠很方便地覆蓋樣式,並設置不一樣屬性來屢次複用該組件。當你使用了形如antd
之類的UI庫,並但願自定義一些樣式時,這個優勢會很是明顯。
CSS in or not in js ? this is a question.
我以爲沒有絕對的最佳實踐,只有在工程迭代的過程當中,不停的找尋最適合工程、最適合團隊的方案,這纔是最明智的選擇。