상세 컨텐츠

본문 제목

[리액트 스타터1] 9장. 컴포넌트 스타일링

22-23/22-23 리액트 스타터 1

by 2jo 2022. 12. 1. 10:00

본문

728x90

리액트에서는 다양한 방식으로 컴포넌트를 스타일링할 수 있습니다. 이번 장에서는 자주 사용하는 4가지 방식을 알아보도록 하겠습니다.

 


먼저 이번 예시에서는 create-react-app을 이용해 새로운 프로젝트를 만듭니다. styling-react 프로젝트를 만들고 열어주세요.

 

$ yarn create react-app styling-react
$ cd styling-react
$ yarn start

 

 

9.1 가장 흔한 방식, 일반 CSS

 

기존의 CSS 스타일링에 불편을 겪지 않고, 새로운 기술을 배우고 싶지 않다면 일반 CSS를 계속 사용해도 괜찮습니다. 실제로 소규모 프로젝트에서는 새로운 스타일링 시스템을 적용하는 것이 불필요할 수도 있습니다. 방금 만든 프로젝트에는 App.js 파일과 App.css 파일이 있습니다.

 

/* 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);
  }
}
/* 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;

 

이 방식은 일반 CSS방식입니다.를 작성할 때 가장 중요한 것은 CSS 클래스가 중복되지 않는 것입니다. 중복되지 않게 하는 방식 중 대표적으로 두 가지가 있는데, 이름을 특별한 규칙을 사용하여 짓는 것이고, 또 다른 하나는 CSS Selector를 활용하는 것입니다.

 

 

9.1.1 이름 짓는 규칙

App.css를 보면 클래스 이름을 [컴포넌트 이름-클래스] 형태로 지은 것을 알 수 있습니다. 예를 들면 ‘App-header’과 같은 형태입니다. 클래스 이름에 컴포넌트 이름을 포함시키면서 다른 컴포넌트에서 중복되는 것을 방지합니다. 그 외로는 BEM 네이밍 방식이 있으며, 해당 클래스가 어디서 어떤 용도로 사용되는지 명확하게 작성하는 방식입니다. 예를 들면 ‘. card_title-primary’처럼 지을 수 있습니다.

 

 

9.1.2 CSS Selector

CSS SelectorCSS클래스가 특정 클래스 내부에 있는 경우에만 스타일을 적용할 수 있습니다. 최상위 html 요소에는 컴포넌트의 이름으로 클래스 이름을 짓습니다.

 

/* 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 a {
  color: #61dafb;
}


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

 

수정 전의 코드와 비교해봅시다. 

 

.App-logo {…}      .App .logo {…}

.App-header {…}   .App header {…}

.App-link {...}     .App a {…}

 

.App header {...}의 경우 header 클래스가 아닌 header 태그 자체에 스타일을 적용하기 때문에 .이 생략되었습니다.

 

/* 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>
          <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;

 

CSS에서 작성한 내용을 JSX에서 소문자를 입력하거나 태그를 사용하여 클래스 이름이 불필요한 경우에 아예 생략할 수도 있습니다.

 

 

 

9.2 Sass 사용하기

 

Sass는 CSS 전처리기로 3가지 장점을 가집니다.

 

1.     CSS 전처리기로 복잡한 작업을 쉽게 할 수 있도록 합니다.

2.     스타일 코드의 재활용성을 높여줍니다.

3.     코드의 가독성을 높여 유지 보수를 더욱 쉽게 합니다.

 

 create-react-app 구버전에서는 Sass를 사용하기 위해 추가 작업이 필요했는데, v2 버전부터는 별도의 작업 없이 바로 사용할 수 있습니다.

 

Sass에서는 두 가지 확장자 .sass.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;
}

 

.sass는 중괄호와 세미콜론을 사용하지 않습니다. 반면 .scss는 기존 CSS와 비슷한 방식입니다.

두 방식 중에 .scss가 더 자주 사용되므로, 이 방식에 대해 알아보도록 하겠습니다.

 

실습을 하기 위해서는 SassCSS로 변환해주는 node-sass라는 라이브러리를 설치해야 합니다. 서버를 구동 중인 Git bash말고, 창을 하나 더 띄워 다음 명령어를 실행하세요.

 

$yarn add node-sass

 

설치가 됐다면, 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도 만들어 App 컴포넌트에 띄워보세요.

서버를 재구동하면, 아래와 같은 화면이 적용됩니다.

 

 

9.2.1 utils 함수 분리하기

여러 파일에서 사용될 수 있는 Sass 변수 및 믹스인은 다른 파일로 분리하여 작성한 뒤, 필요한 곳에서 쉽게 불러와 사용할 수 있습니다. 바로 utils 함수를 이용하는 것인데요, 위의 예제를 분리하기 위해 3가지 단계가 필요합니다.

 

1. src 디렉터리에 styles 디렉터리를 생성하고, 그 안에 utils.scss 파일을 만드세요

2. 위의 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;
}

 

3. SassComponent.scss에서 @import를 이용해 utils.scss파일을 불러오세요.

@import './styles/utils';
.SassComponent {
  display: flex;
  .box {
    background: red; 
    cursor: pointer;
    transition: all 0.3s ease-in;
    (...)
  }
}

 

그렇다면 분리되기 전과 같은 결과가 나타납니다. 

 

 

9.2.2 sass-loader 설정 커스터마이징하기

반드시 필요한 설정은 아니지만, 설정해두면 편리합니다. @import 구문에서 참조할 파일의 경로명이 길어진다면 불편하겠죠? 이 문제점을 sass-loader의 설정을 커스터마이징하여 해결할 수 있습니다.

 

create-react-app로 만든 프로젝트는 프로그램 구조를 간단히 하기 위해 세부 설정이 모두 숨겨져 있습니다. 따라서 커스터마이징하기 위해 프로젝트 디렉터리에서 yarn eject 명령어를 통해 세부 설정을 밖으로 꺼내 주어야 합니다.

 

먼저, yarn eject Git에 커밋되지 않은 변화가 있다면 진행되지 않으니, 커밋해줍니다. VS Code 좌측의 메뉴 중 Git UI를 이용하거나, Git bash에 다음과 같은 명령어를 사용하여 커밋할 수 있습니다.

 

$ git add .
$ git commit -m’Commit before yarn eject’
$ yarn eject
$ react-scripts eject

 

커밋했다면, 프로젝트 디렉터리에 config라는 디렉터리가 생성됩니다. 그 디렉터리에 있는 webpack.config.js를 열어보세요. 그 파일에서 “sassRegex”라는 키워드를 찾아보세요. 아래와 같은 코드에 존재할 것입니다.

 

{
  test: sassRegex,
  exclude: sassModuleRegex,
  use: getStyleLoaders(
    {
      importLoaders: 2,
      sourceMap: isEnvProduction && shouldUseSourceMap,
    },
    ‘sass-loader‘
  ),
  sideEffects: true,
},

 

여기에 있는 use:에 있는 ‘sass-loder’ 부분을 지우고, 뒷부분에 concat을 통해 커스터마이징된 sass-loader 설정을 넣어주세요.

 

{
  test: sassRegex,
  exclude: sassModuleRegex,
  use: getStyleLoaders({
    importLoaders: 2,
    sourceMap: isEnvProduction && shouldUseSourceMap
}).concat({
    loader: require.resolve(‘sass-loader‘),
    options: {
      includePaths: [paths.appSrc + ‘/styles‘],
      sourceMap: isEnvProduction && shouldUseSourceMap,}
}),
sideEffects: true
},

 

설정 파일은 저장한 후, 서버를 재구동하세요. 설정이 완료되었다면 이제 utils.scss 파일을 불러올 때 상대 경로가 아닌 절대 경로를 사용하여 불러올 수 있습니다.

 

그럼 @import './styles/utils.scss'; 가 아닌 @import ‘utils.scss’;로 간단하게 불러올 수 있습니다.

 

 

만약 매번 import하는 방법이 귀찮다면, sass-loaderdata옵션을 설정할 수 있습니다. 이 옵션을 통해 Sass 파일을 불러올 때마다 코드의 맨 윗부분에 특정 코드를 포함합니다. Webpack.config.js를 열어 data필드를 수정해보세요.

 

{
  test: sassRegex,
  exclude: sassModuleRegex,
  use: getStyleLoaders({
    importLoaders: 2,
    sourceMap: isEnvProduction && shouldUseSourceMap
  }).concat({
    loader: require.resolve('sass-loader'),
    options: {
      includePaths: [paths.appSrc + '/styles'],
      sourceMap: isEnvProduction && shouldUseSourceMap,
      data: `@import 'utils';`
    }
  }),
  sideEffects: true
},

 

작성 후, 서버를 재구동하고 나면 이제 import 구문을 쓰지 않아도 정상 작동합니다.

 

 

 

 

9.2.3 node_modules에서 라이브러리 불러오기

Sass의 장점은 라이브러리를 쉽게 불러와 사용할 수 있다는 것입니다.  

yarn을 통해 설치한 라이브러리를 사용하는 기본 방식은 상대 경로를 이용해 node_modules까지 들어가서 불러오는 것입니다.

 

@import ‘../../../node_modules/library/styles‘

 

너무 길지 않나요? 물결 문자를 이용하면 더 간략하게 표현할 수 있습니다.

 

@import ‘~library/styles‘;

 

Sass 라이브러리를 불러올 때 node_modules 내부 라이브러리 경로 안에 들어있는 scss 파일을 불러와야 합니다. 보통 scss 파일 경로를 따로 알려주지 않는 경우가 많아 직접 들어가 확인해야 합니다. 

 

 

 

 

 

9.3 CSS Module

CSS ModuleCSS를 불러와 사용할 때 고유한 이름으로 자동 생성하여 컴포넌트 스타일 클래스 이름이 중첩되는 현상을 방지하는 기술입니다. 고유한 이름의 형태는 [파일명]_[클래스명]_[해시값] 입니다. CSS Module을 사용하기 위해 구버전에서는 웹팩에서 별도의 설정이 필요했지만 v2부터 .module.css 확장자로 파일을 저장하기만 하면 됩니다.

 

Src 디렉터리 아래 CSSModule.module.css 파일을 만들어 아래와 같이 작성해 보세요.

 

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



.inverted {
  color: black;
  background: white;
  border: 1px solid black;
}



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

 

CSS Module을 이용하면 클래스 이름을 지을 때 고유성에 관해 걱정할 필요 없습니다. 흔한 이름을 지어도 이 클래스를 불러온 컴포넌트 내부에서만 작동하기 때문입니다. 만약 전역에서 사용되는 클래스를 만들고 싶다면 :global를 앞에 입력하면 됩니다. 위의 예시에서는 something이 전역 함수입니다.

 

이제 CSSModule.js를 작성하여 CSSMoudle.module.css를 불러와 스타일을 적용합니다.

 

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;

 

두 번째 줄에서 import ‘./CSSModule.module.css’를 불러옵니다. 이것을 불러오면 CSS Moule에서 사용한 클래스 이름과 해당 이름을 고유화한 값이 키-값 형태로 들어오는데, 이것을 styles 객체가 받고 있습니다. 따라서 console.log.(styles)를 한다면, 다음과 같은 결과가 나타납니다.

 

{ wrapper: “CSSModule_wrapper__1SbdQ” }

 

CSS Module의 클래스를 사용하고 싶다면, 적용하고 싶은 JSX 엘리먼트에 className={styles.[클래스명]} 형태로 전달합니다. 만약 전역 변수라면 className=”클래스명으로 전달할 수 있습니다.

 

작성한 CSSModule.jsApp.js에서 렌더링을 하면 다음과 같은 결과를 볼 수 있습니다..

 

 

만약 두 개 이상의 클래스를 적용하고 싶다면 어떻게 해야 할까요?

 

import React from 'react';
import styles from './CSSModule.module.css';
 
const CSSModule = () => {
  return (
    <div className={`${styles.wrapper} ${styles.inverted}`}>
      안녕하세요, 저는 <span className="something">CSS Module!</span>
    </div>
  );
};
 
export default CSSModule;

 

중괄호({})와 백 틱(`) 안에 $를 붙여 클래스명을 작성하면 됩니다. 이 문법을 ES6 문법 템플릿 리터럴이라고 부르며, 이 문법을 이용해 자바 스크립트 레퍼런스를 쉽게 넣을 수 있습니다.

 

 

템플릿 리터럴 문법을 사용하고 싶지 않다면 다음과 같이 작성할 수 있습니다.

className={[styles.wrapper, styles.inverted].join(‘ ‘)}

 

 

 

9.3.1 classnames

ClassnamesCSS 클래스를 조건부로 설정할 때나 CSS Module을 사용할 때 유용한 라이브러리입니다. Git bash에서 해당 라이브러리를 설치하세요.

 

$ yarn add classnames

 

간략적인 classnames 사용 방법을 봐봅시다.

 

import classNames from ‘classnames’;


classNames(‘one’, ‘two’); // = ‘one two‘
classNames(‘one’, { two: true }); // = ‘one two‘
classNames(‘one’, { two: false }); // = ‘one‘
classNames(‘one’, [‘two’, ‘three’]); // = ‘one two three‘



const myClass = ‘hello’;
classNames(‘one’, myClass, { myCondition: true }); // = ‘one hello myCondition‘

 

importclassnames를 불러와 classNames() 안에 여러 가지 파리 미터를 조합하여 CSS 클래스를 설정할 수 있습니다.

 

const MyComponent = ({ highlighted, theme }) => (
  <div className={`MyComponent ${theme} ${highlighted ? 'highlighted' : ''}`}>
    Hello
  </div>
);

 

Highlighted 값이 true highlighted 클래스가 적용되고, false면 적용되지 않는 예시입니다. 이 코드는 작성하기 복잡해 보이죠?를 이용해 간단히 표현할 수 있습니다.

 

const MyComponent = ({ highlighted, theme }) => (
  <div className={classNames('MyComponent', { highlighted }, theme)}>Hello</div>
);

 

또한, CSS Module과 함께 사용할 수 있습니다. classnames내장 함수 bind와 함께 사용하면 styles.[클래스이름] 형태를 사용하지 않아도 됩니다.

 

import React from 'react';
import classNames from 'classnames/bind';
import styles from './CSSModule.module.css';
 
const cx = classNames.bind(styles); // 미리 styles에서 클래스를 받아 오도록 설정하고
 
const CSSModule = () => {
return (
  <div className={cx('wrapper', 'inverted')}>
    안녕하세요, 저는 <span className="something">CSS Module!</span>
    </div>
);
};
 
export default CSSModule;

 

사전에 미리 styles에서 받아온 후 사용하게 끔 설정하고 cx(‘클래스 이름’, ‘클래스 이름 2’)형태로 사용할 수 있습니다.

 

 

 

9.3.2 Sass와 함께 사용하기

Sass를 사용할 때 파일 이름 뒤에 .module.scss 확장자를 붙이면 바로 CSS Module을 사용할 수 있습니다. CSSModule.module.cssCSSModule.module.scss로 바꾸어 보세요.

 

.wrapper {
  background: black;
  padding: 1rem;
  color: white;
  font-size: 2rem;
  &.inverted {
    color: black;
    background: white;
    border: 1px solid black;
  }
}
 

:global {

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

 

그래고 CSSModule.js에서 import문을 바꾸어보세요.

 

import styles from './CSSModule.module.scss';

 

같은 화면이 나타난 것을 볼 수 있습니다.

 

 

 

 

9.3.3 CSS Module이 아닌 파일에서 사용하기

:local 을 붙여주면 CSS Module이 아닌 파일에서도 사용할 수 있습니다.

 

:local .wrapper {
/* 스타일 /
}
:local {
.wrapper {
  / 스타일 */
}
}

 

 

 

