Slide 1

Slide 1 text

從 Styled System 看下⼀一代 CSS 技術 Anna Su

Slide 2

Slide 2 text

Anna Su Front-end Engineer

Slide 3

Slide 3 text

技術演變 CSS

Slide 4

Slide 4 text

傳統 CSS @池⽥田曉⼦子

Slide 5

Slide 5 text

SASS LESS index.sass .breadcrumb { display: flex; } .breadcrumb-item { display: flex; &.active { color: $breadcrumb-active-color; } }

Slide 6

Slide 6 text

BEM OOCSS SMACSS index.sass .breadcrumb { display: flex; } .breadcrumb__item { display: flex; &.breadcrumb__item--active { color: $breadcrumb-active-color; } }

Slide 7

Slide 7 text

的時代 元件化

Slide 8

Slide 8 text

CSS Module breadcrumb.sass .breadcrumb { display: flex; .item { display: flex; &.active { color: blue; } } } Breadcrumb.js import React from "react"; import styles from "./breadcrumb.scss"; const Breadcrumb = () => { return (
products
iphone
airpods
); } export default Breadcrumb;

Slide 9

Slide 9 text

CSS Module breadcrumb.sass .breadcrumb { display: flex; .item { display: flex; &.active { color: blue; } } } Breadcrumb.js import React from "react"; import classNames from "classnames"; import styles from "./breadcrumb.scss"; const cx = classNames.bind(styles); const Breadcrumb = () => { return (
products
iphone
airpods
); }; export default Breadcrumb; classnames

Slide 10

Slide 10 text

