본문 바로가기

React

20210729 React style 01: REACT CSS(classnames 라이브러리), SCSS(open-color, include-media 라이브러리), CSS Module, Styled-components

React Style 01



📄 주요 사항 정리


리액트의 스타일 방식은 여러가지가 존재 한다.


  • 일반적인 CSS
  • Sass
  • CSS Module
  • styled-components

CSS


작은 규모의 프로젝트의 경우에는 기존의 CSS 스타일링을 고수하여 사용하여도 좋음

  • CSS 클래스를 중복되지 않게 만드는 것이 제일 중요함

  • REACT에서 추천하는 형태 : 컴포넌트 이름-클래스 형태
  • BEM : Block__Element--Modifier 형태
    • Block : 큰 독립적인 형태 (화면을 구성하는 component 단위의 느낌)
    • Element : Block을 구성하는 작은 단위
    • Modifier : Block 또는 Element의 속성(특성, 외관 상태를 변화시키는 것)을 담당함
  • CSS Selector(CSS 선택자) : 선택자의 위계 질서를 통해서 특정 부분을 구체적으로 가르켜 스타일링 하는 방식
    • 컴포넌트 최상위 HTML 요소 : 컴포넌트의 이름으로 클래스 이름 설정 (파스칼 케이스)
    • 컴포넌트 내부 요소 : 태그이름, 내부 요소의 이름으로 클래스 이름 설정 (소문자)



Sass


  • Sass(Syntactically Awesome Style Sheets)
    • CSS 전처리기
    • 코드 재활용성 향상
    • 코드 가독성 향상
    • 유지 보수 향상

  • CRA v2 버전 부터 React에 별도 추가 설정 없이 Sass 사용 가능
  • .scss , .sass 두 가지 확장자 지원
  • Component 별로 SCSS를 만들어 해당 Component에 import하여 사용함
  • utils.scss : utils 함수 SCSS를 만들어서 Sass 변수 및 믹스인만 따로 관리하여 다른 곳에서 @import 하여 사용
  • sass-loader 설정 커스터 마이징
    • cra에서 npm run eject 해서 사용 함(eject 하기전 최초 commit 이있어야 eject가 허용 됨)
    • eject 후 webpack.config.js의 sassRegex 설정 부분으로 가기
      • sass 파일내의 @import root 경로 변경
      • sass 파일 생성시 기본 코드 설정
// webpack.config.js
{
  test: sassRegex,
  exclude: sassModuleRegex,
  use: getStyleLoaders(
    {
      importLoaders: 3,
      sourceMap: isEnvProduction
        ? shouldUseSourceMap
        : isEnvDevelopment,
    }
  ).concat({
    loader: require.resolve('sass-loader'),
    options: {
      sassOptions: {
        includePaths: [paths.src + '/styles']
        // sass 파일의 import root 경로로 styles 폴더를 설정 함
      },
      sourceMap: isEnvProduction
        ? shouldUseSourceMap
        : isEnvDevelopment,
      prependData: `@import 'utils';`
      // sass 파일 생성시 보이진 않지만 기본적인 코드 작성 (주로, 기본 import 설정이 들어가는 듯 함)
    }
  }),
  sideEffects: true,
},

open-color, include-media 라이브러리 (Sass 용)


  • open-color : 여러가지 색깔을 단계적으로 나누어 고른 색을 사용할 수 있게 해주는 색상 팔레트
  • include-media : 반응형 디자인을 쉽게 만들어주는 라이브러리 (특정 필셀 또는, phone, tablet, pc 등의 사이즈를 조건으로 스타일을 지정해 줄 수 있음)
  • npm i open-color include-media
  • sass 파일에 라이브러리를 @import하여 사용하는 경우 경로를 모두 작성(node_modules/library/...)할 필요 없이 ~로 시작 하면 편하게 @import 할 수 있음
@import "~include-media/dist/include-media";
@import "~open-color/open-color";



CSS Module


  • 파일이름_클래스이름__해시값 형태로 자동으로 만들어서 컴포넌트 스타일 클래스 이름이 중첩되는 현상 방지 (고유성 고민 필요 없음)
  • CRA v2 부터 따로 설정 없이 가능 함