9.4 styled-components

‘CSS-in-JS’는 이름에서 알 수 있듯, 자바스크립트 파일 안에 스타일을 선언하는 방식입니다.  

이와 관련된 다양한 라이브러리는 https://github.com/MicheleBertoli/css-in-js에서 확인할 수 있습니다.

 

그중 개발자들이 가장 선호하는 styled-components에 대해 알아보겠습니다. Git bash에서 설치해주세요.

 

$ yarn add styled-components

 

이제 작성해봅시다. styled-components는 자바스크립트 파일 하나에 스타일까지 작성할 수 있기 때문에 .css 또는 .scss 확장자를 가진 스타일 파일을 따로 만들지 않아도 됩니다. 이제 작성해봅시다. Src 디렉터리에 styledComponent.js 파일을 만들어 다음 코드를 작성해주세요.

 

import React from ‘react‘;
import styled, { css } from ‘styled-components‘;


const Box=styled.div`
  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;


  &:hover {
    background: rgba(255, 255, 255, 0.9);
  }



  ${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;

 

그리고 App.js 에서 렌더링 해보세요

그렇다면 아래 사진과 같이 두 개의 버튼이 나옵니다.

 

 

Styled-components와 일반 classNames를 사용하는 css/Sass를 비교했을 때 가장 큰 장점은 props 값으로 전달해주는 값을 쉽게 스타일에 적용할 수 있다는 것입니다.

 

 

9.4.1 Tagged 템플릿 리터럴

`을 사용한 위의 문법을 Tagged 템플릿 리터럴이라고 합니다. 일반 템플릿 리터럴과의 차이점은 템플릿 안에 자바스크립트 객체나 함수를 전달할 때 온전히 추출할 수 있다는 것입니다.

 