CSS in JS Breadcrumb.js import React from "react"; import styled from "styled-components"; const Wrapper = styled.div` display: flex; `; const Item = styled.a` display: flex; color: ${props => (props.active ? "blue" : "black")}; &::after { content: "/"; } &:last-child { &::after { content: ""; } } `; const Breadcrumb = () => { return ( products

Slide 11

Slide 11 text

不容易易修改樣式 UI component library

Slide 12

Slide 12 text

Ant Design

Slide 13

Slide 13 text

Slider

Slide 14

Slide 14 text

@slider-rail-background-color-hover: #e1e1e1; @slider-track-background-color: @primary-3; @slider-track-background-color-hover: @primary-4; Ant Design Less variables

Slide 15

Slide 15 text

找到對應的 class 名稱,再覆蓋樣式 如果需要變更更樣式

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

const StyledSlider = styled(Slider)` .ant-slider-handle { width: 24px; height: 24px; margin-top: -10px; } `;

Slide 18

Slide 18 text

有沒有辦法更更彈性的修改樣式?

Slide 19

Slide 19 text

簡介 Styled System

Slide 20

Slide 20 text

是⼀一個 Library Styled System 幫我們快速建立 API ⼀一致的 UI 元件

Slide 21

Slide 21 text

提供 style props API Styled System

Slide 22

Slide 22 text

Button B U T T O N Button

Slide 23

Slide 23 text

import { space, layout, typography, border, color } from 'styled-system'; const StyledButton = styled.button` cursor: pointer; ${space} ${color} ${layout} ${typography} ${border} `; Button !

Slide 24

Slide 24 text

import { space, layout, typography, border, color } from 'styled-system'; const StyledButton = styled.button` cursor: pointer; ${space} ${color} ${layout} ${typography} ${border} `; Button !

Slide 25

Slide 25 text

import { space, layout, typography, border, color } from 'styled-system'; const StyledButton = styled.button` cursor: pointer; ${space} ${color} ${layout} ${typography} ${border} `; Button !

Slide 26

Slide 26 text

import { space, layout, typography, border, color } from 'styled-system'; const StyledButton = styled.button` cursor: pointer; ${space} ${color} ${layout} ${typography} ${border} `; Button !

Slide 27

Slide 27 text

import { space, layout, typography, border, color } from 'styled-system'; const StyledButton = styled.button` cursor: pointer; ${space} ${color} ${layout} ${typography} ${border} `; Button !

Slide 28

Slide 28 text

Button ! Button B U T T O N Button

Slide 29

Slide 29 text

⼤大幅降低 props 命名不⼀一致的問題

Slide 30

Slide 30 text

Label1! Button2 Button1 Label2 Label1 Button1!

Slide 31

Slide 31 text

Label1! Button1! Button2 Button1 Label2 Label1

Slide 32

Slide 32 text

傳入樣式的程式碼更更簡潔

Slide 33

Slide 33 text

const StyledButton = styled.button` padding: ${(props) !=> props.padding}; margin-left: ${(props) !=> props.marginLeft}; width: ${(props) !=> props.width}; height: ${(props) !=> props.height}; font-size: ${(props) !=> props.fontSize}; font-family: ${(props) !=> props.fontFamily}; line-height: ${(props) !=> props.lineHeight}; border: ${(props) !=> props.border}; border-radius: ${(props) !=> props.borderRadius}; color: ${(props) !=> props.color}; background-color: ${(props) !=> props.backgroundColor}; cursor: pointer; … `; const StyledButton = styled.button` ${space} ${layout} ${typography} ${border} ${color} cursor: pointer; `;

Slide 34

Slide 34 text

可⾼高度⾃自定義的 theme Styled System

Slide 35

Slide 35 text

const theme = { breakpoints: ['768px'], space: [0, 4, 8, 16, 24, 32, 64], fontSizes: [12, 14, 16, 20, 24, 32], colors: { black: '#000', blacks: ['#ccc', '#999'] white: '#fff', primary: '#456000', }, !!... }

Slide 36

Slide 36 text

const theme = { colors: { black: '#000', white: '#fff', primary: '#456000', }, !!... }

Slide 37

Slide 37 text

export const Box = styled.div` ${color} `; const theme = { colors: { black: '#000', white: '#fff', primary: '#456000', }, !!... }

Slide 38

Slide 38 text

import React from 'react'; import { ThemeProvider } from 'styled-components'; import theme from './theme'; const App = props !=> ( {!/* application elements !*/} ! ) export default App; const theme = { breakpoints: ['768px'], space: [0, 4, 8, 16, 24, 32, 64], fontSizes: [12, 14, 16, 20, 24, 32], colors: { black: '#000', blacks: ['#ccc', '#999'] white: '#fff', primary: '#456000', }, button: { !!... }, breadcrumb: { !!... } … pagination: { !!... } }

Slide 39

Slide 39 text

const theme = { breakpoints: ['768px'], space: [0, 4, 8, 16, 24, 32, 64], fontSizes: [12, 14, 16, 20, 24, 32], colors: { black: '#000', blacks: ['#ccc', '#999'] white: '#fff', primary: '#456000', }, button: { !!... }, breadcrumb: { !!... } … pagination: { !!... } }

Slide 40

Slide 40 text

const theme = { breakpoints: ['768px'], space: [0, 4, 8, 16, 24, 32, 64], fontSizes: [12, 14, 16, 20, 24, 32], colors: { black: '#000', blacks: ['#ccc', '#999'] white: '#fff', primary: '#456000', }, button: { !!... }, breadcrumb: { !!... } … pagination: { !!... } }

Slide 41

Slide 41 text

const theme = { breakpoints: ['768px'], space: [0, 4, 8, 16, 24, 32, 64], fontSizes: [12, 14, 16, 20, 24, 32], colors: { black: '#000', blacks: ['#ccc', '#999'] white: '#fff', primary: '#456000', }, button: { !!... }, breadcrumb: { !!... } … pagination: { !!... } }

Slide 42

Slide 42 text

⾃自訂不同的元件變異異 Styled System

Slide 43

Slide 43 text

const theme = { buttons: { size: { large: { height: 40, padding: '0 10px', }, small: { height: 26, padding: '0 10px', }, default: { height: 32, padding: '0 10px', }, }, }, … } Button Button Button Default Small Large

Slide 44

Slide 44 text

const theme = { buttons: { size: { large: { height: 40, padding: '0 10px', }, small: { height: 26, padding: '0 10px', }, default: { height: 32, padding: '0 10px', }, }, }, … } Button Button Button Default Small Large

Slide 45

Slide 45 text

Button! const Button = styled.button` ${buttonSizeStyle} `; const buttonSizeStyle = variant({ prop: 'size', key: 'buttons.size', }); Button Button Button Default Small Large

Slide 46

Slide 46 text

Button! Button Button Button Default Small Large const theme = { buttons: { size: { large: { height: 40, padding: '0 10px', }, small: { height: 26, padding: '0 10px', }, default: { height: 32, padding: '0 10px', }, }, }, … }

Slide 47

Slide 47 text

Primary Default Danger Button Button Button

Slide 48

Slide 48 text

const theme = { buttons = { default: { color: "white", backgroundColor: "gray" }, primary: { color: "white", backgroundColor: "blue" }, danger: { color: "black", backgroundColor: "tomato" }, … }

Slide 49

Slide 49 text

import { buttonStyle } from "styled-system"; const Button = styled.button` ${buttonStyle} `;

Slide 50

Slide 50 text

Button! Button! Button! Button.defaultProps = { variant: 'default', }

Slide 51

Slide 51 text

const theme = { buttons = { default: { color: "white", backgroundColor: "gray" }, primary: { color: "white", backgroundColor: "blue" }, danger: { color: "black", backgroundColor: "tomato" }, … } Button Button Button Primary Default Danger Button!

Slide 52

Slide 52 text

Button Danger Button! Large

Slide 53

Slide 53 text

能夠靈活變更更 RWD 樣式 Styled System

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

const theme = { breakpoints: ['576px', '768px'] };

Slide 56

Slide 56 text

const breakpoints = ['576px', '768px'];

Slide 57

Slide 57 text

const Article = styled.div` width: 100%; … @media (min-width: 567px) { width: 50%; … } @media (min-width: 768px) { width: 25%; … } `; const breakpoints = ['576px', '768px'];

Slide 58

Slide 58 text

Anna Su Front-End Developer [email protected] 935-721-3322 [email protected] 935-721-3322 Anna Su Front-End Developer

Slide 59

Slide 59 text

Anna Su Front-End Developer [email protected] 935-721-3322 [email protected] 935-721-3322 Anna Su Front-End Developer import { flexbox, space, typography } from 'styled-system'; const Info = styled.div` display: flex; ${flexbox} ${space} ${typography} `; !

Slide 60

Slide 60 text

style props API Theme Specification Variants Responsive Styles

Slide 61

Slide 61 text

建立⾃自⼰己團隊的 UI Component 透過 Styled System

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

請設計師提供 Design System

Slide 65

Slide 65 text

@css day 2019

Slide 66

Slide 66 text

@css day 2019

Slide 67

Slide 67 text

No content

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

No content

Slide 71

Slide 71 text

@84colors

Slide 72

Slide 72 text

@css day 2019

Slide 73

Slide 73 text

可以在開發時,更更全⾯面思考該如何抽象化樣式 Design system

Slide 74

Slide 74 text

⽤用 Styled System 開發元件需要注意的細節

Slide 75

Slide 75 text

theme 使⽤用 array 設定樣式時, 需要花比較多時間思考

Slide 76

Slide 76 text

theme.js const theme = { breakpoints: ['40em', '52em', '64em'], space: [0, 4, 8, 16, 24, 32, 64], colors: { blacks: ['#000', '#ccc', '#aaa', '#eee', '#999'] }, button: { !!... }, breadcrumb: { !!... } … pagination: { !!... } }

Slide 77

Slide 77 text

Slide 78

Slide 78 text

const theme = { breakpoints: ['40em', '52em', '64em'], space: [0, 1, 2, 4, 8, 16, 32, 64], colors: { !!... }, button: { !!... }, breadcrumb: { !!... } … pagination: { !!... } } 有邏輯的 Array space value = 2 的 n 次⽅方 space index = n + 1

Slide 79

Slide 79 text

Slide 80

Slide 80 text

const theme = { colors: { primary: '#4560B0', primaryDark: '#233771', primaryHover: '#6A7FBF', primaryLight: '#B9C4E3', danger: '#f44336', icon: '#aaa', link: '#4A90E2', border: '#ccc', } } 有語意的 key

Slide 81

Slide 81 text

primary="#4560B0"

Slide 82

Slide 82 text

注意樣式被覆蓋的問題

Slide 83

Slide 83 text

const Title = styled.h2` ${space} margin: 0; `; Hello! module 的順序在上⽅方 造成樣式被覆蓋

Slide 84

Slide 84 text

const Title = styled.h2` margin: 0; ${space} `; Hello! 建議 module 統⼀一放在 樣式下⽅方

Slide 85

Slide 85 text

export const Box = styled.div` box-sizing: border-box; ${space} ${layout} `; Hello! const Title = styled(Box)` line-height: 1.42; font-weight: normal; margin: 0; `; 擴充元件時, 注意樣式被覆蓋

Slide 86

Slide 86 text

export const Box = styled.div` box-sizing: border-box; ${space} ${layout} `; Hello! export const Title = styled(Box).attrs({ m: 0 })` line-height: 1.42; font-weight: normal; `; 擴充元件時, 建議使⽤用 attach props

Slide 87

Slide 87 text

使⽤用第三⽅方 UI Library Styled System

Slide 88

Slide 88 text

rebass

Slide 89

Slide 89 text

grommet

Slide 90

Slide 90 text

No content

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

Slider

Slide 93

Slide 93 text

!

Slide 94

Slide 94 text

const StyledSlider = styled(Slider)` .ant-slider-handle { width: 24px; height: 24px; margin-top: -10px; } `; @slider-rail-background-color-hover: #e1e1e1; @slider-track-background-color: @primary-3; @slider-track-background-color-hover: @primary-4; !

Slide 95

Slide 95 text

! !

Slide 96

Slide 96 text

No content

Slide 97

Slide 97 text

No content

Slide 98

Slide 98 text

紅⾊色!

Slide 99

Slide 99 text

紅⾊色! 的逆襲? HTML

Slide 100

Slide 100 text

‣ https://styled-system.com/ ‣ Brad Frost | The Technical Side of Design Systems | UI Special, CSS Day 2019 ‣ https://material-ui.com/system/basics/ ‣ https://material.io/design/ ‣ https://ant.design/components/slider/ ‣ https://storybook.grommet.io/ Reference

Slide 101

Slide 101 text

No content