/*Component.module.css*/
.wrapper {
  background: black;
  color: white;
}
.inverted {
  color: black;
  background: white;
}
:global {
  /*CSS module에서 글로벌 CSS를 하는 경우*/
  .something {
  }
}
import React from "react";
import styles from "./Component.module.css";
const Component = () => {
  return <div className={`${styles.wrapper} ${styles.inverted}`}>Element</div>;
};

export default Component;

/* 
console.log(styles)
{
  wrapper: "Component_wrapper__1SbdQ",
  inverted: "Compnent_inverted_2BdiK"
}
 */

classnames 라이브러리


  • CSS 클래스를 조건부로 설정할 때 유용함
  • npm i classnames
  • trusy 한 값의 이름을 className으로 그대로 들어가게 하고 falsy 값의 이름은 들어가지 않게 함
  • 객체를 제공하는 경우 해당 프로퍼티의 값이 trusy 한 경우의 프로퍼티 이름을 className으로 제공함(여러개도 가능함)
import classNames from "classnames";
classNames("one", { two: true, three: false, four: true }); // one two four

  • CSS Module과 같이 사용하는 경우, bind를 사용하여 css module과 classnames를 연결하여 편하게 사용할 수 있음
import classNames from "classnames";
import styles from "./Component.modules.css";

const cx = classNames.bind(styles);

cx("wrapper", "inverted");
// cx 함수를 기존에 className을 사용하듯이 사용하면 되고, 굳이 `styles.프로퍼티`로 넣을 필요 없음



styled-components

  • JS 파일 안에 스타일을 선언하는 방식인 CSS-in-JS 방식 중에 하나가 styled-components 임
  • JS 단의 props를 style에서 참조 할수 있음
  • JS의 문법도 사용이 가능해서 여러 조건부 스타일링이 가능 함
  • Tagged 템플릿 리터럴 사용
    • 일반 템플릿과 다르게 함수 뒤에 ` ` 백틱을 바로 붙여 함수의 인자를 제공함
    • 일반 템플릿과 다르게 템플릿(${...}) 안에 있는 코드를 평가하지 않고 온전히 추출 함
  • vscode-styled-components vscode 익스텐션을 활용하면, 편집기에 Tagged 템플릿 리터럴 부분의 코드의 하이라이팅이 제공 됨
import styled, {css} from 'styled-components'

const Component = () => {
  // 컴포넌트 안에서 사용되는 Element 이름과 해당 Element 종류 설정
const MyInput = styled.input`
  background: gray;
`
// 컴포넌트 안에서 사용되는 Element 종류를 유동적으로 변경 가능함
const MyDiv = styled('div')`
  color: blue;
`
// 컴포넌트 자체를 스타일을 지정할 종류로서 지정 가능함
const Unknown = 'button'
const MyUnknown = styled(Unknown)`
  color: pink;
`
// 지정한 Element 자체의 Prop을 받아서 유동적으로 style 값 변경 가능 (prop 참조가 가능해 짐)
const PropDiv = styled.div`
background: ${props => props.color || 'blue'}
`
// 자신 컴포넌트를 참조할 수 있는 &를 사용 할 수 있음 style 값이 아니라 prop을 받아 조건부 style을 구현할 수 있음
// 여러줄의 스타일 코드를 유동적으로 추가시에는 css를 받아와 붙여 태그드 템플릿 구조로 만들어 주어야 함
const PropButton = styled.button`
  background: white;

  &:hover {
    background: gray;
  }

  ${props => props.inverted && css`
  background: yellow;
  `}

`
  return (
  <>
    <MyInput />
    <MyDiv />
    <MyUnknown/>
    <PropDiv color={"red"} />
    <PropButton inverted={true}/>
  )
}
  • styled-component의 반응형 디자인은 media 쿼리를 사용함 (@media())
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]}/ 16em) {
    ${css(...args)}
  }
  `;
  return acc;
},{})

const Box = styled.div`
${media.desktop`width: 768px;`}
${media.tablet`width: 100%`}
`