끄적끄적 코딩
article thumbnail
Published 2023. 6. 22. 06:46
[React] 컴포넌트 스타일링 React

전체적인 정의

  • CSS - 제일 기본 방식
  • Sass - 자주 사용되는 css 전처리기
  • CSS module - 클래스명 중복 방지를 위한 기술, css를 모듈화 한다고 생각
  • style-components - 스타일을 js파일에 내장하는 방식


가장 흔한 방식, 일반 CSS

  • 소규모 프로젝트에 적합
  • 가장 중요한 것은 CSS 클래스를 중복되지 않게 만드는 것방법 2. CSS selector을 활용
  • 방법 1. 클래스를 특별 규칙을 사용하여 지정

이름 짓는 규칙

  • React 프로젝트 내에 자동 생성된 App.css이다.
  • 클래스 명을 컴포넌트명-클래스 형태로 짓는다.

이와 비슷한 방법 중에 BEM 네이밍 방식이 있다.

BEM 네이밍 방식

  • 정의 : Block, Element, Modifier의 약자로, Block, Element, Modifier을 기준으로 작성하는 네이밍 방법론이다.
  • 장점 : 클래스만 보고도 누구나 이해할 수 있다.
  • 단점 : 클래스 명이 길다.
  • 특징 : 절대 ID를 사용하지 않는다.
  • 사용: .block__element--modifier (각각을 __, —로 구분 !)
  • 각각의 설명
    • Block
      • 독립적인 의미를 가지는 추상화된 컴포넌트
      • 재사용 가능한 컴포넌트
    • Element
      • 블록을 구성하는 단위
    • Modifier
      • Block이나 Element의 속성을 담음

 

CSS Selector

  • selector을 사용하면 CSS클래스가 특정 클래스 내부에 있는 경우에만 스타일을 적용할 수 있다.
  • 선택자를 통해 형제, 자식 등으로 접근 가능하기 때문에 모든 클래스를 지정하지 않아도 된다.

 

Sass

  • 정의 : Syntactically Awesome Style Sheets (문법적으로 매우 멋진 스타일 시트)
  • 장점
    • CSS 전처리기로 복잡한 작업을 쉽게 할 수 있도록 해준다.
    • 코드의 재활용성 및 가독성을 높여준다.
  • 특징
    • 두 가지 확장자 .scss, .sass를 지원한다
    • 주요 차이점
      • sass : {}와 ;를 사용하지 않는다.
      • scss : 기존 css와 다르지 않다.

Sass, SCSS의 차이?

  • SCSS : Sass 3 version에서 등장한 Sass의 상위 호환 집합
  • 결론
    • Sass는 들여쓰기를 사용하여 구조화된 문법을 가진 CSS 전처리기
    • SCSS는 중괄호와 세미콜론을 사용하는 기존의 CSS 문법과 유사한 문법을 가진 CSS 전처리기
    • SCSS가 Sass에 비해 호환성과 적응성이 더 높기 때문에 현재는 SCSS가 더 많이 사용되고 있다.


CSS 전처리기

  • css를 편하게 작성할 수 있도록 도와주는 도구(언어)
  • 기존 css 문법을 확장하여 아래 기능을 제공한다.
    • 변수, 함수, 믹스인, 중첩 등
  • 사용법
    1. 전처리기로 코딩한다.
    2. 작성한 코드를 표준 CSS로 컴파일 한다.
      • 전처리기로 작성한 코드는 웹에서 동작하지 않으므로 웹에서 동작 가능한 표준 CSS로 컴파일해준다.

ex) SCSS → CSS

$primary-color: seashell;
$primary-bg: darkslategrey;

body {
  color: $primary-color;
  background: $primary-bg;
}
body {
  color:seashell;
  background: darkslategrey;
}

 

utils 함수 분리하기

styles > utils.scss

  • 자주 사용되는 변수 및 믹스인을 저장해주기 위해 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문을 통해 불러준다.


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

  • 위에서 import할 때 상위 폴더가 깊어졌다면, 한참 상위로 올라가야 한다는 단점이 있다.
@import ‘../../../styles/utils’;
  • 이는 sass-loader의 설정을 커스터마이징 하여 해결할 수 있다.
  • sass-loader을 설정하면 @import 없이 utils 파일을 자동적으로 불러온다.


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

  • Sass의 장점 중 하나가 라이브러리를 쉽게 불러와서 사용할 수 있다는 점이다.
  • 실제로 yarn을 통해 설치한 라이브러리는 다음과 같이 상대 경로를 통해 불러오는 방법이 있다.
  • 너무 깊이 위치하면 ../ 가 많아지는 경우가 존재 그럴땐 다음과 같이 ~문자 (물결 문자)를 사용한다.
    • 이렇게 하면 자동적으로 node_modules에서 디렉터리를 탐지한다.
@import ‘~library/styles’;

 

CSS Module

  • CSS를 불러와서 사용할 때, 클래스 이름을 고유한 값인 [파일 이름]_[클래스명]_[해시값] 형태로 자동으로 만들어서 클래스 이름이 중첩되는 현상을 방지해주는 기술
  • .module.css 확장자로 파일을 저장하면 CSS Module이 적용된다.
  • CSS Module 기본 코드
    •  CSSModule.module.css
/* 자동으로 고유해질 것이므로 흔히 사용되는 단어를 클래스 이름으로 마음대로 사용가능*/

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

