일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 프로그래머스
- vanillaJS
- 자바 공부
- 코틀린
- react
- 백준
- useEffect
- 리액트 훅
- 프로그래밍 언어론
- 자바
- 프로그래머스 완전탐색
- 코딩테스트 고득점 Kit
- useState
- NextJS
- react firebase
- 데이터모델링과마이닝
- design pattern
- 컴퓨터 네트워크
- React JS
- websocket
- 자바스크립트
- Java
- 디자인 패턴
- JavaScript
- codesandbox
- 리액트
- 장고
- 코딩테스트 고득점 Kit 완전탐색
- 프로그래머스 자바
- react hook
- Today
- Total
기록하는 개발자
CSS 방법론 - BEM, OOCSS, SMACSS 본문
내가 지금까지 무심코 써왔던 CSS 스타일링 방법이 사실은 CSS 방법론이라는 이름하에 여러 개로 나눠지고 있었다.
가장 유명한 BEM, OOCSS, SCACSS 세 가지 중 무엇을 쓰는 것이 효율적인가에 대해 많은 이야기가 있는데
알고 보니 나는 이 3가지를 모두 섞어서 쓰고 있었다🫢
더 놀라운 점은 실제로 한 가지만 쓰는 것보다는 두 가지 이상을 섞어 쓰면서 개별적인 단점을 보완하는 것이 더 유리하다는 것이다🫢🫢🫢
그렇다면 세 가지 방법론에 대해 알아보자
1. BEM
블록(Block), 요소(Element), 상태(Modifier)로 구분하여 클래스 이름을 작성하는 방법론이다. 각 부분을 __와 --로 구분하여 클래스명을 짓게 된다. Ex) Block__Element—Modifier
1. Block
- block의 속성을 가지고 재사용할 수 있는 독립적인 영역에 적용한다.
- block은 여백, 위치, 색상 등 상태에 대한 내용은 담지 않는다.
- 클래스명이 길어질 경우엔 하이픈(-) 으로 구분한다.
<!-- right way -->
<div class="header"></div>
<div class="btn-container"></div>
<!-- wrong way -->
<!-- fixed, white 같이 상태에 대한 내용은 클래스로 담지 않는다. -->
<div class="header-fixed"></div>
<div class="btn-container-white"></div>
2. Element
- Block 안에 적용되는 내용들로 클래스명도 블록과 맥락이 이어져야한다.
- 클래스명은 언더바 2개(__) 로 작성한다.
<div class="nav">
<div class="nav__logo">
<img class="nav__logo--small" src="/logo"></img>
</div>
<div class="btn-container">
<button class="btn-container__btn"></button>
<span class="btn-container__btn-text"></span>
</div>
</div>
3. Modifiers
- block 혹은 element의 모양(color, size), 상태(position, disabled, checked)를 정의한다.
- 클래스명은 하이픈 2개(--)로 작성한다.
<div class="nav">
<div class="nav__logo">
<img class="nav__logo--small" src="/logo"></img>
</div>
</div>
장점
- 직관적인 클래스 사용을 통해 여러사람이 함께 작업을 진행하더라도 클래스를 알아보기 쉽게한다.
- 코드의 재사용성이 용이하다.
단점
- 직관적인 클래스명을 사용하다보니 클래스명이 지나치게 길어져 복잡해지는 경우가 있다.
2. OOCSS(Object Oriented Css)
CSS를 모듈 방식으로 작성하여 중복을 줄이는 방식의 방법론으로, 실제로 가장 많이 쓰인다.
특징
- css를 모듈 방식으로 적용해서 중복을 최소화 하는 것을 추구한다.
- id 선택자를 사용하지 않는다.
- 각 단어별 하이픈(-)으로 구분한다.
1. 구조와 외형을 분리
반복되는 기본 구조 및 외형과 관련된 내용을 공통 스타일화 하여 정의한다.
<style>
/* 구조 스타일 */
.button{
width : 80px;
height : 40px;
text-align : center;
}
/* 외형 스타일 */
.button-black{
background : black;
color : white;
}
</style>
<span class="button button-black">click</span>
2. 컨텐츠와 컨테이너를 분리
- 어떤 요소(element)에 적용되어 있는게 중요한 것이 아니라 클래스를 적용한 컨텐츠 자체에 의미를 부여하고 사용한다.
- 태그가 변경되어도 적용한 클래스가 같다면 css를 바꿀 필요가 없다.
- 태그에 영향없이 클래스 자체에 스타일이 부여되기 때문에 재사용이 용이하다.
<h2 class="title"></h2>
<p class="title"></p>
장점 : 공통된 부분을 찾아 어디서나 재활용 할 수 있다.
단점 : 다중 클래스 사용으로 유지보수의 어려움과 가독성 저하의 가능
3. SMACSS(Scalable and Modular Architecture for CSS)
CSS를 범주화(Categorization)로 패턴화 하고자 하는 방법론
작성할 CSS를 비슷한 종류끼리 모아 5가지 스타일로 나누고 각 유형에 맞는 선택자와 작명법, 코딩 기법을 제시한다. 기본(base), 레이아웃(layout), 모듈(module), 상태(state), 테마(theme) 다섯 가지의 범주를 제시한다.
1. Base (기본)
각 브라우저의 스타일 초기화를 위해 reset 등 페이지 전체에 기본 스타일을 적용하며 !important는 사용하지 않는다.
2. Layout (레이아웃)
- 페이지 큰 틀을 잡아주는 레이아웃과 관련된 스타일을 정의한다.
- header, footer, container, aside 등 주요 컴포넌트들과 그 하위 컴포넌트에 규칙을 적용한다.(nav, form...)
- 주요 요소(id)와 하위 요소(class)로 구분하고 접두사를 사용한다.
- 특정 상태에 따른 레이아웃을 변경하는 내용을 다루는 css 작성시 l- 혹은 layout- 클래스를 접두사로 붙인다.
#header{
width:100%
}
#header .nav{
overflow:hidden;
}
/* ex) fixed: 고정된 크기의 #header를 명시 */
.l-fixed #header{
width:1200px;
}
/* ex) flipped: floating된 .nav를 명시 */
.l-flipped #header .nav{
float:left
}
3. Module (모듈)
- 재사용성이 높은 구성 요소를 정의한다.
- 재사용을 위해서 id 선택자, 태그(element) 선택자를 사용하지 않는다.
(단순 태그 선택자를 사용하게 된다면 .side_button > a 와 같이 '>' 직계자손 선택자를 사용한다.)
<style>
.buttons{absolute; top:0; right:0}
.buttons > a{display:block; border:1px solid blue;}
</style>
<div class="buttons">
<a href="#">버튼</a>
</div>
4. State (상태 규칙)
- 요소의 상태 변화를 표현하며, 주로 접두사 .is- 클래스를 사용한다(ex) .is-disabled, .is-checked).
- 클래스 적용은 javascript를 통해(element.classList.add) 특정 이벤트에 따라 적용한다.
.is-error { ... }
.is-hidden { ... }
.is-disabled { ... }
5. Theme (테마)
- 사용자가 선택 가능하도록 스타일을 재선언하여 사용한다.
- 주의 할 점은 메인 css 뒤에 테마용 css를 선언해야 한다는 점이다.(main이 나중에 오면 theme이 덮어씌워짐)
/* main.css */
.button{background:black;}
/* theme.css */
.button{background:white;}
SMACSS 사용 시 유의사항
- 파생된 CSS 선택자(후손 선택자, 자식 선택자, 필터 선택자, 형제 선택자 등)사용금지
- Id 선택자 사용금지
- !Important 사용금지
- 다른 개발자들이 이해할 수 있도록 class 이름을 의미 있게 지어야 한다.
내가 사용하는 방식을 소개해볼까 한다🤭
우선 나는 css가 아닌 scss를 사용한지는 꽤 됐다. scss는 css 전처리기로 아래와 같은 장점이 있다.
css 전처리기(preprocessor) 장점
재사용성 - 공통 요소 또는 반복적인 항목을 변수 또는 함수로 대체
시간적 비용 감소 - 임의 함수 및 Built-in 함수로 개발 시간적 비용 절약
유지 관리 - 중첩, 상속 등의 기능으로 구조화된 코드로 유지 및 관리 용이
Sass(Scss)의 장점(특징)
- 변수 사용 가능 / - 수학 연산자(+ - / * % == !=)를 사용할 수 있다.
- nesting 기능 : 중첩해서 선언 가능. 상위 요소 참조 시 문자 & 사용
- import를 통해 다른 scss 파일을 import 가능
- extend를 통해 특정 선택자의 속성을 상속받기 가능
- mixin을 통해 공통적으로 쓰이는 css 속성을 묶어 선언 후 @include를 통해 재사용 가능
- 커스텀 함수를 사용 가능. @function으로 정의, @return이 리턴값
- @if, @else, @for, @each, @while을 통해 흐름을 제어할 수 있다.
글의 시작에서 알고 보니 내가 방법론 3가지를 모두 섞어서 쓰고 있었다고 했다. 세 가지를 엄격하게 적용한 것은 아니고, 어떻게 보면 편리하게 필요한 부분만 가져와서 사용한 것 같다. 가장 최근 프로젝트에서는 아래와 같은 방법으로 스타일링을 적용했다.
0. 전역으로 사용하는 색상은 변수로, 재사용 되는 스타일(헤더나 본문폰트, 버튼 스타일 등)은 mixin으로 지정해두고 필요할 때 include 해서 사용한다. 아래는 실제 내가 프로젝트에서 작성한 variable.scss 파일의 일부이다.
// variable.scss
// 전역으로 사용하는 색상
$color-disabled: #bdc8d6;
$color-error: #EE0D0D;
$color-focus: #2a82f0;
$color-toast-background: rgba(0, 0, 0, 0.8);
$color-text-white: #fff;
$color-text-black: #000;
$color-text-gray: #a0a0a0;
$color-text-darkgray: #646464;
$color-placeholder: rgba(0, 0, 0, 0.3);
// 전역으로 사용하는 폰트 스타일
@mixin text-h1 {
font-weight: 400;
font-size: 6rem;
line-height: 6.5rem;
}
@mixin text-body1 {
font-size: 1rem;
line-height: 1.5rem;
letter-spacing: 0.5px;
}
@mixin button-white {
color : $color-text-white;
border : $border-button;
border-radius: $border-radius-button;
background-color: $color-surface-white;
}
@mixin button-hover-black {
background-color: $color-hover;
color:$color-text-white;
border: $border-button-hover;
box-shadow: $shadow-button-hover;
}
// 전역으로 사용하는 그림자 스타일
$shadow-bottom: 0 4px 4px rgba(0, 0, 0, 0.25);
$shadow-center: 0 0 5px rgba(0, 0, 0, 0.25);
$shadow-dropdown: 1px 2px 4px rgba(0, 0, 0, 0.25);
$shadow-button: 1px 3px 3px rgba(0, 0, 0, 1);
$shadow-button-hover: 1px 3px 3px rgba(204, 207, 209, 1);
// 전역으로 사용하는 버튼 스타일
$border-button: 3px solid #000;
$border-button-hover: 3px solid #e5e6e8;
$border-radius-button: 1.25rem;
1. SMACSS 방식으로 기본 html base를 reset한다. 아래는 내가 사용한 reset.scss 파일이다.
* Reset 하는 이유
- 각 브라우저마다 설정 되어있는 기본 스타일이 다 다르기 때문에, CSS를 작성할 때 초기화를 시킨다. 즉, 기본적으로 태그가 가지고 있는 간격, border, 색상 등을 통일 시키는 작업이다.
// reset.scss
@import "./mixin.scss";
*{
margin: 0;
padding: 0;
border: 0;
}
/* HTML5 display-role reset for older browsers */
article, aside, details,figcaption,figure,footer,header,hgroup,menu,nav,section {
display: block;
}
ol, ul {
list-style-type: none;
}
button{
cursor: pointer;
}
a {
text-decoration: none;
outline: none;
}
2. scss(sass)를 사용해 클래스 이름은 BEM 방식으로 짓는다.
- 기존 BEM 방식은 modifier에 block 혹은 element의 모양(color, size), 상태(position, disabled, checked)를 정의 하는데, 이러한 부분은 취하지 않았다. 단지 이름을 지을 때 '__'와 '--"로 구분하는 방식만 가져와서 사용했다.
ex) 최상위-블럭__블럭-내-요소--개별요소
@import "../../../base/variable.scss";
.MyReview{
min-width : 550px;
max-height: 40rem;
@include overflow-y-scroll();
}
.MyReview-card__container{...}
.MyReview-card__header{
.MyReview-card__header--col1{...}
.MyReview-card__header--col2{
.MyReview-card__header--row1{...}
}
}
.MyReview-card__content{
.MyReview-card__rating{...}
}
3. OOCSS를 기반으로 스타일을 적용한다.
- 아래와 같이, 두 container 내 button은 모두 동일한 mixin 'button-white'를 사용하지만 필요한 스타일링을 유동적으로 추가해서 사용한다.
.ReviewModal-btn__container{
.ReviewModal-submitBtn{
@include button-white;
padding : 7px 20px;
&:hover{
@include button-hover-gray;
}
}
}
.userInfo-btn__container{
button{
@include button-white();
cursor: pointer;
padding: 5px 0;
width : 110px;
font-size: 15px;
margin : 5px;
&:hover {
@include button-hover-black();
}
}
}
참고
'Web' 카테고리의 다른 글
[CSS] Display : none, opacity : 0, visibility : hidden 비교 (0) | 2023.12.19 |
---|---|
브라우저의 렌더링 과정과 Reflow, Repaint (0) | 2023.12.19 |
쿠키(cookie), 세션(session), 캐시(cache), 웹 저장소(localstorage, sessionstorage) (0) | 2023.12.11 |
scss에서의 media query 적용하기 (0) | 2023.04.07 |
[SCSS] SCSS의 rgba에 Opacity(투명도)적용하기 (0) | 2022.10.17 |