스타일 간섭을 방지하기 위한 styled components와 css module

jangws·2022년 5월 8일
2

React

목록 보기
5/8

0. 기존 css 스타일링 문제

컴포넌트 파일에 css 파일을 import하여 사용하는 기존의 일반적인 스타일링 방식은 스타일의 스코프가 해당 컴포넌트에만 국한되지 않는다. 큰 프로젝트에서 수많은 개발자들이 같은 코드에서 작업하고 있을 때, 동일한 css 선택자가 다른 의도임에도 중복해서 사용될 수도 있고, 이는 스타일에 잘못된 영향을 미칠 수 있다.

중복된 클래스명을 실수로 재사용하여 다른 컴포넌트 스타일에 영향을 주는 문제를 방지해야 한다.

이러한 문제를 피하기 위한 두 가지의 일반적인 접근 방법이 있다.

1. styled components

css in JS 개념에서 영감을 받은 다양한 라이브러리(styled components, emotion 등)가 있으나 그 중에서 가장 대중적인 styled components에 대해 알아보자.
styled components는 특정 스타일이 첨부된 컴포넌트를 구축할 수 있도록 도와주는 패키지이다. 이 스타일이 첨부되는 컴포넌트에만 영향을 미치고 다른 컴포넌트에는 전혀 영향을 미치지 않는다.

사용방법으로는 우선 styled components를 npm 설치하고, 사용하려는 컴포넌트에서 해당 패키지를 import하는 것이다.

styled.태그`` 과 같은 구문을 사용하는데, 여기서 백틱 관련 구문을 tagged template literal이라 한다. styled는 styled components에서 import하는 객체이고, 옆에 명시한 태그의 메소드에 접근할 수 있다. 간단히 말하면, 백틱 사이에 전달한 것이 결국 해당 태그 메소드로 전달된다는 것이다. 그리고 해당 태그 메소드가 새로운 태그 컴포넌트를 반환한다.
styled 패키지는 모든 html 요소에 대한 메소드를 갖고 있다.

styled components로 만들어진 해당 요소들의 class 명은 styled components 패키지에 의해 동적으로 생성된다. 모든 클래스는 고유한 이름을 갖게 되어, 다른 컴포넌트에 영향을 주지 않는다.

1-1. styled components에서 css pseudo 선택자 및 중첩 선택자

css pseudo 선택자는 styled components에서 지원하는 & 기호를 사용한다. &:hover 처럼 말이다. &은 생성된 컴포넌트를 참조한다. 만약 대상으로 하고 싶은 중첩 선택자가 있다면 & label&.invalid 과 같은 방식으로 하면 된다.

1-2. styled components에서 props 전달하기

styled components에 props를 추가하여 백틱 안에서 그 props를 사용할 수도 있다. 이를 통해 스타일을 동적으로 쉽게 바꿀 수 있다. 백틱 사이에서 $ 기호와 중괄호를 사용할 수 있다. 아래와 같이 서로 다른 세 가지 방식을 통해 동일한 효과를 낼 수 있다. 코드량이 줄어드는 case 2나 case 3가 더 나은 것 같다.

<CircleStyled invalid={true}/>
// case 1
const CircleStyled = styled.div`
  border-radius: 100%;
  background-color: ${({ invalid }) => invalid ? 'red' : 'black'};
`;
// case 2
const CircleStyled = styled.div(({ invalid ) => `
  border-radius: 100%;
  background-color: ${invalid ? 'red' : 'black'};
`);
// case 3
const CircleStyled = styled.div`
  ${({ invalid }) => `
    border-radius: 100%;
    background-color: ${invalid ? 'red' : 'black'};
  `}
`);

1-3. styled component에서 미디어 쿼리

스타일드 컴포넌트에서 반응형을 위해 미디어 쿼리 사용 방법도 간단하다. 아래와 같이 @media와 옆에 조건을 (min-width: 700px)처럼 적어주고 해당 중괄호 안에 조건 충족 시 적용될 스타일링을 적으면 된다.

const Button = styled.button`
	width: 100%;

	@media (min-width: 700px) {
		// 브라우저 폭이 700px 이상인 경우에 적용되는 코드
		width: auto;
	}
`

2. css module

css 모듈은 브라우저에서 코드가 실행되기 전에 코드의 변환이 필요하기 때문에, 그 기능을 지원하도록 설정된 프로젝트에서만 사용 가능하다. CRA에서는 이미 css 모듈을 지원하도록 설정되어 있다.

css 모듈의 사용법은 간단하다. css 파일의 이름을 이름.module.css과 같이 변경한다. 이것은 css 모듈이 작동하도록 코드를 변환하라고 컴파일 과정에 보내는 신호이다.
className에 문자열을 넣는 대신 import하고 있는 styles 객체를 넣는다. stlyes는 객체이며, 그 객체 안에 파일에서 프로퍼티로 정의하는 모든 클래스를 갖는다.

import styles from './Button.module.css

const Button = props => {
 	return (
      // css 파일에 my-button 클래스가 있을 경우
      <button className={styles['my-button']}>{props.children}</button>
      )
}

css 모듈을 통해 생성된 class 이름은 결과적으로 고유한 값이다. 왜냐하면 class 이름에 개발자가 지정한 값 외에 더 많은 정보가 추가되었기 때문이다. 컴포넌트 이름_클래스 이름_고유한 해시값으로 구성되었다.

css 모듈이 하는 일은 결국 css class 이름을 고유하게 바꾸는 것이다.

const Button = props => {
 	return (
      // isValid가 false면 클래스에 `.my-button.invalid`이 들어간다.
      <button className={`${styles['my-button'] ${!isValid && styles.invalid}`}}>{props.children}</button>
      )
}

1개의 댓글

comment-user-thumbnail
2022년 5월 9일

스타일드 컴포넌트 쓸 때 전역에 미디어쿼리를 선언해두고 사용한적이 있어요 ㅋㅋㅋ 굉장히 편하다고 느꼈습니다 .. 잘 보고갑니다 마르코군 ~~ 크크

답글 달기