CSS를 작성하는 방식과 라이브러리는 너무나 다양한 현재, 선택지가 많으니 어떤 것을 써야 좋을지 고민을 많이 하게된다. 그래서 각 방식 및 라이브러리의 장단점을 보다 잘 이해하기 위해 CSS 문제를 해결하기 위해 등장했던 다양한 언어 및 방식들의 등장 배경과 장단점 대해 순서대로 정리해보려고 한다.
1) Global namespace : 클래스 이름 중복문제
2) Dependencies : 스타일 상속에 의한 중복
3) Dead Code Elimination : 기능이 추가,변경,삭제되는 과정에서 미사용 코드 처리에 어려움이 있음
4) Minification : 클래스이름이나 선택자가 string 기반이며 간결하게 작성하기 어려움
5) Sharing Constants : 자바스크립트 코드와의 상수 공유 불가
6) Non-deterministic Resolution : CSS 로드 순서에 따라 스타일이 달라지는 문제
7) Isolation : CSS의 Cascaidng 특성과 전역 네임스페이스 때문에 css style을 격리하기 어려움(인라인 스타일만이 완전한 격리를 제공함)
이러한 기존 CSS의 문제들로 인해 이를 해결하기 위한 다양한 CSS 언어 및 작성 방식이 등장하게 된다.
= Syntatically Awesome Style Sheets
variables, mixin, extend 등을 활용해 쉽게 css를 작성할 수 있도록 도움을 주는 css 전처리기이자 Syntax이다.
코드를 읽어 전처리한 다음 컴파일 과정을 거쳐 전역 CSS 번들 파일을 생성해준다.
CSS와 비슷한 문법으로도 Sass 지원하기 위해 SCSS(Sassy CSS)를 제공하고 있다.
하지만 네이밍 중복에 대한 처리는 해결되지 않아 이를 해결하고자 BEM이 등장한다.
= BLock,Element,Modifier
CSS 내에서의 네이밍 중복 문제를 해결하기 위해 아이디와 클래스를 중복되지 않게 명명하는 방법론이며 프로젝트를 진행하는 개발자들 간의 약속이라고 할 수 있다.
Block, Element, Modifier로 구성된 클래스명을 지으며 각각 __
와 --
로 구분한다.
작성 예시
.header__navigation--navi-text {
color: red;
}
header
: block, navigation
: element, navi-text
: modifier
Block : 재사용 가능한 기능적으로 독립적인 컴포넌트
Element: 블럭을 구성하는 단위. 자신이 속한 블럭 내에서만 의미를 가짐
Modifier: 블럭이나 엘리먼트의 속성 ex) tab__item--selected
하지만 BEM 방식은 클래스명이 길어지고 길어진 클래스명으로 인해 코드길이가 증가하며 무엇보다 클래스명의 중복을 피하기는 하지만 여전히 개발자가 신경써야한다는 불편함이 있다.
CSS를 모듈화하여 사용하는 방식으로, 클래스명에 고유한 해시 문자열을 추가하여 각기 다른 파일에서 유일한 클래스명이 될 수 있도록 만든다(scope를 지역적으로 제한). 또한 Sass와 함께 CSS-in-CSS 방식이다.
[예시]
1) 파일의 확장자가.module.css인 css 파일 작성
2) js파일에서 import => 이 때 JSON 형태로 반환됨.
import React from "react";
import styles from "./Button.modul.css";
fucntion Button() {
return <button className={styles.Button}></button>;
}
export default Button;
CSS Modules을 통해 클래스명 중복 문제는 해결할 수 있지만 CSS 파일들을 따로 관리해야하는 문제가 있다.
컴포넌트 기반으로 CSS를 작성하는 방법론으로, JS코드에서 CSS를 작성하는 방식이다. 2014년 Facebook 개발자인 Christopher Chedeau aka Vjeux의 발표에서 등장하였으며 1에서 언급했던 CSS 문제들이 이 발표에서 소개되었고, CSS-in-JS가 이러한 문제들을 모두 해결할 수 있다고 강조했다.
1) style 파일을 별도로 관리할 필요 없음.
2) javascript와 css 간의 상수, 함수를 쉽게 공유 가능
3) 고유한 클래스 이름 생성
4) 진정한 분리 법칙 - 부모 요소의 속성 상속하지 않음
5) 컴포넌트 단위로 추상화
6) 벤더 프리픽스(-webkit-, -moz, -webkit- 등) 자동생성
7) 현재 사용중인 스타일만 DOM에 포함함.
ex) Styled-Components, emotion, radium
💅 Styled-Components 사용 예시
import styled from "styled-components";
const Button = styled.button`
backgroundColor: black;
color: white;
`;
const Container = styled.div`
margin: 0 auto;
`;
function App() {
return (
<Container>
<Button>Click</Button>
</Container>
);
}
export default App;
하지만 CSS-in-JSS도 사용 시 라이브러를 별도로 설치해야하기 때문에 번들 크기가 커져 CSS-in-CSS에 비해 렌더링 속도가 느려지는 문제가 존재한다.
지금까지 CSS 문제를 해결하기 위해 등장했던 다양한 방식들에 대해 정리해보았다.
장단점을 이해는 했지만 CSS-in-CSS vs CSS-in-JS (Sass vs Styled-Components) 둘 중 어떤 것을 사용해야할지 여전히 고민될 수 있다. 결론적으로 둘 다 장단점이 있어 서비스 환경에 맞게 사용하는 것이 좋다는 의견들이 많다. 개발의 효율성이 중요하고 컴포넌트 위주의 프로젝트라면 CSS-in-JS, 렌더링 속도가 빨라야하는 인터렉티브한 프로젝트일 경우 CSS-in-CSS를 추천한다고 한다.
출처 및 참고
[번역] CSS의 진화 : CSS 부터 SASS, BEM, CSS 모듈, 스타일드 컴포넌트 까지
[CSS 방법론] BEM 방식
CSS의 진화 과정
모던 CSS : 1. CSS-in-JS
웹 컴포넌트 스타일링 관리: CSS-in-JS vs CSS-in-CSS
SCSS와 Styled-Components를 잠깐씩 프로젝트에 사용하면서 경험했던 내용을 토대로 개인적인 느낌을 말해보자면, SCSS 경우는 include, extend, mixin 등의 유용한 기능이 많았지만 파일을 하나하나 만들어줘야한다는 점이 번거로웠다. 또한 벤더프리픽스가 자동으로 추가되지는 않아서 mixin을 활용해 작성된 오픈소스를 사용해보기도 했었다.
Styled-Components도 역시 유용한 기능들이 많았고, 무엇보다 JS와 변수를 같이 사용할 수 있다는 점에서 CSS를 이용해 복잡하게 작성해야하는 부분들이 확연하게 간단해질 수 있었다. 또한 벤더프리픽스가 자동으로 추가되는 점도 정말 유용했다. 하지만 여러 개의 props를 전달하려니 태그가 점점 길어지는 부분이 조금 아쉬웠다.
아직 두가지 모두 기능을 완전히 사용해보지 않아서 어떤게 더 좋은지 확정지을 수 없으나 우선은 개발 당시에 좀 더 편하게 사용했던 styled-components를 좀 더 사용해보기로 결정했다.