除了傳統的 CSS,你還可以使用 內聯樣式
和 CSS-in-JS
作爲 React 應用程序的樣式選項。
對於內聯樣式,你可以將 JavaScript對象傳遞給樣式屬性:
const myStyle = {
fontSize: 24,
lineHeight: '1.3em',
fontWeight: 'bold',
};
<span style={myStyle}>Hello World!</p>
然而,並非所有 CSS 特性都受支持。
另一方面,CSS-in-JS 是一種使用 JavaScript來設置組件樣式的技術。在解析此 JavaScript時,會生成 CSS(通常作爲 <style>
元素)並附加到 DOM 中。
這個功能由第三方庫實現。例如,下面是使用 Aphrodite 實現的上一個示例:
import { StyleSheet, css } from 'aphrodite';
const styles = StyleSheet.create({
myStyle: {
fontSize: 24,
lineHeight: '1.3em',
fontWeight: 'bold',
}
});
<span className={css(styles.myStyle)}>Hello World!</p>
其他第三方庫推薦:
我並不完全贊成使用 CSS-in-JS,但我不得不說,其中一些庫增加了對在某些情況下可能會有用的功能支持。
在這篇文章中,我將討論在 CSS-in-JS 中你可以用上面的庫來做的五件事,而我打賭這是你不知道的。
1.參照其他樣式組件
像 styled-components 和 emotion 庫允許您使用 標記模板文字 從樣式中創建 React 組件:
import styled from 'styled-components';
// Create a component that renders a <p> element with blue text
const BlueText = styled.p`
color: blue;
`;
<BlueText>My blue text</BlueText>
它們也允許你定位於其他樣式組件(像你使用 CSS 選擇器一樣):
const ImportantText = styled.div`
font-weight: bold;
`;
const Text = styled.div`
color: gray;
${ImportantText} {
font-style: italic;
}
`;
render(
<div>
<Text>
Text in gray
<ImportantText>Important text in gray, bold and italic</ImportantText>
</Text>
<ImportantText>Important text bold</ImportantText>
</div>
);
這在組合僞類時很有用,例如,在懸停時更改組件的顏色:
const Text = styled.div`
color: gray;
&:hover ${ImportantText} {
color: red;
}
`;
2.使用JSS(或其他庫)擴展某些庫的特性
假設你已經使用 Aphrodite 爲你的應用程序設計樣式,現在你需要支持主題。
但問題是 Aphrodite 不能輕易地支持主題。 至少不像 Emotion 那麼容易。
不過,這裏有兩個項目將 JSS
的核心與 Aphrodite
和 styled-components
相結合,aphrodite-jss 和 styled-jss。
通過這種方式,你可以保留 Aphrodite
(或 styled-components
) 的優點,並使用 JSS
的所有特性和 插件,從 規則緩存 到 規則隔離,以及主題,主題包,以下是它提供的高階組件:
-
ThemeProvider
:通過 context 向 react 樹傳遞主題對象。 -
withTheme
:允許你接收一個主題對象並作爲屬性來更新。
例如:
const blackTheme = {
color: 'black',
};
const App = () => (
<ThemeProvider theme={blackTheme}>
<MyComponent />
</ThemeProvider>
);
在 Aphrodite
和主題的案例中,作爲另一個例子,你也可以使用 react-with-styles,它有實現 Aphrodite 或 JSS 接口,這樣在定義樣式時就可以訪問主題信息了。
3.使用關鍵幀鏈接多個動畫
與內聯樣式不同,CSS-in-JS 允許你使用關鍵幀定義動畫。 例如,這是使用 styled-components
做的:
const heightAnimation = keyframes`
0% { height: 0; }
100% { height: 200; }
`;
const myComponent = styled.div`
display: inline-block;
width: 200;
position: relative;
animation-name: ${heightAnimation};
animation-duration: 1.5s;
animation-timing-function: ease;
`;
但是很多人不知道的是,你可以通過在 animation
屬性中使用多個關鍵幀對象來鏈接多個動畫。 下面是修改後的兩個動畫的例子:
const heightAnimation = keyframes`
0% { height: 0; }
100% { height: 200; }
`;
const rotateAnimation = keyframes`
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
`;
const myComponent = styled.div`
display: inline-block;
width: 200;
position: relative;
animation: ${props => css`
${heightAnimation} 1.5s ease infinite,
${rotateAnimation} 1.5s linear infinite
`}
`;
Radium
是另一個通過傳遞關鍵幀對象數組作爲 animationName
屬性值來支持多個 動畫 的庫:
const heightAnimation = Radium.keyframes(
{
0% { height: 0; }
100% { height: 200; }
},
'myHeightAnimation',
);
const rotateAnimation = Radium.keyframes(
{
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
},
'myRotateAnimation',
);
const styles = {
myStyle: {
animationName: [heightAnimation, rotateAnimation],
animationDuration: '1.5s, 1s',
animationIterationCount: 'infinite, infinite',
animationTimingFunction: 'ease, linear',
display: inline-block;
width: 200;
position: relative;
},
};
4.聲明全局樣式
CSS 中的一切都是全局的,使用 CSS-in-JS 的目的之一是消除全局樣式定義。
但是,全局樣式的使用有時可能是很有效的,例如,當你想對頁面中的每個元素應用相同的字體樣式時。
當然,你總是可以使用傳統的 CSS,通過 Webpack 導入或在 index.html
文件中聲明它。
但是,如果您真的想在所有樣式中使用 JavaScript,那麼有些庫實際上允許您通過 helper
組件或擴展/插件來定義全局樣式。
在 Radium
中,您可以使用 Style 組件來渲染具有全局樣式的樣式元素。 例如:
<Style
rules={{
body: {
fontFamily: 'Arial, Helvetica, sans-serif'
}
}}
/>
將返回:
<style>
body {
font-family: 'Arial, Helvetica, sans-serif';
}
</style>
JSS
使用一個 插件 來編寫全局樣式:
const styles = {
'@global': {
body: {
fontFamily: 'Arial, Helvetica, sans-serif'
}
}
}
在 Aphrodite
中,你可以用 第三方擴展 來做:
import {injectGlobalStyles} from "aphrodite-globals";
injectGlobalStyles({
"body": {
fontFamily: 'Arial, Helvetica, sans-serif',
}
});
或者通過 aphrodit-jss 來使用 JSS
全局插件。
5.在單元測試中使用樣式測試組件
有些庫包含用於測試組件樣式的工具。
Aphrodite
提供了一個沒有文檔說明(至少在寫這篇文章的時候是這樣)的對象StyleSheetTestUtils,它僅適用於非生產環境(process.env.NODE_ENV!=='production'
),有三個方法:
-
suppressStyleInjection
:它阻止樣式被注入到DOM中,當你想要在沒有DOM的情況下測試Aphrodite
組件的輸出時非常有用。 -
clearBufferAndResumeStyleInjection
:它與suppressStyleInjection
相反,所以它們應該搭配使用。 -
getBufferedStyles
:它返回尚未刷新的緩衝樣式字符串。
以下是如何使用它們的示例:
import { StyleSheetTestUtils, css } from 'aphrodite';
//...
beforeEach(() => {
StyleSheetTestUtils.suppressStyleInjection();
});
afterEach(() => {
StyleSheetTestUtils.clearBufferAndResumeStyleInjection();
});
test('my test', () => {
const sheet = StyleSheet.create({
background: {
backgroundColor: 'blue'
},
});
css(sheet.background);
// buffer will contain something like [ ".background_k554e1{background-color:blue !important;}" ]
const buffer = StyleSheetTestUtils.getBufferedStyles();
// ...
});
Radium
是另一個例子。它有一個 TestMode 對象,用於在測試期間使用 clearState
,enable
和 disable
方法控制內部狀態和行爲。
在 這裏,您可以找到如何使用它的示例。
結論
CSS-in-JS 是一種使用 JavaScript爲應用程序設置樣式的技術,你可以使用實現它的庫來做有趣的事情。
在這篇文章中,我向你展示了5件你可能不知道可以使用這些庫來做的事情。當然,並不是所有的庫都是對等的,有些情況只適用於特定的庫。
在這個 頁面 中,您可以測試和比較許多 CSS-in-JS 的庫。
另一方面,還有其他庫正在進一步採用 CSS,JavaScript和類型的概念。
其中一個庫是 stylable,一個基於組件的庫,帶有一個預處理器,可以將 stylable 的 CSS 轉換成最小的跨瀏覽器的 vanilla CSS。