CSS 클래스를 만들다보면 이름을 짓는 것이 고민될 때가 많다. BEM은 CSS 클래스 이름을 짓는 규칙이다. 블록(Block), 요소(Element), 변경자(Modifier) 형태로 쓴다. 블록은 <di> 같은 영역을 의미하고, 요소는 <button>, <input> 같은 요소를 의미한다. 변경자는 요소의 변형을 표시하는 거라고 이해하면 된다. .block__element--modifier 형태로 쓴다.
<form class="signin-form">
<label class="signin-form__label">
Email
<input type="text" class="signin-form__input">
</label>
<label class="signin-form__label">
Password
<input type="password" class="signin_form__input signin_form__input--pasword">
</label>
<button class="signin-form__button signin-form__button--submit">
Sign In
</button>
</form>
.signin-form { /* 로그인 폼 */ }
.signin-form__input { /* 로그인 폼의 인풋 */ }
.signin-form__input.signin-form__input--password { /* 로그인 폼의 비밀번호 인풋 */ }
.signin-form__button { /* 로그인 폼의 버튼 */ }
.signin-form__button.signin-form__button--submit { /* 로그인 폼의 제출 버튼 */ }
BEM 예제
BEM 101 | CSS-Tricks
Quick Start / Methodology / BEM
BEM - Block Element Modifier
CSS는 웹 표준이기 때문에 문법이 빠르게 바뀌지 않는다. 그래서 개발자들이 사용하기 편한 여러가지 문법을 추가한 새로운 언어를 만들기 시작했고, 그 중에 가장 많이 쓰는 것이 Sass이다. 네스팅(Nesting) 문법, 믹스인(Mixin) 등등 다양한 기능을 제공한다. 이 중에서 많은 사람들이 좋다고 생각한 문법(변수, 네스팅 등)은 엡 표준으로 흡수되기도 했다.
Sass는 프리프로세서(Preprocessor) 스크립트 언어라고 하는데, 프리프로세서라는 프로그램을 통해서 Sass 코드를 CSS 코드로 변환하기 때문이다. Sass에는 기존 Sass와 SCSS 두 가지 문법이 있는데, 최근에는 CSS의 모든 문법 위에서 확장된 문법을 사용하는 SCSS를 많이 사용한다.
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
@mixin theme($theme: DarkGray) {
background: $theme;
box-shadow: 0 0 1px rgba($theme, .25);
color: #fff;
}
.info {
@include theme;
}
.alert {
@include theme($theme: DarkRed);
}
.success {
@include theme($theme: DarkGreen);
}
.info {
background: DarkGray;
box-shadow: 0 0 1px rgba(DarkGray, .25);
color: #fff;
}
.alert {
background: DarkRed;
box-shadow: 0 0 1px rgba(DarkRed, .25);
color: #fff;
}
.success {
background: DarkGreen;
box-shadow: 0 0 1px rgba(DarkGreen, .25);
color: #fff;
}
패키지 설치 후 큰 설정없이 적용 가능
패키시 설치 후 큰 설정없이 적용 가능
리액트 컴포넌트를 CSS로 개발하다보면 CSS 이름이 겹치는 문제가 발생할 수 있다.
왼쪽 사이드 바에 있는 로고를 .logo라는 클래스로 스타일링하고, 오른쪽 화면의 로고도 .logo라는 클래스로 스타일링하면 CSS 스타일이 겹치게 된다. 이럴 때는 서로 다른 이름을 사용해야 할는데, 컴포넌트 단위로 개발할 때는 쉽지가 않다.
CSS Modules는 마치 자바스크립트 모듈을 사용하듯이 CSS 파일을 각각 독립적으로 사용할 수 있도록 해준다. 예를 들어 Sidebar라는 컴포넌트랑 Homepage라는 컴포넌트가 있을 때 아래처럼 CSS를 사용할 수 있다.
/* Sidebar.module.css */
.logo { /* ... */ }
.searchInput { /* ... */ }
.menu { /* ... */ }
/* Homepage.module.css */
.logo { /* ... */ }
.sections { /* ... */ }
.logo라는 똑같은 클래스 이름을 사용하더라도 CSS Modules에서는 서로 다른 클래스 이름이다. 이 코드들을 CSS로 변환하면서 적절한 문자열을 추가해 준다. 이렇게 만든 코드를 리액트에서는 클래스 이름을 담은 객체로 가져와서 사용한다. styles.logo는 .logo에 매칭되는데, 그 값은 .logo에 적절한 문자열이 추가된 CSS 클래스 이름이다.
// Sidebar.js
import styles from './Sidebar.module.css';
export default function Sidebar() {
return (
<div>
<img className={styles.logo} src="/logo.svg" />
<input className={styles.searchInput} />
<nav className={styles.menu}>
...
</nav>
</div>
);
}
create-react-app으로 생성한 프로젝트라면 별도의 설정 없이 사용할 수 있다.
Next.js 프로젝트에서는 별도의 설정 없이 사용할 수 있다.
GitHub - css-modules/css-modules: Documentation about css-modules
자바스크립트 코드로 CSS를 작성하는 방식이다. 자바스크립트 코드가 실행되면서 CSS 코드가 생성되는데, 컴포넌트를 만들면서 동시에 CSS도 개발할 수 있다는 장점이 있다.
Utility-first라는 방법론으로 디자인을 적용하는 라이브러리 중에서 가장 많이 쓰이는 라이브러리이다.
기존의 CSS에서는 요소를 기준으로 스타일을 작성했다. 위 모달 디자인에서 취소, 비우기 버튼의 디자인을 아래처럼 작성할 수 있다.
<div class="buttons">
<button class="cancel-button">취소</button>
<button class="confirm-button">비우기</button>
</div>
.buttons {
display: flex;
justify-content: flex-end;
}
.cancel-button {
background-color: var(--secondary);
padding: 8px 16px;
}
.confirm-button {
background-color: var(--primary);
padding: 8px 16px;
}
Utility-first에서는 각 CSS 속성을 CSS 클래스로 만든다. CSS 속성을 작성하는 게 아니라 미리 잘 정의된 클래스들을 가지고 조합해서 디자인을 적용한다.
<div class="flex justify-end">
<button class="bg-secondary px-16 py-8">취소</button>
<button class="bg-primary px-16 py-8">비우기</button>
</div>
하나의 완벽한 기술은 없다. 서로 장단점이 있기 때문에 각 기업들은 상황에 맞는 기술을 선택하고 사용한다.
@apply)으로 추상화를 지원하기도 한다.<a href="..." className="rounded-lg px-3 py-2 text-slate-700 font-medium hover:bg-slate-100 hover:text-slate-900">...</a>