[React] 리액트를 다루는 기술 - 9장 컴포넌트 스타일링

Lynn·2021년 8월 31일
0

React

목록 보기
12/17
post-thumbnail

프로젝트에 자동으로 만들어지는 src/App.js, src/App.css를 가지고 다양한 컴포넌트 스타일링을 살펴보자.

  • App.js
import React, { Component } from ‘react‘;
import logo from./logo.svg‘;
import./App.css‘;

class App extends Component {
  render() {
    return (
      <div className=“App“>
        <header className=“App-header“>
          <img src={logo} className=“App-logo“ alt=“logo“ />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className=“App-link“
            href=“https://reactjs.org“
            target=“_blank“
            rel=“noopener noreferrer“
          >
            Learn React
          </a>
        </header>
      </div>
    );
  }
}

export default App;
  • App.css
.App {
  text-align: center;
}
 
.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 40vmin;
}
 
.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}
 
.App-link {
  color: #61dafb;
}
 
@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

가장 흔한 방식, 일반 CSS

CSS를 작성할 때 가장 중요한 점은 CSS 클래스를 중복되지 않게 만드는 것이다.

  • 명명 규칙
    자동으로 생성되는 App.css를 살펴보면 클래스 이름에 컴포넌트 이름이 포함되어 있는 걸 볼 수 있다 (ex: App-header). 또 BEM 네이밍이라는 CSS 방법론도 있는데, 해당 클래스가 어디에서 어떤 용도로 사용되는지 명확하게 작성하는 방식이다 (ex: .card__title-primary).

  • CSS Selector
    CSS 클래스가 특정 클래스 내부에 있는 경우에만 스타일을 적용할 수 있게 하는 기능이다. 예를 들어 .App 안에 들어 있는 .logo에 스타일을 적용하고 싶다면 클래스명을 좀 더 간단히 다음과 같이 변경할 수 있다.

.App {
  text-align: center;
}


/.App 안에 들어 있는 .logo/
.App .logo {
  animation: App-logo-spin infinite 20s linear;
  height: 40vmin;
}

/* .App 안에 들어 있는 header 
   header 클래스가 아닌 header 태그 자체에
   스타일을 적용하기 때문에 .이 생략 */
.App header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

/* .App 안에 들어 있는 a 태그 */
.App a {
  color: #61dafb;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

이에 맞춰 컴포넌트의 JSX 부분도 수정해 준다.

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
 
class App extends Component {
  render() {
    return (
      <div className="App">
        <header>
          <img src={logo} className="logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header>
      </div>
    );
  }
}
 
export default App;

이런 식으로 컴포넌트의 최상위 html 요소에는 컴포넌트의 이름으로 클래스 이름을 짓고(.App), 그 내부에서는 소문자를 입력하거나(.logo), header 같은 태그를 사용하여 클래스 이름이 불필요한 경우에는 아예 생략할 수도 있다.


확장된 CSS 문법, Sass

Sass(Syntactically Awesome Style Sheets, 문법적으로 쩌는 스타일시트 ㅋㅋ)는 CSS 전처리기로 복잡한 작업을 쉽게 할 수 있게 해 준다. 또한 스타일 코드의 재활용성과 코드의 가독성을 높여 유지보수를 쉽게 만든다.

Sass에서는 .sass.scss 두 확장자를 지원하는데 아래를 보면 중괄호와 세미콜론 사용 부분에서 조금 차이가 있는 걸 알 수 있다. 하지만 보통 .scss 문법이 더 자주 사용됨

.sass

$font-stack: Helvetica, sans-serif
$primary-color: #333
body
  font: 100% $font-stack
  color: $primary-color

.scss

$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
  font: 100% $font-stack;
  color: $primary-color;
}
  • SassComponent.scss
// 변수 사용하기
$red: #fa5252;
$orange: #fd7e14;
$yellow: #fcc419;
$green: #40c057;
$blue: #339af0;
$indigo: #5c7cfa;
$violet: #7950f2;
// 믹스인 만들기(재사용되는 스타일 블록을 함수처럼 사용할 수 있음)
@mixin square($size) {
  $calculated: 32px * $size;
  width: $calculated;
  height: $calculated;
}


.SassComponent {
  display: flex;
  .box { // 일반 CSS에서는 .SassComponent .box와 마찬가지
    background: red; 
    cursor: pointer;
    transition: all 0.3s ease-in;
    &.red {
      // .red 클래스가 .box와 함께 사용되었을 때
      background: $red;
      @include square(1);
    }
    &.orange {
      background: $orange;
      @include square(2);
    }
    &.yellow {
      background: $yellow;
      @include square(3);
    }
    &.green {
      background: $green;
      @include square(4);
    }
    &.blue {
      background: $blue;
      @include square(5);
    }
    &.indigo {
      background: $indigo;
      @include square(6);
    }
    &.violet {
      background: $violet;
      @include square(7);
    }
    &:hover {
      // .box에 마우스를 올렸을 때
      background: black;
    }
  }
}
  • SassComponent.js
import React from ‘react‘;
import./SassComponent.scss‘;