일반 템플릿 안에 객체나 함수를 넣으면 본 형태를 잃어버리게 됩니다.

 

Tagged 템플릿 리터럴을 이용한다면 온전히 추출할 수 있습니다. Styled-components는 이런 속성을 사용해 컴포넌트의 props를 스타일 쪽에서 쉽게 조회 가능합니다.

 

 

 

 

9.4.2 스타일링된 엘리먼트 만들기

스타일링된 엘리먼트를 만들어봅시다. 그렇기 위해서는 컴포넌트 상단에서 styled를 불러오고, styled.태그명 사용하여 구현합니다.

 

import styled from 'styled-components';
 
const MyComponent = styled.div`
  font-size: 2rem;
`;

 

Styled.div 뒤에 `를 사용해 tagged 템플릿 리터럴 문법을 넣어주면 해당 스타일이 적용된 div로 이루어진 리액트 컴포넌트가 생성됩니다. 그래서 나중에 <MyComponent>안녕</MyComponent>처럼 사용할 수 있습니다.

 

만약 사용해야 할 태그명이 유동적이거나 특정 컴포넌트 자체에 스타일링을 해주고 싶다면 다음과 같이 styled 함수의 인자로 전달하여 구현할 수 있습니다.

 

const MyInput = styled(‘input‘)`
	background: gray;