/* 글로벌 CSS 를 작성하고 싶다면 */
:global .something {
  font-weight: 800;
  color: aqua;
}
    • 장점
      • 클래스 명을 지을 때, 흔히 사용되는 단어로 지어도 문제가 되지 않는다.
      • (방금 만든 스타일을 직접 불러온 컴포넌트 내부에서만 작동하기 때문)


CSSModule.js

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

const CSSModule = () => {
  return (
    <div className={styles.wrapper}>
      안녕하세요, 저는 <span className='something'>CSS Module !</span>
    </div>
  );
};

export default CSSModule

여기서 import를 통해 styles 라는 객체를 받는다.

  • 콘솔에 찍어보면 다음과 같다.

global CSS는 직접 넣어 사용한다.

 

classnames

  • 클래스를 조건부로 설정할 때 유용한 라이브러리이다.
  • CSS Module을 사용할 때 이 라이브러리를 사용하면 여러 클래스를 적용할 때 편리하다.
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'
  • props 값에 따라 다른 스타일 주기
const MyComponent = ({ highlighted, theme }) => {
	<div className={classNames('MyComponent', { highlighted }, theme)}Hello</div> // highlighted가 true면 적용, false면 미적용 
});

 

styled-components

  • **‘css-in-js’**의 대표적인 예시이다.
  • 그 중에서 styled-components를 개발자들이 많이 선호한다.
  • CSS in JS
 

State of CSS 2022: CSS-in-JS

This chart splits positive (“want to learn”, “would use again”) vs negative (“not interested”, “would not use again”) experiences on both sides of a central axis. Bar thickness represents the number of respondents aware of a technology.

2022.stateofcss.com

 

StyledComponents.js

  • css 파일을 따로 작성하지 않아도 된다.
  • 뒤에서 상세하게 알아보자.
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;

 

Tagged 템플릿 리터럴

  • Tagged 템플릿 리터럴
    • 스타일을 작성할 때 ``(백틱)안에 스타일 정보를 넣어주는 문법
  • 기존 템플릿 리터럴
    • 객체 타입인 경우 대입이 안된다.
    const foo = {foo: 'bar'};
    `hello ${foo} ${() => 'world'}!`
    // 결과: "hello [object Objct] () => 'world'!"
  • 기존 템플릿 리터럴의 문제점 극복
  • 템플릿 리터럴을 통해 함수를 만든다. ⇒ Tagged 템플릿 리터럴
function tagged(...args) {
	console.log(args);
}

// 함수 뒤에 템플릿 리터럴 작성 -> 템플릿 리터럴 안의 값들을 온전히 추출 
tagged`hello ${{foo: 'bar' }} ${() => 'world'}!`;

  • Tagged 템플릿 리터럴을 통해 템플릿 사이사이에 들어가는 자바스크립트 객체나 함수 원본값을 그대로 추출할 수 있다.
  • styled-components는 이러한 속성을 사용하여 styled-components로 만든 컴포넌트의 props를 스타일 쪽에서 쉽게 조회할 수 있도록 한다.
const styled = {
		// texts : 속성명, rest : 속성값 
    p(texts, ...rest) {
        const defaultProps = {
            color1: 'yellow',
            color2: 'orange'
        };
        return texts.reduce((acc, cur, i) => `${acc}${cur}${rest[i] ? `${rest[i](defaultProps)}` : ''}`, '');
    }
}

styled.p`
background: ${props => props.color1}
color: ${props => props.color2}
`

// 결국 return 받는 값 
/*
background: yellow
color: orange
*/

 

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

  • MyComponent
  • import styled from 'styled-components'; const MyComponent = styled.div` font-size: 2rem; `;
  • styled.div뒤에 Tagged 템플릿 리터럴 문법을 통해 스타일을 넣어주면 해당 스타일이 적용된 div 태그로 이루어진 리액트 컴포넌트가 생성된다.
  • 사용
  • <MyComponent>Hello</MyComponent>

 스타일에서 props 조회하기

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

props에 따른 조건부 스타일링

/* 다음 코드는 inverted 값이 true 일 때 특정 스타일을 부여해줍니다. */
  ${props =>
    **props.inverted &&
		// 여기서 여러 줄의 css를 사용하기 위해 css를 불러와야 한다.
		// tagged 템플릿 리터럴이 아니기 때문에 props를 사용하지 못한다.** 
    css` 
      background: none;
      border: 2px solid white;
      color: white;
      &:hover {
        background: white;
        color: black;
      }
    `};
<Button>안녕하세</Button>
<Button inverted={true}>테두리만</Button>

 

반응형 디자인

const sizes = {
  desktop: 1024,
  tablet: 768
};

// 위에있는 size 객체에 따라 자동으로 media 쿼리 함수를 만들어줍니다.
// 참고: <https://www.styled-components.com/docs/advanced#media-templates>
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`
  /* props 로 넣어준 값을 직접 전달해줄 수 있습니다. */
  background: ${props => props.color || 'blue'};
  padding: 1rem;
  display: flex;
  width: 1024px;
  margin: 0 auto;
  ${media.desktop`width: 768px;`}
  ${media.tablet`width: 100%;`};
`;

	// @media (max-width: 64em) {
  //    width: 768px;
  // }

'React' 카테고리의 다른 글

[React] immer  (0) 2023.06.28
[React] 컴포넌트 스타일링  (0) 2023.06.27
[React] Hooks  (0) 2023.06.22
[React] 컴포넌트의 라이프사이클 메서드  (0) 2023.06.22
[React] 컴포넌트 반복  (0) 2023.06.22

검색 태그