[React] ๐Ÿ’…Styled-Components ์‚ฌ์šฉ๋ฒ•

TATAยท2023๋…„ 2์›” 20์ผ
0

React

๋ชฉ๋ก ๋ณด๊ธฐ
10/32

CSS-in-JS - The State of CSS 2022์—์„œ
์‚ฌ์šฉ ์ˆœ์œ„๊ฐ€ ์ œ์ผ ๋†’์€ Styled-Component์˜ ์‚ฌ์šฉ๋ฒ•์„ ์•Œ์•„๋ณด์ž๐Ÿ’จ

๐Ÿ’… Styled-Component ์ค€๋น„

โ–ท Styled Components ์„ค์น˜

// with npm
$ npm install --save styled-components

// with yarn
$ yarn add styled-components

โ–ท package.json์— ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€

// ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์—ฌ๋Ÿฌ ๋ฒ„์ „์˜
// Styled Components๊ฐ€ ์„ค์น˜๋˜์–ด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ์ค„์—ฌ์ค€๋‹ค.
{
  "resolutions": {
    "styled-components": "^5"
  }
}

โ–ท import ํ•˜๊ธฐ

import styled from "styled-components"

๐Ÿ’… Styled-Component ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

๋”ฐ์˜ดํ‘œ๊ฐ€ ์•„๋‹Œ ๋ฐฑํ‹ฑ(`)์„ ์‚ฌ์šฉํ•œ๋‹ค.

import styled from "styled-components";

// Styled Components๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ 
const BlueButton = styled.button`
  background-color: blue;
  color: white;
`;

export default function App() {
  // React ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋“ฏ์ด ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
  return <BlueButton>Blue Button</BlueButton>;
}

๐Ÿ’… ์ปดํฌ๋„ŒํŠธ ์žฌํ™œ์šฉ

๊ธฐ์กด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌํ™œ์šฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

import styled from "styled-components";

const BlueButton = styled.button`
  background-color: blue;
  color: white;
`;

//๋งŒ๋“ค์–ด์ง„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌํ™œ์šฉํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
const BigBlueButton = styled(BlueButton)`
  padding: 15px;
  margin-top: 15px;
`;

//์žฌํ™œ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌํ™œ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
const BigRedButton = styled(BigBlueButton)`
  background-color: red;
`;

export default function App() {
  return (
    <>
      <BlueButton>Blue Button</BlueButton>
      <br />
      <BigBlueButton>Big Blue Button</BigBlueButton>
      <br />
      <BigRedButton>Big Red Button</BigRedButton>
    </>
  );
}

๐Ÿ’… Props ํ™œ์šฉ

ํ…œํ”Œ๋ฆฟ ๋ฆฌํ„ฐ๋Ÿด ๋ฌธ๋ฒ• ${ }์œผ๋กœ JavaScript ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


Props๋กœ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

import styled from "styled-components";

export default function App() {
  return (
    <>
      <Button1>Button1</Button1>
      <Button1 skyblue>Button1</Button1>
    </>
  );
}

// ๋ฐ›์•„์˜จ prop์— ๋”ฐ๋ผ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
const Button1 = styled.button`
  background: ${(props) => (props.skyblue ? "skyblue" : "white")};
`;

Props ๊ฐ’์œผ๋กœ ๋ Œ๋”๋ง๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

๋˜๋Š”

import styled from "styled-components";

// ๋ฐ›์•„์˜จ prop ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์ด์šฉํ•ด ๋ Œ๋”๋งํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
const Button1 = styled.button`
  background: ${(props) => (props.color ? props.color : "white")};
`;
// ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•์‹์œผ๋กœ๋„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
const Button2 = styled.button`
  background: ${(props) => props.color || "white"};
`;

export default function App() {
  return (
    <>
      <Button1>Button1</Button1><br />
      <Button1 color="orange">Button1</Button1>
      <Button1 color="tomato">Button1</Button1>
      <br />
      <Button2>Button2</Button2>
      <Button2 color="pink">Button2</Button2>
      <Button2 color="turquoise">Button2</Button2>
    </>
  );
}

๐Ÿ’… ์ „์—ญ ์Šคํƒ€์ผ ์„ค์ •

// createGlobalStyle ๊ฐ€์ ธ์˜ค๊ธฐ
import { createGlobalStyle } from "styled-components";

// ์Šคํƒ€์ผ ์ž‘์„ฑํ•˜๊ธฐ
const GlobalStyle = createGlobalStyle`
	button {
        padding : 5px;
        margin : 2px;
        border-radius : 5px;
	}
`

// <GlobalStyle> ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ
function App() {
	return (
		<>
			<GlobalStyle />
			<Button>์ „์—ญ ์Šคํƒ€์ผ ์ ์šฉํ•˜๊ธฐ</Button>
		</>
	);

์ปดํฌ๋„ŒํŠธ๋กœ ๋งŒ๋“ค์–ด์„œ ์˜ฌ๋ ค๋„ ๋จ

import { createGlobalStyle } from 'styled-components';
import { useLocation } from 'react-router-dom';

function BackgroundColor() {
  const { pathname } = useLocation();

  let background;
  switch (pathname) {
    case '/':
      background = '#EBEEFF';
      break;
    default:
      background = '#FFF';
  }
  return <GlobalStyled $background={background} />;
}

export default BackgroundColor;

const GlobalStyled = createGlobalStyle<{ $background: string; }>`
  body {
    background: ${({ $background }) => $background || '#FFF'};
  }

  @media all and (max-width: 805px) {
    body {
      background: #FFF;
    }
  }
`;

๐Ÿ’… hover ์†์„ฑ ์ ์šฉ

&:hover์— ์Šคํƒ€์ผ์„ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

โ—๏ธ์ฐธ๊ณ ) &๋Š” ํ˜„์žฌ์˜ ์š”์†Œ๋ฅผ ๋œปํ•œ๋‹ค.

const Button1 = styled.button`
  color: ${(props) => props.color || "white"};

  // ํ˜„์žฌ ์š”์†Œ์— ๋งˆ์šฐ์Šค๊ฐ€ ์˜ฌ๋ผ๊ฐˆ ๋•Œ
  &:hover { 
    background: purple;
    color: white;
  }
`;
&(ํ˜„์žฌ ์š”์†Œ) ์‚ฌ์šฉ๋ฒ•


&:hover // ํ˜„์žฌ ์š”์†Œ์— ๋งˆ์šฐ์Šค๊ฐ€ ์˜ฌ๋ผ๊ฐˆ ๋•Œ
& ~ & // ํ˜„์žฌ ์š”์†Œ์˜ ๋ฐ”๋กœ ์˜†์€ ์•„๋‹ˆ์ง€๋งŒ ํ˜•์ œ ์š”์†Œ์ผ ๋•Œ
& + & // ํ˜„์žฌ ์š”์†Œ์˜ ๋ฐ”๋กœ ์˜† ํ˜•์ œ ์š”์†Œ์ผ ๋•Œ
&.something // ํ˜„์žฌ ์š”์†Œ๊ฐ€ something์ด๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ๊ฐ–๊ณ  ์žˆ์„ ๋•Œ
.something & // something์ด๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ๊ฐ€์ง„ ์นœ๊ตฌ ์•ˆ์— ์žˆ์„ ๋•Œ

๐Ÿ’… attrs ๋ฉ”์†Œ๋“œ

attributes๋ฅผ ์‚ฝ์ž…ํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ์ด๋ฉฐ 1๊ฐœ์˜ ๊ฐ์ฒด ํƒ€์ž… arg๋ฅผ ๋ฐ›๋Š”๋‹ค.

html tag๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ณ ์œ ์˜ attributes๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์กŒ๋‹ค.
(ex. <input type="radio" />๋ฅผ ๋งŒ๋“ค ๋•Œ attrs({ type: radio })๋ฅผ ์‚ฌ์šฉ)

export const ModalView = styled.div.attrs((props) => ({
  // attrs ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด div ์—˜๋ฆฌ๋จผํŠธ์— ์†์„ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  role: "dialog",
}))`
  border-radius: 10px;
  background-color: #ffffff;
  width: 400px;
  ...
`;

input ์˜ˆ์‹œ

// ์‘์šฉ1
const Input = styled.input.attrs((props) => ({
  cursor: props.pointer ? "pointer" : "null",
}))`
  cursor: ${({ cursor }) => cursor};
`;

-----
// ์‘์šฉ2
const Input = styled.input.attrs((props) => ({
  cursor: props.pointer ? "pointer" : "null",
  transparent: props.transparent ? "transparent" : "null",
}))`
  cursor: ${({ cursor }) => cursor};
  caret-color: ${({ transparent }) => transparent};
`;

๐Ÿ’… hover + ์ „์—ญ + ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง ์˜ˆ์‹œ

import "./styles.css";
import styled, { createGlobalStyle } from "styled-components";

export default function App() {
  return (
    <>
      <GlobalStyle />
      <Button1 color="black">
        Practice!
      </Button1>
    </>
  );
}

const GlobalStyle = createGlobalStyle`
	button {
	  padding : 5px;
      margin : 2px;
      border-radius : 5px;
	}
`;

const Button1 = styled.button`
  color: ${(props) => props.color || "white"};
  
  &:hover {
    background: purple;
    color: white;
  }
`;

๐Ÿ”ฅCSS vs SASS vs BEM vs Styled-Component

โœš ์ฐธ๊ณ 

ํŠน์ง•์žฅ์ ๋‹จ์ 
CSS๊ธฐ๋ณธ์ ์ธ ์Šคํƒ€์ผ๋ง ๊ธฐ๋ฒ•์ผ๊ด€๋œ ํŒจํ„ด์„ ๊ฐ–๊ธฐ ์–ด๋ ค์›€, !important์˜ ๋‚จ์šฉ
SASSํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ๋ฒ•๋ก ์„ ๋„์ž…ํ•˜์—ฌ, ์ปดํŒŒ์ผ๋œ CSS๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š” ์ „์ฒ˜๋ฆฌ๊ธฐ๋ณ€์ˆ˜/ํ•จ์ˆ˜/์ƒ์† ๊ฐœ๋…์„ ํ™œ์šฉํ•˜์—ฌ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ, CSS์˜ ๊ตฌ์กฐํ™”์ „์ฒ˜๋ฆฌ ๊ณผ์ •์ด ํ•„์š”, ๋””๋ฒ„๊น…์˜ ์–ด๋ ค์›€์ด ์žˆ์Œ. ์ปดํŒŒ์ผํ•œ CSS ํŒŒ์ผ์ด ๊ฑฐ๋Œ€ํ•ด์ง
BEMCSS ํด๋ž˜์Šค๋ช… ์ž‘์„ฑ์— ์ผ๊ด€๋œ ํŒจํ„ด์„ ๊ฐ•์ œํ•˜๋Š” ๋ฐฉ๋ฒ•๋ก ๋„ค์ด๋ฐ์œผ๋กœ ๋ฌธ์ œ ํ•ด๊ฒฐ, ์ „์ฒ˜๋ฆฌ ๊ณผ์ • ๋ถˆํ•„์š”์„ ํƒ์ž์˜ ์ด๋ฆ„์ด ์žฅํ™ฉํ•˜๊ณ , ํด๋ž˜์Šค ๋ชฉ๋ก์ด ๋„ˆ๋ฌด ๋งŽ์•„์ง
Styled-Component์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ CSS๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌCSS๋ฅผ ์ปดํฌ๋„ŒํŠธ ์•ˆ์œผ๋กœ ์บก์Šํ™”, ๋„ค์ด๋ฐ์ด๋‚˜ ์ตœ์ ํ™”๋ฅผ ์‹ ๊ฒฝ ์“ธ ํ•„์š”๊ฐ€ ์—†์Œ๋น ๋ฅธ ํŽ˜์ด์ง€ ๋กœ๋“œ์— ๋ถˆ๋ฆฌํ•จ

๐Ÿ‘‰ styled-components ๊ณต์‹ ๋ฌธ์„œ ๋ณด๋Ÿฌ๊ฐ€๊ธฐ

profile
๐Ÿพ

0๊ฐœ์˜ ๋Œ“๊ธ€