1. Styling 라이브러리 종류
컴포넌트가 많은 경우 일반 CSS로 스타일링을 하다보면 불편함이 생기는데
- class 만들어놓은걸 까먹고 중복해서 또 만들거나
- 갑자기 다른 이상한 컴포넌트에 원하지않는 스타일이 적용되거나
- CSS 파일이 너무 길어져서 수정이 어렵거나
위 경우를 해결하기 위해 라이브러리들을 사용합니다.
💡 CSS의 문제점
Global Namespace: 글로벌 변수를 지양해야하는 JS와 대치Dependencies: css 간의 의존 관리Dead Code Elimination: 안쓰는 css 인지 어려움Minification: 클래스 이름 최소화Sharing Constants: JS의 코드와 값을 공유하고 싶음Non-deterministic Resolution: css 파일 로드 타이밍 이슈Isolation: 격리
css로 꾸밀 떄 사용하는 라이브러리는 크게 CSS-in-CSS 방식과 CSS-in-JS 방식으로 구분합니다.
CSS-in-JS- Styled-Component 공식사이트✔️
- 대표적인 CSS-in-JS
- https://speakerdeck.com/vjeux/react-css-in-js
- Basic : https://styled-components.com/docs/basics
- CSS Selector Ref : https://www.w3schools.com/cssref/css_selectors.php
- API : https://styled-components.com/docs/api
- Emotion 공식사이트✔️
- Styled-Component 공식사이트✔️
CSS-in-CSS: CSS-in-JS 아닌 것들은 다 CSS-in-CSS- Sass (전처리기)✔️
- CSS Module (Post CSS)✔️
- cf. CSS 2022 통계
2. Styled Components
- JS 파일 안에서 CSS를 작성할 수 있는 대표적인 CSS-in-JS 라이브러리
- Styled이 적용된 Component라고 해서
Styled Components라고 부름 - https://styled-components.com/docs/basics#getting-started
- 장점
Automatic critical CSS: 자동 style injects & 코드 스플릿No class name bugs: unique / overlap x / misspellinEasier deletion of CSS: tied to a specific componentSimple dynamic styling: props / global themPainless maintenance: styling affecting your componAutomatic vendor prefixing: current standard o
2.1 예제 : 공식문서 따라해보기
1$ npx create-react-app styleing2$ cd styleing3$ npm install styled-components # Styled Components 설치4$ npm start
2.2 예제1 : 기본 사용법
2.2.1 App.js
1import './App.css'2import StyledComponentsExample from './components/StyledComponentsExample/StyledComponentsExample'34export default function App() {5return (6<div className="App">7<StyledComponentsExample />8</div>9)10}
2.2.2 StyledComponentsExample
1// src/components/StyledComponentsExample/StyledComponentsExample.jsx2import React from 'react'3import styled from 'styled-components'45export default function StyledComponentsExample() {6const Title = styled.h1`7font-size: 1.5em;8text-align: center;9color: palevioletred;10`1112// Create a Wrapper component that'll render a <section> tag with some styles13const Wrapper = styled.section`14padding: 4em;15background: papayawhip;16`1718const Button = styled.button`19/* Adapt the colors based on primary prop */20background: ${props => (props.primary ? 'palevioletred' : 'white')};21color: ${props => (props.primary ? 'white' : 'palevioletred')};2223font-size: 1em;24margin: 1em;25padding: 0.25em 1em;26border: 2px solid palevioletred;27border-radius: 3px;28`2930const TomatoButton = styled(Button)`31color: tomato;32border-color: tomato;33`3435const ReversedButton = props => <Button {...props} children={props.children.split('').reverse()} />3637// Use Title and Wrapper like any other React component – except they're styled!38return (39<>40<Wrapper>41<Title>Hello World!</Title>42</Wrapper>43<Button onClick={() => alert('normal')}>Normal</Button>44<Button onClick={() => alert('normal')} primary>45Primary46</Button>47<TomatoButton>Tomato 확장 버튼</TomatoButton>4849<Button as="a" href="#">50Link with Button styles51</Button>52<TomatoButton as="a" href="#">53Link with Tomato Button styles54</TomatoButton>5556<Button as={ReversedButton}>Custom Button with Normal Button styles</Button>57</>58)59}
2.3 예제2 : 상속(&)
1import React from 'react'2import styled from 'styled-components'34const Thing = styled.div.attrs((/* props */) => ({ tabIndex: 0 }))`5color: blue;67// "&(ampersand)"는 현재 선택된 요소를 의미, 해당 컴포넌트 아래에 있는 자식들을 참조할 수 있음8&:hover {9color: red; // <Thing> when hovered10}1112// 일반 형제 결합자 : 첫번쟤 요소를 뒤따르면서 같은 부모와 공유하는 2번쟤 형제 요소 선택13// Thing의 바로 옆은 아니지만 형제요소일 때14& ~ & {15background: tomato; // <Thing> as a sibling of <Thing>, but maybe not directly next to it16}1718// 인접 형제 결합자 : 첫번쟤 요소를 뒤따르면서 바로 뒤에 있는 2번쟤 형제 요소 선택19// Thing이 바로 옆에 붙어있을 때20& + & {21background: lime; // <Thing> next to <Thing>22}2324// Thing이 something이라는 클래스를 갖고있을 때25&.something {26background: orange; // <Thing> tagged with an additional CSS class ".something"27}2829// // something-else라는 클래스를 가진 친구안에 있을 때30.something-else & {31border: 1px solid; // <Thing> inside another element labeled ".something-else"32}33`3435export default function StyledComponentsExample() {36// Use Title and Wrapper like any other React component – except they're styled!37return (38<>39<Thing>Hello world!</Thing>40<Thing>How ya doing?</Thing>41<Thing className="something">The sun is shining...</Thing>42<div>Pretty nice day today.</div>43<Thing>Don't you think?</Thing>44<div className="something-else">45<Thing>Splendid.</Thing>46</div>47</>48)49}
2.4 예제3 : Overriding .attrs
1import React from 'react'2import styled from 'styled-components'34const Input = styled.input.attrs(props => ({5type: 'text',6size: props.size || '1em',7}))`8border: 2px solid palevioletred;9margin: ${props => props.size};10padding: ${props => props.size};11`1213// Input's attrs will be applied first, and then this attrs obj14const PasswordInput = styled(Input).attrs({15type: 'password',16})`17// similarly, border will override Input's border18border: 2px solid aqua;19`2021export default function StyledComponentsExample() {22// Use Title and Wrapper like any other React component – except they're styled!23return (24<>25<Input placeholder="A bigger text input" size="2em" />2627{/* Notice we can still use the size attr from Input */}28<PasswordInput placeholder="A bigger password input" size="2em" />29</>30)31}
2.5 예제4 : Animations
1import React from 'react'2import styled, { keyframes } from 'styled-components'34const rotate = keyframes`5from {6transform: rotate(0deg);7}89to {10transform: rotate(360deg);11}12`1314const Rotate = styled.div`15display: inline-block;16animation: ${rotate} 2s linear infinite;17padding: 2rem 1rem;18font-size: 1.2rem;19`2021export default function StyledComponentsExample() {22// Use Title and Wrapper like any other React component – except they're styled!23return (24<>25<Rotate>< 💅🏾 ></Rotate>26</>27)28}
2.6 예제5 : Theme
1import React, { useState } from 'react'2import styled, { ThemeProvider } from 'styled-components'34// Define our button, but with the use of props.theme this time5const Button = styled.button`6font-size: 1em;7margin: 1em;8padding: 0.25em 1em;9border-radius: 3px;1011/* Color the border and text with theme.main */12color: ${props => props.theme.color};13border: 2px solid ${props => props.theme.borderColor};14`1516// Define what props.theme will look like17const defaultTheme = {18color: 'green',19borderColor: 'pink',20}2122const redTheme = {23color: 'red',24borderColor: 'red',25}2627export default function StyledComponentsExample() {28const [theme, setTheme] = useState(defaultTheme)29// Use Title and Wrapper like any other React component – except they're styled!30return (31<div>32<button onClick={() => setTheme(redTheme)}>red</button>33<button onClick={() => setTheme(defaultTheme)}>green</button>34<ThemeProvider theme={theme}>35<Button>Normal</Button>36<Button>Themed</Button>37</ThemeProvider>38</div>39)40}
2.7 예제 6 : Helpers
- https://styled-components.com/docs/api#helpers
- 전역 스타일(Global Style) 설정
1import React, { useState } from 'react'2import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'34// Define our button, but with the use of props.theme this time5const Button = styled.button`6font-size: 1em;7margin: 1em;8padding: 0.25em 1em;9border-radius: 3px;1011/* Color the border and text with theme.main */12color: ${props => props.theme.color};13border: 2px solid ${props => props.theme.borderColor};14`1516// Define what props.theme will look like17const defaultTheme = {18color: 'green',19borderColor: 'pink',20}2122const redTheme = {23color: 'red',24borderColor: 'red',25}2627const GlobalStyle = createGlobalStyle`28button {29background-color : pink;30}31`3233export default function StyledComponentsExample() {34const [theme, setTheme] = useState(defaultTheme)35// Use Title and Wrapper like any other React component – except they're styled!36return (37<>38<div>39<GlobalStyle />40<button onClick={() => setTheme(redTheme)}>red</button>41<button onClick={() => setTheme(defaultTheme)}>green</button>42<ThemeProvider theme={theme}>43<Button>Normal</Button>44<Button>Themed</Button>45</ThemeProvider>46</div>47<div>48<button>Other</button>49</div>50</>51)52}