`

const StyledLink = styled(Link)`
	color: blue;
`

 

 

 

 

9.4.3 스타일에서 props 조회하기

Styled-components를 사용하면 스타일 쪽에서 컴포넌트에 전달된 props 값을 참조할 수 있습니다.

 

const Box = styled.div`
	background: ${props => props.color || 'blue'};
    padding: 1rem;
    dispaly: flex;
`;

 

이 전에 작성했던 StyledComonents.js의 Box 컴포넌트를 다시 보면, background 값에 props를 조회하여, 만약 props.color가 주어지지 않았다면 blue를 설정하도록 했습니다. 이렇게 만든 코드는 JSX에서 사용될 때 다음과 같이 color 값을 props로 넣어줄 수 있습니다.

 

<Box color=“black“>(…)</Box>

 

 

 

 

9.4.4 props에 따른 조건부 스타일링

일반 CSS 클래스를 사용해 조건부 스타일링을 해야 할 때는 className을 사용했습니다.

styled-components에서는 조건부 스타일링을 간단하게 props로 처리할 수 있습니다.

앞서 만든 Button 컴포넌트를 봐봅시다.

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;


  &:hover {
    background: rgba(255, 255, 255, 0.9);
  }


  ${props =>
    props.inverted &&
    css`
    background: none;
    border: 2px solid white;
    color: white

    &:hover {
        background: white;
        color: black;
      }
    `};

    & + button {
        margin-left: 1rem;
    }
    `;

 

