從一個按鈕實例入門CSS in JS之styled-components
前言
最近接手一個react項目,項目中使用的 CSS in JS方案來實現CSS模塊化,它使用的包是styled-components
我以前的項目Vue居多的,Vue是很簡單的通過scoped就可以實現模塊化CSS,當然也在項目中用過CSS Modules方案,但CSS in JS還是第一次接觸到,正好趁這個時機學習一下,在做demo時候把平時開發用的比較高頻的CSS特性都試了一下,最終完成了一個小按鈕demo,突然發現它是一個不錯的用來入門styled-components不錯的小案例,特記錄
styled-components介紹
主要作用是它可以編寫實際的CSS代碼來設計組件樣式,也不需要組件和樣式之間的映射,即創建后就是一個正常的React組件,在一個組件內會將結構、樣式和邏輯寫在一起,雖然這違背了關注點分離的原則,但是這有利于組件間的隔離
使用styled-components不需要再使用className屬性來控制樣式,而是將樣式寫成更具語義化的組件的形式,使用style-components會隨機生成一個class名稱,這樣保證每個元素的樣式名都是唯一的,當然因為隨機生成,維護會增加難度,很難通過樣式名定位到元素
入門styled-components的小按鈕效果
小按鈕的關鍵代碼
import styled, { keyframes, createGlobalStyle, css } from 'styled-components'
const Wrap = styled.div`
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 20px;
`
// css幀動畫
const aniTag = keyframes`
0% {
opacity: 0;
transform: translateY(-100%);
}
100% {
opacity: 1;
transform: translateY(0);
}
`
const MyButton = styled.div`
width: 400px;
height: 80px;
border:1px solid gray;
border-radius: 10px;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
// 傳參
background-color: ${props => props.bgNormalColor ? props.bgNormalColor : 'blue'};
transition: background-color 0.3s ease-in-out;
// 偽元素
&::after{
content: 'after';
height: 20px;
font-size: 14px;
line-height: 20px;
padding:0 5px;
border-radius: 0 0 6px 6px;
position: absolute;
top: 0;
right: 10px;
background-color: yellow;
color: ${props => props.hightightColor ? props.hightightColor : 'white'};
opacity: 0;
}
// 子孫選擇器
p {
line-height: 24px;
color: ${props => props.normalColor ? props.normalColor : 'black'};
transition: color 0.3s ease-in-out;
}
// 當有全局樣式的時候,使用&&提高局部樣式優先級來覆蓋全局樣式
&& span{
color: rgba(255,0,255,0.6);
}
// 類選擇器
.emphasize{
text-decoration: underline;
}
// 偽類
&:hover{
background-color: ${props => props.bgHighlightColor ? props.bgHighlightColor : 'yellow'};
p{
color: ${props => props.hightightColor ? props.hightightColor : 'white'};
}
// css animation動畫
&::after{
animation: ${aniTag} 0.4s ease-in-out forwards;
}
}
`
// 全局樣式
const GlobalStyle = createGlobalStyle`
*{
padding: 0;
margin: 0;
}
${MyButton}{
span{
color: rgba(255,255,255,0.6);
font-size: 12px;
line-height: 20px;
}
}
`
export default function StyleComponentsTest() {
return (
<Wrap>
<GlobalStyle />
<MyButton
bgNormalColor="gray"
bgHighlightColor="white"
normalColor='rgba(255,255,255,0.6)'
hightightColor="red"
>
<p><strong className="emphasize">styled components</strong> 入門</p>
<span>我是只小小鳥</span>
</MyButton>
</Wrap>
)
}
這個小demo有用到styled-components的關鍵技術點:
- 其本語法,見Wrap
- 動態樣式實現,通過$
- 怎么寫全局樣式,見createGlobalStyle
- 怎么實現子/孫元素樣式控制,見p和strong元素樣式控制
- 怎么實現偽類,見:hover
- 怎么實現偽元素,見::after
- 怎么實現動畫,見transition/keyframes
- 當全局樣式和自帶樣式沖突的,怎么提高樣式優先級,見span
示例代碼都做了詳細的注釋,可以瀏覽代碼了解詳情
補充
其實通過實現上面示例基本算已經入門styled-components了,但是開發經常要考慮代碼復用,那styled-components怎么實現CSS復用,我來優化一下demo
最終實現的效果如下:
關鍵代碼如下:
import styled, { keyframes, createGlobalStyle, css } from 'styled-components'
// 樣式復用
const flexColCenter = css`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`
const textHighlightColor = css`
color: ${props => props.hightightColor ? props.hightightColor : 'white'};
`
const Wrap = styled.div`
width: 100%;
height: 100vh;
${flexColCenter}
gap: 20px;
`
// css幀動畫
const aniTag = keyframes`
0% {
opacity: 0;
transform: translateY(-100%);
}
100% {
opacity: 1;
transform: translateY(0);
}
`
const MyButton = styled.div`
width: 400px;
height: 80px;
border:1px solid gray;
border-radius: 10px;
overflow: hidden;
${flexColCenter}
position: relative;
// 傳參
background-color: ${props => props.bgNormalColor ? props.bgNormalColor : 'blue'};
transition: background-color 0.3s ease-in-out;
// 偽元素
&::after{
content: 'after';
height: 20px;
font-size: 14px;
line-height: 20px;
padding:0 5px;
border-radius: 0 0 6px 6px;
position: absolute;
top: 0;
right: 10px;
background-color: yellow;
${textHighlightColor}
opacity: 0;
}
// 子孫選擇器
p {
line-height: 24px;
color: ${props => props.normalColor ? props.normalColor : 'black'};
transition: color 0.3s ease-in-out;
}
// 當有全局樣式的時候,使用&&提高局部樣式優先級來覆蓋全局樣式
&& span{
color: rgba(255,0,255,0.6);
}
// 類選擇器
.emphasize{
text-decoration: underline;
}
// 偽類
&:hover{
background-color: ${props => props.bgHighlightColor ? props.bgHighlightColor : 'yellow'};
p{
${textHighlightColor}
}
// css animation動畫
&::after{
animation: ${aniTag} 0.4s ease-in-out forwards;
}
}
`
const MyButton1 = styled(MyButton)`
border:4px solid gray;
border-radius: 20px;
`
// 全局樣式
const GlobalStyle = createGlobalStyle`
*{
padding: 0;
margin: 0;
}
${MyButton}{
span{
color: rgba(255,255,255,0.6);
font-size: 12px;
line-height: 20px;
}
}
`
export default function StyleComponentsTest() {
return (
<Wrap>
<GlobalStyle />
<MyButton
bgNormalColor="gray"
bgHighlightColor="white"
normalColor='rgba(255,255,255,0.6)'
hightightColor="red"
>
<p><strong className="emphasize">styled components</strong> 入門</p>
<span>我是只小小鳥</span>
</MyButton>
<MyButton1
bgNormalColor="gray"
bgHighlightColor="white"
normalColor='rgba(255,255,255,0.6)'
hightightColor="red"
>
<p><strong className="emphasize">styled components</strong> 入門1</p>
<span>我是只小小鳥1</span>
</MyButton1>
</Wrap>
)
}
關鍵點:
- 樣式復用,見flexColCenter/textHighlightColor
- 樣式繼承重寫,見MyButton1
本來是想放一個在線測試案例的,找了很久都找到能用的React的playground,如果你想自己跑起示例來也是很簡單的,初始化一個最簡單的React示例項目并安裝styled-components依賴,新建一個組件,把上面代碼復制進去即可,推薦直接使用vite初始化項目
// 1命令行執行如下命令,再選擇react即可
npm create vite@latest
或者直接clone我的測試倉庫,你本地測試即可:demo倉庫
小結
個人的知識和能力是有限的,本文只是個人練習styled-components的小demo,應該還有很多styled-components高級用法我沒有了解到,如果有不對的地方或者你有更好的建議,希望不吝留言分享,一起學習一起進步

浙公網安備 33010602011771號