IT/React

[React] 컴포넌트 스타일링

무녈 2021. 8. 7. 20:57

자료의 출처는 '엘리스 AI 트랙 2기 (https://aitrack.elice.io/)' 'React 심화', 및 '리액트를 다루는 기술'입니다.


React 스타일링

React 앱에서의 스타일링

좋은 앱이란 무엇인가

  • 번들 사이즈에 대한 고려
    => CSS 코드가 차지하는 사이즈는 무척 중요한 요소.
  • 앱성능에대한고려
    => animation, transition 등 유저와의 상호작용에서 스타일 코드의 성능이 중요 요소
  • 사용자에게 유리한 UI/UX를 고려
    => 스타일링에 대한 지식으로, 고급 테크닉을 적용하여 더 나은 UI/UX를 반영
  • 자바스크립트를 이용한 다양한 스타일 기법
    => UI 토글링, 애니메이션, 다크모드, 복잡한 UI 컴포넌트 등은 자바스크립트에 대한 지식만으로 구현하기 힘듦.
  • 유지보수가 용이하고 확장 가능한 코드를 작성
    => 스타일에 관련된 코드를 어떻게 작성하고 관리하는가에 대한 지식이 필요.

좋은 앱을 만들기위한 다양한 방식이 있지만 중요한 요소 중 하나는 앱에 대한 스타일링이다.

스타일링 방식 및 종류

  • 일반 CSS: 컴포넌트 스타일링의 가장 기본적인 방식
  • Sass: 자주 사용되는 CSS 전처리기(pre-processor) 중 하나로 확장된 CSS 문법을 사용하여 CSS 코드를 더욱 쉽게 작성할 수 있도록 해줌.
  • CSS Module: 스타일을 작성할 때 CSS 클래스가 다른 CSS 캘르스의 이름과 절대 충돌하지 않도록 파일마다 고유한 이름을 자동으로 생성해주는 옵션
  • styled-componenets: 스타일을 자바스크립트 파일에 내장시키는 방식으로 스타일을 작성함과 동시에 해당 스타일이 적용된 컴포넌트를 만들 수 있게 해 줌.

가장 일반적인 CSS

이름 짓는 규칙

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

1. 컴포넌트-이름 클래스 형태

ex) App.css

.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;
}

클래스 이름에 컴포넌트 이름을 포함시켜 다른 컴포넌트에서 실수로 중복되는 캘래스를 만들어 사용하는 것을 방지

2. BEM 네이밍(BEM Naming)

CSS 방법론 중 하나로, 이름을 지을 때 일종의 규칙을 준수하여 해당 클래스가 어디에서 어떤 용도로 사용되는지 명확히 작성

ex) .card__title-primary

CSS Selector

CSS Selector를 사용하여 CSS 클래스가 특정 클래스 내부에 있는 경우에만 스타일 적용 가능

/* .App 안에 들어 있는 .logo */
.App .logo {
  height: 40vmin;
  pointer-events: none;
}

CSS Import

button.jsx

import 'button.css';
  function Button({ children }) {
  return (
	<button className="button"> {children}
	</button>
);}

button.css

.button {
  background-color: orangered; 
  color: white;
  width: 140px;
  height: 40px;
}

App.jsx

import Button from './Button';

function App() { 
  return (
    <div>
      <Button>Submit</Button>
    </div>
)}

WEB

 

결과

import 'title.css';

방식으로 해당 js에 import하고, 

element에 

<element className="selector" />

방식으로 class를 사용하여 css를 적용한다.

 

CSS import - 장/단점

  • 단순히 CSS 파일만을 import 하여 사용할 수 있어 편리.
  • 컴포넌트가 많지 않을 경우, 하나의 CSS 파일에 코드를 관리하는 것도 가능함.
  • CSS 파일은 분리할 수 있으나, namespace를 나눌 수 없음.
  • 만일 스타일이 겹칠 경우 cascading rule에 따라, 마지막에 나온 룰이 덮어씌워짐.

Sass

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

복잡한 작업을 쉽게 할 수 있도록 해주고, 스타일 코드의 재활용성을 높여 줄 뿐만 아니라 코드이 가독성을 높여 유지 보수에 더욱 용이

 

Sass에서는 두 가지 확장자 .scss와 .sass를 지원 ( 두 확장자의 문법은 다름)

ex) .sass

$font-stack: Helvetica, sans-erif
$primary-color: #333

body
  font: 100% $font-stack
  color: $primary-color

ex) .scss

$font-stack: Helvetica, sans-erif;
$primary-color: #333;

body {
  font: 100% $font-stack
  color: $primary-color
}

주요 차이점: .sass 확장자는 중괄호({})와 세미콜론(;)을 사용하지 않는다.

.scss는 기존 CSS 작성방식과 유사

 

설치방법

$ yarn add node-sass@4.14.1

(sass 내용은 이후 추가 예정)


Sass 참고 

 

Sass(SCSS) 완전 정복!

Style(CSS) 작업 시 필수가 되어버린 CSS Preprocessor(전처리기) Sass(SCSS)에 대해서 이해하고, CSS로 컴파일하는 방법부터 자세한 SCSS 문법까지 살펴봅니다.

heropy.blog


 

CSS Module

CSS module은 css를 불러와서 사용할 때 클래스 이름을 고유한 값, 

[파일 이름]_[클래스 이름]__[해시값] 형태로 자동으로 만들어서 컴포넌트 스타일 클래스 이름이 중첩되는 현상을 방지해주는 기술

 

CSS module 예시

 

