Styled-component 元件管理
參加 Web 實驗室 React 讀書會所做的筆記
Styled-component 元件管理
React 以輕量化 Library 自居,因此 React 在樣式刻畫、狀態管理、網頁互動上充滿靈活、自由的樣貌,相同的問題,有各式各樣的解決方案!
前言
如何根據狀態(state)來動態改變 Web 的 CSS 樣式呢?大家透過各自的經驗及想法提出了許多不同的方案,包含:Styled Components, CSS module, Styled JS, Emotion, JSS, Glamor, Radium, Aphrodite 等...。在 CSS 2019 當中,CSS in JS 篇章裡 Styled Components 在 關注度、感興趣程度及滿意度 綜合評比中獲得非常不錯的總體評價。
styled-components 能在 JSX 當中 基於已刻畫好的元件中,透過 template literals ,在其中撰寫 CSS 樣式。使我們可以更專注、聚焦在每個元件之下,為使用者提供更好的體驗及視覺呈現。
styled-components 的特點
Automatic critical CSS: styled-components持續追蹤頁面上顯示的元件,並在其中注入樣式,完全自動化,可讓開發者 代碼分割(code splitting),同時替使用者提供更好的體驗。(不載入未使用的冗余程式碼,提升載入速度)No class name bugs: styled-components自動替你的樣式,產生 class 名稱,不必再擔心命名的衝撞、想不到名字的窘境、拼錯字、重複使用等...。Easier deletion of CSS:傳統的程式碼在檔案之前,很難辨別某個 class name 在哪些地方被使用過了, styled-components 使元件結構與樣式的關聯,顯而易見,每份樣式都專注對應在某個元件上。假如這個元件沒被使用、想刪除了,這個樣式很容易跟著被一起刪除。Simple dynamic styling:當你需要根據某個 props 或是 global theme 來動態改變樣式時,styled-components 使這件事變得容易,不用手動管理無數的 css classes。Painless maintenance:不用再跨檔案去尋找你的樣式與結構,你可以在同一份檔案之中,替你的元件上結構及樣式。在維護上,就算未來你的 codebase 變更大了,也不會變得能以掌控。Automatic vendor prefixin:依照當前的標準來撰寫你的 CSS,讓 styled-components 替你完成其他任務,不用再思考不同瀏覽器間的前綴字,可以更專注在開發樣式上。-webkit- (Chrome, Safari, iOS Safari / iOS WebView, Android) -moz- (Firefox) -ms- (Edge, Internet Explorer) -o- (Opera, Opera Mini) CSS Vendor Prefixes
- 直接在 styled 預設提供的 HTML 元件,寫入 css 樣式
const Button = styled.button`
background: blue;
color: white;
&:hover {
background: gray;
color: black;
}
`;
render(<Button> 點我!</Button>);
- 透過 props 動態改變 styled-components 的元件
``javascript= const Button = styled.button<{ primary?: boolean }>background: ${props => (props.primary ? 'pink' : 'blue')}; color: ${props => (props.primary ? 'white' : 'green')}; &:hover { background: gray; color: black; } `;
render(
3. 基於某個 styled-components 之上,創造新的元件
```javascript=
const Button = styled.button`
background: blue;
color: white;
&:hover {
background: gray;
color: black;
}
`;
const CoolButton = styled(Button)`
background: yellow;
color: pink;
&:hover {
background: pink;
color: yellow;
}
`;
render(
<div>
<Button> 點我!</Button>
<CoolButton> 點我!</CoolButton>
</div>
);
如此可知,我們便可以修改某些其他人寫好的 styled-components 了
如 MATERIAL-UI, Ant Design 等等, 目前都有支援 styled-components 互動了
import Button from '@material-ui/core/Button';
const ChillButton = styled(Button)`
font-weight: 900;
text-transform: inherit;
`;
render(
<ChillButton variant="contained" color="primary">
Yoyoyo 點我!
</ChillButton>
);
題外話,與有支援的第三方套件互動?!(以 MATERIAL-UI 為例) 期待其他大大分享如 Ant Design 等相關經驗。
有時候,我們會需要修改、覆寫到第三方套件預設的樣式,難不成要用到兇殘的 !important?
import Button from '@material-ui/core/Button';
const ChillButton = styled(Button)`
color: blue !important;
font-weight: 900;
text-transform: inherit;
`;
render(
<ChillButton variant="contained" color="primary">
Yoyoyo 點我!
</ChillButton>
);
也許你還有其他種解法,就是 MATERIAL-UI 提供改變注入樣式的優先順序的方法
import { StylesProvider } from '@material-ui/core/styles';
render(
<StylesProvider injectFirst>
<App />
</StylesProvider>
);
- 如何與其他無支援 styled-components 的元件互動及修改樣式呢? (含其他第三方、自己的元件)
透過綁定 className 使 styled-components 能注入樣式,此範例來自官網 styling-any-component
// from official document https://styled-components.com/docs/basics#styling-any-component
// This could be react-router-dom's Link for example
const Link = ({ className, children }) => (
<a className={className}>{children}</a>
);
const StyledLink = styled(Link)`
color: palevioletred;
font-weight: bold;
`;
render(
<div>
<Link>Unstyled, boring Link</Link>
<br />
<StyledLink>Styled, exciting Link</StyledLink>
</div>
);
進階
- 參考其他元件,在元件樣式中使用 css 選擇器,選取其子元件
註解:& 代表 當下的這個元件,於是我們可以使用 &:hover,& > ${SomeComponent}
const StyledTitle = styled.h2`
font-weight: 800;
font-size: 20px;
`;
const StyledSection = styled.div`
display: flex;
align-items: center;
& > ${StyledTitle} {
margin-right: 20px;
padding: 50px;
}
`;
render(
<StyledSection>
<StyledTitle>You're the best!</StyledTitle>
</StyledSection>
);
- 參考其他元件,在元件樣式偵測上面,父元件的狀態
Icon 包在 Button 底下,有時我們會希望當 Button 被 hover 到時,Icon 的樣式也能一起動態改變樣式
參考文獻:
const Button = styled.button<{ primary?: boolean }>`
background: ${props => (props.primary ? 'pink' : 'blue')};
color: ${props => (props.primary ? 'white' : 'green')};
&:hover {
background: gray;
color: black;
}
`;
const Icon = styled.i`
color: white;
background-color: orange;
font-size: 1.5 rem;
${Button}:hover & {
color: black;
}
`;
render(
<Button>
Click me<Icon>icon </Icon>
</Button>
);
Comments
Join the discussionNo comments yet. Be the first to comment.

