styled-components 的初步探索

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 的特点

1.Automatic critical CSS: styled-components 持续追踪页面上显示的元件,并在其中注入样式,完全自动化,可让开发者 代码分割(code splitting),同时替使用者提供更好的体验。(不载入未使用的冗余程序码,提升载入速度)

  1. No class name bugs: styled-components 自动替你的样式,产生 class 名称,不必再担心命名的冲撞、想不到名字的窘境、拼错字、重复使用等...。

  2. Easier deletion of CSS: 传统的程序码在档案之前,很难辨别某个 class name 在哪些地方被使用过了, styled-components 使元件结构与样式的关联,显而易见,每份样式都专注对应在某个元件上。假如这个元件没被使用、想删除了,这个样式很容易跟着被一起删除。

  3. Simple dynamic styling: 当你需要根据某个 props 或是 global theme 来动态改变样式时,styled-components 使这件事变得容易,不用手动管理无数的 css classes。

  4. Painless maintenance: 不用再跨档案去寻找你的样式与结构,你可以在同一份档案之中,替你的元件上结构及样式。在维护上,就算未来你的 codebase 变更大了,也不会变得能以掌控。

  5. 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

Ken 的styled components 学习笔记

1.直接在 styled 预设提供的 HTML 元件,写入 css 样式

const Button = styled.button`
  background: blue;
  color: white;
  &:hover {
    background: gray;
    color: black;
  }
`;

render(<Button> 点我!</Button>);

2.透过 props 动态改变 styled-components 的元件

const Button = styled.button<{ primary?: boolean }>`
  background: ${props => (props.primary ? 'pink' : 'blue')};
  color: ${props => (props.primary ? 'white' : 'green')};
  &:hover {
    background: gray;
    color: black;
  }
`;

render(
  <div>
    <Button> 点我!</Button>
    <Button primary> 点我!</Button>
  </div>
);

3.基於某个 styled-components 之上,创造新的元件

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>
);

4.如何与其他无支援 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>
);

进阶

5. 参考其他元件,在元件样式中使用 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>
);

6. 参考其他元件,在元件样式侦测上面,父元件的状态

Icon 包在 Button 底下,有时我们会希望当 Button 被 hover 到时,Icon 的样式也能一起动态改变样式
React. 7 tricks to work with Styled Components
Official Doc [Referring to other components]

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>
);

参考

谈谈前端框架
styled-components official document
State of CSS 2019
介绍撰写React CSS的神套件Styled Components
【Day 12】Styled-component
Ways play with styled-components


<<:  故事二十九:今晚,简单练习就好!

>>:  【Day 29】超级好用的侧边栏固定效果 - Sticky Sidebar

Powershell 入门之 Alias

很多时候,我们需要经常运行一些很长的命名,此时,我们可以同给该命令以及部分固定的参数设置一个别名(A...

DAY 12 - 时钟怪 (1)

大家好~ 我是五岁 ( ̄▽ ̄)~* 今天来尝试画一个时钟怪吧~!!! 设定: 它是由一个传统闹钟变成...

数位逻辑 2B OR NOT 2B

数位逻辑 (Digital Logic) 是用来代表电路输入与输出的控制,横跨非常多领域,可以用电子...

【Side Project】 (老板)订单清单UX功能实作

我们接续上一篇完成一些未完成的功能。 完成按钮 & 返回按钮 这两个按钮在整个篇章中,属於比...

【第十二天 - 递回介绍】

Q1. 递回 (recursive) 是什麽? 递回是一种解题的方法,主要是透过「重复呼叫自身程序码...