특징

  • 클래스 이름을 지을 때 고유성에 대해 고민하지 않아도 됨
    => 해당 클래스는 우리가 방금 만든 스타일을 직접 불러온 컴포넌트 내부에서만 작동하기 때문
    특정 클래스가 웹 페이지에서 전역적으로 사용되는 경우, :global을 앞에 입력하여 글로벌 CSS임을 명시해 줄 수 있음
  • 하나의 CSS module 파일 안에 작성한 스타일은 하나의 파일 namespace로 관리.
  • class name 뒤에 겹치지 않는 hash를 붙임.
  • 스타일이 겹치는 상황을 해결.
  • 두 단어 이상의 경우, class 명을 camelCase로 이름을 지음. 

import CSS module.js

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

파일명 뒤에 확장자를 위해 module.css를 기입한다.

ex)

import styles from "./input-with-button.module.css";

export function InputWithButton() { 
  return (
    <div className={styles.container}>
      <input type="text" name="text" className={styles.input} />
      <button className={styles.button}>Submit</button>
    </div>
); }

CSS Module이 적용된 스타일 파일을 불러오면 객체를 하나 전달받게 되는데, CSS Module에서 사용한 이름과 해당 이름을 고유화한 키-값 형태로 들어있다.

 

사용법

/* JSX element */
className = {styles.[클래스 이름]} 형태로 전달

CSS Module을 사용한 클래스 이름을 두 개 이상 적용할 때

ex) CSS Module.module.css

/* 자동으로 고유해질 것이므로 흔히 사용되는 단어를 클래스 이름으로 맘음대로 사용 가능 */
.wrapper {
  background: black;
  padding: 1rem;
  color: white;
  font-size: 2rem;
}

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

/* 글로벌 CSS를 작성하고 싶다면 */
:global .something {
  font-weight: 800;
  color: aqua;
}

ex) CSSModule.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;

React 실행
inspect element

classnames

설치

$ yarn add classnames

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

CSS Module 사용 시 이 라이브러리를 사용하면 여러 클래스를 적용할 때 매우 편리


classnames 사용법 참고

 

[React] 리액트 classnames 활용하기 (classnames, !! 연산자)

컴퓨터/IT/알고리즘 정리 블로그

chanhuiseok.github.io


Sass와 함께 사용하기

Sass를 사용할 때 파일 이름 뒤에 .module.scss 확장자를 사용해 주면 CSS Module로 사용

ex) CSSModule.module.scss

/* 자동으로 고유해질 것이므로 흔히 사용되는 단어를 클래스 이름으로 마음대로 사용 가능 */

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

/* 글로벌 CSS를 작성하고 싶다면 */
:global {
  // :global {}로 감싸기
  .something {
    font-weight: 800;
    color: aqua;
  }
}
import styles from './CSSModule.module.css';

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

CSS Module이 아닌 일반 .css/.scss 파일에서도 :local을 사용하여 CSS Module을 사용할 수 있다

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

styled-components

자바스크립트 파일 안에 스타일을 선언하는 방식으로 'CSS-in-JS'라고도 부름

관련 라이브러리 참고

https://github.com/MicheleBertoli/css-in-js

 

GitHub - MicheleBertoli/css-in-js: React: CSS in JS techniques comparison

React: CSS in JS techniques comparison. Contribute to MicheleBertoli/css-in-js development by creating an account on GitHub.

github.com

 

  • 별도의 CSS 파일을 만들지 않고 하나의 컴포넌트 파일 안에서 스타일을 작성
  • 자바스크립트 문법을 그대로 활용하여 코드를 작성
  • React 컴포넌트를 사용하는 것처럼 사용
  •  Sass 문법 활용 가능

* 다양한 라이브러리 중 styled-componenets를 가장 선호하며 해당 내용을 소개함

설치

$ yarn add styled-components

작성 방법

import React from "react";
import styled from "styled-components";

const {className} = styled.{element}` /*백틱*/
	/* 스타일 */
`;

const StyledComponent = () => {
	return (
    	<className />
    )
}

ex) styledComponent.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;
  width: 1024px;
  margin: 0 auto;
`;

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;

App.js

import React, { Component } from "react";
import StyledComponent from "./StyledComponent";

class App extends Component {
  render() {
    return (
      <div>
        <StyledComponent />
      </div>
    );
  }
}

export default App;

*

styled-componenets와 일반 classNames를 사용하는 CSS/Sass를 비교 시, 가장 큰 장점은

props 값으로 전달해 주는 값을 쉽게 스타일에 적용할 수 있다는 점

Tagged 템플릿 리터럴

스타일 작성 시 `(백틱)을 사용하여 만든 문자열에 스타일 정보를 넣어 주었다.

여기서 사용한 문법 => Tagged 템플릿 리터럴

CSS Module의 일반 템플릿 리터럴과 다른 점은 템플릿 안에 자바스크립트 객체나 함수를 전달할 때 온전히 추출할 수 있는 것

`hello ${{foo: 'bar'}} ${() => 'world'}!`
// 결과: "hello [objec Object] () => `world`!"

템플릿에 객체를 넣거나 함수를 넣으면 형태를 잃어버림

다음과 같은 함수를 작성하고 나서 해당 함수 뒤에 템플릿 리터럴을 넣어 준다면, 템플릿 안에 값을 온전히 추출할 수 있음

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

=> console을 통한 결과 

Tagged 템플릿 리터럴을 사용하면 템플릿 사이사이에 들어가는 자바스크립트 객체나 함수의 원본 값을 그대로 추출 할 수 있다.

styled-components는 이러한 속성을 사용해 styled-components로 만든 컴포넌트의 props를 스타일 쪽에서 쉽게 조회할 수 있도록 해준다.


정리

 

리액트 컴포넌트 스타일링의 여러 방식들은 현재 모두 사용되는 쓸모있는 기술들이며, 본인이 원하는, 또는 업무에 필요한 방법들을 익혀 능숙하게 사용하도록 하자.

반응형