Styled.button`의 바로 다음 줄에 여러 줄의 스타일 구문을 조건부로 설정하기 위해 css를 불러왔습니다. 그리고 ${props => … }에서 값이 &&연산자를 이용해 props.inverted 값이 true일 때 특정 스타일을 부여해주었습니다.

 

이 컴포넌트를 다음과 같이 props를 사용하여 서로 다른 스타일을 적용할 수 있습니다.

 

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

 

스타일 코드 여러 줄을 조건부로 설정하려면 CSS를 불러와야 한다고 했는데, 사용하지 않고 다음과 같이 사용해도 작동하기는 합니다.

 

${props =>
  props.inverted &&
  `
      background: none;
      border: 2px solid white;
      color: white;
      &:hover {
        background: white;
        color: black;
      }
    `};

 

그러나 다음과 같은 단점을 갖습니다.

 

1.     VS Code 확장 프로그램에서 신택스 하이라이팅이 제대로 이루어지지 않습니다.

2.     Tageed 템플릿 리터럴이 아니기 때문에 함수를 받아 사용하지 못해, 해당 부분에서 props값을 사용하지 못합니다.

 

따라서 props를 참조한다면 반드시 css로 감싸주어서 tagged 템플릿 리터럴을 사용해야 합니다.

 

 

 

 

9.4.5 반응형 디자인

이번에는 styled-components를 이용해 반응형 디자인을 만들어 봅시다. 브라우저의 가로 크기를 다르게 할 때마다, 다른 스타일이 적용되게 해 보겠습니다 Box 컴포넌트를 다음과 같이 수정해보세요.

const Box = styled.div`

  background: ${props => props.color || 'blue'};
  padding: 1rem;
  display: flex;

  width: 1024px;
  margin: 0 auto;
  @media (max-width: 1024px) {
    width: 768px;
  }
  @media (max-width: 768px) {
    width: 100%;
  }
