6. Global Style

keyword

  • Reset CSS

  • box-sizing ์†์„ฑ

  • word-break ์†์„ฑ

  • Theme

  • ThemeProvider

Reset CSS

styled-reset ํŽธํ•˜๋‹ค.
import { Reset } from "styled-reset";

export default function App() {
  return (
    <>
      <Reset />
      <GlobalStyle />
      <Greeting />
    </>
  );
}

๊ฐ„ํŽธํ•˜๊ฒŒ reset๊ณผ global style์„ ์žก์•„์ค„ ์ˆ˜ ์žˆ๋‹ค.

import { createGlobalStyle } from "styled-components";

const GlobalStyle = createGlobalStyle`
 html {
  box-sizing: border-box;
 }
 
 *,
 *::before,
 *::after {
  box-sizing: inherit;
 }
 
 html {
  font-size: 62.5%;
 }
 
 body {
  font-size: 1.6rem;
 }
 
 :lang(ko) {
  h1, h2, h3 {
   word-break: keep-all;
  }
 }
`;

export default GlobalStyle;

Theme

๋””์ž์ธ ์‹œ์Šคํ…œ์˜ ๊ทผ๊ฐ„์„ ๋งˆ๋ จํ•˜๋Š”๋ฐ ํ™œ์šฉ. ์ž˜ ์ •์˜ํ•˜๋ฉด ๋‹คํฌ ๋ชจ๋“œ ๋“ฑ์— ๋Œ€์‘ํ•˜๊ธฐ ์‰ฌ์›€. ๋ˆˆ์— ๋ณด์ด๋Š” ๋‹จํŽธ์ ์ธ ์ •๋ณด๋ฅผ ๋„˜์–ด์„œ, โ€œ์˜๋ฏธโ€์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ.

์ผ๋‹จ ๊ธฐ๋ณธ Theme๋ถ€ํ„ฐ ์ •์˜.

const defaultTheme = {
  colors: {
    background: "#FFF",
    text: "#000",
    primary: "#F00",
    secondary: "#00F",
  },
};

export default defaultTheme;
// App.tsx

import { ThemeProvider } from "styled-components";

import { Reset } from "styled-reset";

import defaultTheme from "./styles/defaultTheme";

import GlobalStyle from "./styles/GlobalStyle";

export default function App() {
  return (
    <ThemeProvider theme={defaultTheme}>
      <Reset />
      <GlobalStyle />
      <Greeting />
    </ThemeProvider>
  );
}

props.theme์„ ํ™œ์šฉ

import { createGlobalStyle } from "styled-components";

const GlobalStyle = createGlobalStyle`
 body {
  background: ${(props) => props.theme.colors.background};
  color: ${(props) => props.theme.colors.text};
 }
 
 a {
  color: ${(props) => props.theme.colors.text};
 }
 
 button,
 input,
 select,
 textarea {
  background: ${(props) => props.theme.colors.background};
  color: ${(props) => props.theme.colors.text};
 }
`;

export default GlobalStyle;

ํƒ€์ž… ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด styled.d.ts ํŒŒ์ผ ์ž‘์„ฑ.

import 'styled-components';

declare module 'styled-components' {
 export interface DefaultTheme extends Theme {
  colors: {
   background: string;
   text: string;
   primary: string;
   secondary: string;
  }
 }
}

ํƒ€์ž…์„ ์ •์˜ํ•˜๊ณ  defaultTheme์„ ๋งž์ถ”๋Š” ๊ฒŒ ๋ถˆํŽธํ•˜๋‹ˆ, ๋ฐ˜๋Œ€๋กœ defaultTheme์—์„œ ํƒ€์ž…์„ ์ถ”์ถœํ•˜์ž.

import defaultTheme from "./defaultTheme";

type Theme = typeof defaultTheme;

export default Theme;

ํƒ€์ž… ํŒŒ์ผ ๋ณ€๊ฒฝ

import 'styled-components';

import Theme from './Theme';

declare module 'styled-components' {
 export interface DefaultTheme extends Theme {}
}

๋‹ค๋ฅธ theme์„ ์ถ”๊ฐ€ํ•  ๋•Œ Theme ํƒ€์ž…์„ ์‚ฌ์šฉ. ํ•ญ์ƒ defaultTheme์— ๋จผ์ € ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€/์‚ญ์ œํ•˜๊ณ , ๋‚˜๋จธ์ง€๋ฅผ ์—ฌ๊ธฐ์— ๋งž์ถ”๋ฉด ๋œ๋‹ค.

์–ด๋–ค ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋น ์ง€๊ณ  ์ถ”๊ฐ€๋๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

import Theme from "./Theme";

const darkTheme: Theme = {
  colors: {
    background: "#000",
    text: "#FFF",
    primary: "#F00",
    secondary: "#00F",
  },
};

export default darkTheme;

์˜๋ฏธ๋ฅผ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋ƒˆ๋‹ค๋ฉด, ๋‹คํฌ ๋ชจ๋“œ๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒƒ๋„ ์‰ฝ๋‹ค.

import { useDarkMode } from "usehooks-ts";

import { ThemeProvider } from "styled-components";

import { Reset } from "styled-reset";

import defaultTheme from "./styles/defaultTheme";
import darkTheme from "./styles/darkTheme";

import GlobalStyle from "./styles/GlobalStyle";

import Greeting from "./components/Greeting";
import Button from "./components/Button";

export default function App() {
  const { isDarkMode, toggle } = useDarkMode();

  const theme = isDarkMode ? darkTheme : defaultTheme;

  return (
    <ThemeProvider theme={theme}>
      <Reset />
      <GlobalStyle />
      <Greeting />
      <Button onClick={toggle}>Dark Theme Toggle</Button>
    </ThemeProvider>
  );
}

Jest ํ…Œ์ŠคํŠธ ์ชฝ์—์„œ โ€œwindow.matchMediaโ€ ๋ฌธ์ œ ๋ฐœ์ƒ.

// src/setupTests.ts
Object.defineProperty(window, "matchMedia", {
  writable: true,
  value: jest.fn().mockImplementation((query) => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: jest.fn(), // deprecated
    removeListener: jest.fn(), // deprecated
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    dispatchEvent: jest.fn(),
  })),
});

Last updated