const SassComponent = () => {
  return (
    <div className=“SassComponent“>
      <div className=“box red“ />
      <div className=“box orange“ />
      <div className=“box yellow“ />
      <div className=“box green“ />
      <div className=“box blue“ />
      <div className=“box indigo“ />
      <div className=“box violet“ />
    </div>
  );
};
export default SassComponent;


순서대로 빨주노초파남보!


utils 함수 분리하기

여러 파일에서 공통으로 사용될 수 있는 Sass 변수 및 믹스인은 다른 파일로 따로 분리하여 작성한 뒤 필요한 곳에서 쉽게 불러와 사용할 수 있다.
src 디렉토리에 styles라는 디렉토리를 생성하고, 그 안에 utils.scss 파일을 만들어보자. 그리고 기존 SassComponent.scss에 작성했던 변수와 믹스인을 utils.scss로 이동시키고, 이들이 필요한 곳에서 @import 해준다.

  • src/styles/utils.scss
// 변수 사용하기
$red: #fa5252;
$orange: #fd7e14;
$yellow: #fcc419;
$green: #40c057;
$blue: #339af0;
$indigo: #5c7cfa;
$violet: #7950f2;


// 믹스인 만들기(재사용되는 스타일 블록을 함수처럼 사용할 수 있음)
@mixin square($size) {
  $calculated: 32px * $size;
  width: $calculated;
  height: $calculated;
}
  • SassComponent.scss
@import './styles/utils';
.SassComponent {
  display: flex;
  .box {
    background: red; // 일반 CSS에서는 .SassComponent .box와 마찬가지
    cursor: pointer;
    transition: all 0.3s ease-in;
    (...)
  }
}

CSS Module

CSS Module은 CSS를 불러와서 사용할 때 클래스 이름을 고유한 값, 즉 "파일 이름_클래스 이름__해시값" 형태로 자동으로 만들어서 컴포넌트 스타일 클래스 이름이 중첩되는 현상을 방지해 주는 기술이다.
CSSModule.module.css라는 파일을 src 디렉터리에 생성하여 다음과 같이 한번 작성해 보자.

/* 자동으로 고유해질 것이므로 흔히 사용되는 단어를 클래스 이름으로 마음대로 사용 가능 */

.wrapper {
  background: black;
  padding: 1rem;
  color: white;
  font-size: 2rem;
}

/* 글로벌 CSS를 작성하고 싶다면 */

:global .something {
  font-weight: 800;
  color: aqua;
}

위 파일을 직접 불러온 컴포넌트 내부에서만 작동하기 때문에 클래스 이름을 지을 때 고유성에 대해 고민하지 않아도 된다.
다 작성했다면 위 CSS Module을 사용하는 리액트 컴포넌트도 작성해 봅시다!

  • CSSModule.js
import React from ‘react‘;
import styles from./CSSModule.module.css‘;
const CSSModule = () => {
  return (
    <div className={styles.wrapper}>
      안녕하세요, 저는 <span className=“something“>CSS Module!</span>
    </div>
  );
};


export default CSSModule;

CSS Module이 적용된 스타일 파일을 import 하면 객체를 하나 전달받게 되는데, CSS Module에서 사용한 클래스 이름과 해당 이름을 고유화한 값이 키-값 형태로 들어 있다. 예를 들어 위 코드에서 console.log(styles)를 한다면 다음과 같은 결과가 나타납니다.

{ wrapper: “CSSModule_wrapper__1SbdQ” }

이 고유한 클래스 이름을 사용하려면 클래스를 적용하고 싶은 JSX 엘리먼트에 className = {styles.클래스 이름} 형태로 전달해 주면 된다. :global을 사용하여 전역적으로 선언한 클래스의 경우 평상시 해 왔던 것처럼 그냥 문자열로 넣어 준다.


JS 파일에 내장된 스타일, styled-components

자바스크립트 파일 안에 스타일을 선언하는 방식으로, 스타일 파일을 따로 만들지 않아도 된다는 큰 이점이 있다. 'CSS-in-JS'라고 부르며 npm이나 yarn으로 설치가 필요하다.

npm install --save styled-components
  • StyledComponent.js
import React from ‘react‘;
import styled, { css } from ‘styled-components‘;

const Box = styled.div`
  /* props로 넣어 준 값을 직접 전달해 줄 수 있다. */
  background: ${props => props.color || 'blue'};
  padding: 1rem;
  display: flex;
`;

const Button = styled.button`
  background: white;
  color: black;
  border-radius: 4px;
  padding: 0.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  font-size: 1rem;
  font-weight: 600;

  /* & 문자를 사용하여 Sass처럼 자기 자신 선택 가능 */
  &:hover {
    background: rgba(255, 255, 255, 0.9);
  }

  /* 다음 코드는 inverted 값이 true일 때 특정 스타일을 부여해 준다. */
  ${props =>
    props.inverted &&
    css`
      background: none;
      border: 2px solid white;
      color: white;
      &:hover {
        background: white;
        color: black;
      }
    `};
  & + button {
    margin-left: 1rem;
  }
`;

const StyledComponent = () => (
  <Box color=“black“>
    <Button>안녕하세요</Button>
    <Button inverted={true}>테두리만</Button>
  </Box>
);

export default StyledComponent;
profile
wanderlust

0개의 댓글

관련 채용 정보