`;

 

 

일반 CSS와 큰 차이가 없습니다. 만약 이 작업을 여러 컴포넌트에서 반복해야 한다면 어떨까요? 매번 작성하는 번거로움을 styled-components에서는 유틸 함수를 제공하여 간단히 수행할 수 있습니다.

 

import React from 'react';
import styled, { css } from 'styled-components';
 
const sizes = {
  desktop: 1024,
  tablet: 768
};


const media = Object.keys(sizes).reduce((acc, label) => {
acc[label] = (...args) => css`
  @media (max-width: ${sizes[label] / 16}em) {
    ${css(...args)};
    }
`;
 
return acc;
}, {});
 
const Box = styled.div`
background: ${props => props.color || 'blue'};
padding: 1rem;
display: flex;
width: 1024px;
margin: 0 auto;
${media.desktop`width: 768px;`}
${media.tablet`width: 100%;`};
`;

 

media를 선언하여 Box 컴포넌트가 간단해진 것을 볼 수 있습니다. 예제에서는 mediaStyledComponent.js에서 불러왔지만, 실제 사용에서는 아예 다른 파일에서 모듈화 한 후 불러와 사용할 수 있습니다.

 

 


 Quiz

 

1. CSS 클래스 이름이 중복되지 않게 하는 대표적인 방법 2가지는 (A)와 (B)이다.
2. Sass에는 두 가지 확장자가 있는데 (C)와 (D)이고, 그중 (D)가 더 많이 사용된다.
3. Sass 변수 및 믹스인을 다른 파일로 분리하여 필요한 곳에서 쉽게 재사용하기 위해서는 (E)를 이용한다.
4. CSS Module를 사용하기 위해서는 확장자를 (F)로 저장해야 한다.
5. 중괄호와 백 틱 안에 $를 붙여 클래스명을 작성하는 문법을 (G)라고 한다.
6. (H)는 props 값으로 전달해 주는 값을 쉽게 스타일에 적용할 수 있다.
7. 일반 템플릿 안에 객체나 함수를 넣으면 본 형태를 잃어버리게 되지만 (I) 안에 넣으면 온전히 추출할 수 있다.
8. classnames의 bind 함수를 이용하여 다음 코드를 간단히 하세요.

import React from 'react';
import styles from './CSSModule.module.css';
 
const CSSModule = () => {
  return (
    <div className={`${styles.highlight} ${styles.inverted}`}>
      저희는 코너의 <span className="something">리액트 스타터1팀입니다.</span>
    </div>
  );
};
 
export default CSSModule;


9. styled-components를 사용하여 조건부 스타일링을 하려 합니다. highlight 값이 true일 때 특정 스타일을 부여해 줍시다. props로 전달한 주석에 들어갈 문장을 작성하세요.

const Button = styled.button`
  background: red;
  color: black;
  border-radius: 6px;


  ${props =>
	// 여기에 들어갈 문장을 작성하세요
    // 여기에 들어갈 문장을 작성하세요
    background: none;
    border: 2px solid white;
    color: white

    &:hover {
        background: white;
        color: black;
      }
    `};
    
    `;

 


Corner React1

Editor: 이조

728x90

관련글 더보기