상세 컨텐츠

본문 제목

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

21-22/21-22 리액트 마스터

by 도리에몽 2021. 11. 15. 13:00

본문

728x90
  • 일반 CSS : 컴포넌트 스타일링하는 가장 기본적인 방식
  • Sass : 자주 사용되는 CSS 전처리기 중 하나로 확장된 CSS 문법을 사용하여 CSS 코드를 작성
  • CSS Module : 스타일 작성 시, CSS 클래스가 다른 클래스의 이름과 충돌하지 않도록 파일마다 고유한 이름을 자동으로 생성해주는 옵션
  • styled-components : 스타일을 자바스크립트 파일에 내장시키는 방식.

9.1 가장 흔한 방식, 일반 CSS

CSS 작성 시, 가장 중요한 점 : CSS 클래스를 중복되지 않게 만드는 것

9.1.1 이름 짓는 규칙

  1. 컴포넌트 이름-클래스 형태
  2. (예: App-header)
  3. BEM 네이밍 : 해당 클래스가 어디에서 어떤 용도로 사용되는지 명확하게 작성하는 방식
  4. (예: .card_title-primary)

9.1.2 CSS selector

CSS selector를 이용하면, CSS 클래스가 특정 클래스 내부에 있는 경우에만 스타일 적용 가능

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

9.2 Sass 사용하기

Sass (Syntactically Awesome Style Sheets : 문법적으로 매우 멋진 스타일시트) : CSS 전처리기

    복잡한 작업 쉽게 할 수 있도록 해줌

    스타일 코드의 재활용성 높여 줌

    코드의 가독성 높여서 유지보수 쉽게 함

Sass는 두 가지 확장자 .scss.sass를 지원

/* .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 작성방식과 비슷한 문법

💡 node-sass 라이브러리 : Sass를 CSS로 변환해 줌

9.2.1 utils 함수 분리하기

여러 파일에서 사용될 수 있는 Sass 변수 및 믹스인은 다른 파일로 따로 분리하여 작성한 뒤 필요한 곳에서 @import문을 통해 불러와 사용할 수 있습니다.

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

프로젝트에 디렉터리를 많이 만들어서 구조가 깊어졌다면 해당 파일에서는 상위 폴더로 한참 거슬러 올라가야 한다는 단점이 있습니다.

→ sass-loader설정을 커스터마이징하여 해결 가능

커스터마이징 하기 위해서 프로젝트 디렉터리에서 yarn eject 명령어를 통해 세부 설정을 밖으로 꺼내 주어야 함

프로젝트 디렉터리 → config 디렉터리 → webpack.config.js

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

설정 파일 저장 후, 서버를 껐다가 재시작

utils.scss 파일을 불러올 때 어디에 위치하더라도 앞부분에 상대 경로를 입력할 필요 없이 styles 디렉터리 기준 절대 경로를 사용하여 불러올 수 있습니다.

@import 'utils.scss';

만약 위처럼 utils.scss를 매번 포함시키는 것도 귀찮다면, webpack.config.js 파일을 다음과 같이 설정하면 됩니다.

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

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

yarn을 통해 설치한 라이브러리를 사용하는 가장 기본적인 방법

  ⇒ 상대 경로를 사용하여 node_modules까지 들어가서 불러오는 방법

@import '../../../node_modules/library/styles';

  → 물결 문자를 사용하면 자동으로 node_modules에서 라이브러리 디렉터리를 탐지하여 스타일을 불러옴

@import '~library/styles';
💡 include-media(https://include-media.com/) : 반응형 디자인을 쉽게 만들어 줌
    open-color(https://www.npmjs.com/package/open-color) : 색상 팔레트

9.3 CSS Module

CSS Module

    CSS를 불러와서 사용할 때 클래스 이름을 [파일이름]_[클래스이름]__[해시값] 형태로 자동으로 만들어 줌

    ⇒ 컴포넌트 스타일 클래스 이름이 중첩되는 현상 방지

    .module.css 확장자로 파일을 저장하면 CSS Module 적용됨

    만약 특정 클래스가 웹 페이지에서 전역적으로 사용되는 경우, :global을 앞에 입력하여 글로벌 CSS임을 명시할 수 있음

/* 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이 적용된 스타일 파일을 불러오면 객체를 하나 전달받는데 CSS Module에서 사용한 클래스 이름과 해당 이름을 고유화한 값이 키-값 형태로 들어 있습니다.

    고유한 클래스 이름을 사용하려면 클래스를 적용하고 싶은 JSX 엘리먼트에 className={styles.[클래스 이름]} 형태로 전달해주면 됨

    전역적으로 선언한 클래스의 경우, 그냥 문자열로 넣어 줌

  • ES6 문법 템플릿 리터럴을 사용하여 문자열 합하기→ 문자열 안에 자바스크립트 레퍼런스를 쉽게 넣어 줄 수 있음
    //템플릿 리터럴 문법을 사용하고 싶지 않다면,
    className = {[styles.wrapper, styles.inverted].join(' ')}
  • const name = '리액트'; const message = `제 이름은 ${name}입니다.`;

9.3.1 classnames

CSS 클래스를 조건부로 설정할 때 매우 유용한 라이브러리

라이브러리 설치

    $yarn add classnames

//간략 사용법
import classNames from 'clasnames';

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'

여러 가지 종류의 파라미터를 조합해 CSS 클래스를 설정할 수 있기 때문에 컴포넌트에서 조건부로 클래스 설정 시 편리함

  • CSS Module과 함께 사용 : classnames의 bind 함수를 사용하면 styles.[클래스 이름] 형태가 아닌 cx('클래스 이름', '클래스 이름2') 형태로 사용할 수 있음

9.3.2 Sass와 함께 사용하기

Sass에도 파일 이름 뒤에 .module.scss 확장자를 사용하면 CSS Module로 사용 가능

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

:local을 사용하여 일반 .css/.scss파일에서도 CSS Module 사용 가능

9.4 styled-components

CSS-in-JS : 자바스크립트 파일 안에 스타일을 선언하는 방식

    → 그중에서도 개발자들이 가장 선호하는 styled-components 방식

//styledCompoonent.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`
bakcground: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;

9.4.1 Tagged 템플릿 리터럴

스타일을 작성할 때 `을 사용하여 만든 문자열에 스타일 정보를 넣어주는 방식

    ⇒ 템플릿 안에 자바스크립트 객체나 함수 전달할 때 온전히 추출할 수 있음

function tagged(...args) {
	console.log(args);
}
tagged`hello ${{foo:'bar'}} ${() => 'world'}!`

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

styled-components를 사용하여 스타일링된 엘리먼트를 만들 때는 컴포넌트 파일의 상단에서 styled를 불러오고,

styled.태그명을 사용하여 구현

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

사용해야 할 태그명이 유동적이거나 특정 컴포넌트 자체에 스타일링해 주고 싶다면 다음과 같은 형태로 구현

//태그의 타입을 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;
	display:flex;
`;

⇒ JSX에서 사용될 때 color값을 props로 넣어 줄 수 있음

    <Box color="black">(...)</Box>

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

일반 CSS 클래스 사용 시에는 className을 사용하여 조건부 스타일링을 했지만,

styled-components에서는 조건부 스타일링을 props로 처리할 수 있음

<Button>안녕하세요</Button>
<Button inverted={true}>테두리만</Button>

9.4.5 반응형 디자인

일반 CSS 사용할 때와 똑같이 media 쿼리를 사용하면 됩니다.

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%;
	}
`;

⇒ 위 작업을 여러 컴포넌트에서 반복해야 한다면 함수화하여 간편하게 사용 가능

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%;`};
`;
728x90

관련글 더보기