노션 클린 코딩 프로젝트을 진행하기 전 컨벤션을 정하다가 CSS에도 컨벤션이 존재한다는 것을 알았다.
가장 많이 사용되는 OOCSS, BEM, SMACSS를 정리한 뒤 프로젝트에 사용할 컨벤션을 정하고자 공부를 시작했다.
OOCSS, BEM, SMACSS는 같은 지향점을 가지고 있다.
약어에서 알 수 있듯이 CSS를 모듈 방식으로 작성하여 중복을 줄이는 방법론이다.
CSS object는 추상화될 수 있는 반복되는 패턴을 의미한다.
OOCSS의 주요 개념은 다음 두 가지이다.
structure은 width
, height
, margin
, padding
등 invisible style을 의미한다.
skin은 color
, font
등 visible style을 의미한다.
한 웹 사이트에서는 대체적으로 한, 두 가지의 색으로 통일하다 보면 다음과 같이 똑같은 skin 스타일 코드가 반복적으로 사용되는 상황이 생기곤 한다.
#button {
width: 200px;
height: 50px;
padding: 10px;
border: solid 1px #ccc;
background: linear-gradient(#ccc, #222);
box-shadow: rgba(0, 0, 0, 0.5) 2px 2px 5px;
}
#box {
width: 400px;
overflow: hidden;
border: solid 1px #ccc;
background: linear-gradient(#ccc, #222);
box-shadow: rgba(0, 0, 0, 0.5) 2px 2px 5px;
}
#widget {
width: 500px;
min-height: 200px;
overflow: auto;
border: solid 1px #ccc;
background: linear-gradient(#ccc, #222);
box-shadow: rgba(0, 0, 0, 0.5) 2px 2px 5px;
}
이러한 코드가 존재할 때 다음과 같이 바꿔준다.
.button {
width: 200px;
height: 50px;
}
.box {
width: 400px;
overflow: hidden;
}
.widget {
width: 500px;
min-height: 200px;
overflow: auto;
}
.skin {
border: solid 1px #ccc;
background: linear-gradient(#ccc, #222);
box-shadow: rgba(0, 0, 0, 0.5) 2px 2px 5px;
}
더 적은 코드로 이루어지고 재사용성이 늘어난다.
(다른 예시)HTML에서는 다음과 같이 사용할 수도 있다.
<a href="#" class="btn-base cart">장바구니</a>
<a href="#" class="btn-base buy">구매</a>
container는 무엇인가를 포함한 것, 그리고 content는 이미지, 문단, 박스 등 container 안에 포함되어 있는 요소들을 이야기한다.
CSS의 space selector나 '>' selector 보다는 content 스타일을 container로부터 분리하는 것을 추구한다.
#sidebar {
/*...*/
}
#sidebar .list {
/*...*/
}
#sidebar .list .list-header {
/*...*/
}
#sidebar .list .list-body {
/*...*/
}
위 코드를 아래와 같이 바꿀 수 있다.
.sidebar {
/*...*/
}
.list {
/*...*/
}
.list-header {
/*...*/
}
.list-body {
/*...*/
}
<div class="aa bb cc">
와 같은 것)를 자주 사용하는데, 멀티 클래스가 많아질수록 유지 보수가 오히려 힘들 수 있음.div.header
등 HTML tag를 selector 앞에 추가하는 것을 자제하라.!important
사용을 자제하라.wiki에서 사용하는 base classess 들의 용도를 정리하려고 추가했다.
property | description |
---|---|
media | wrapper for the media object. |
img , imgExt | media object의 child node. 보통 link, image, flash의 wrapper로 사용됨. |
bd | media object에서 가장 중요. 반드시 필요하고 안에 무엇이든 들어갈 수 있음. |
data | wrapper for the data table |
txtL , txtR , txtC , txtT , txtM , txtB | <table> , <tr> , <td> , <th> 등에 적용할 수 있는 속성. 각각 좌, 우, 중간, 위, 중간, 아래를 의미 |
line | 가로 줄, 행 |
unit | line 은 한 section(column)으로 나눈 단위(base class). |
sizeXofY | unit 의 width를 분수로 표현한 것. extends unit . |
lastUnit | 각 line의 마지막 child에게 적용되는 속성. extends unit . |
mod | 모든 container 모듈의 base class. 안에 무엇이든 들어갈 수 있음. 내부가 transparent함. |
complex | 내부가 transparent함. mod 나 inner 만으로 구분짓기 어려운 내부를 구현. extends mod . |
pop | backdrop같은 것처럼 외부가 transparent함. extends mod . |
tl , tr , bl , br | 블록의 왼쪽 상단 등 모서리를 복합적으로 표시하는 데 사용되는 표현 요소. |
~막상 정리하고 나니까 그닥 뭐 별거 없는거 같기도...~
block / element / modifier 로 나누는 개발 접근법이다.
UI를 독립된 여러 개의 블록으로 분리하자는 목표를 가지고 있다.
전반적으로 다음과 같은 특징이 있다.
.block__element--modifier
형식을 가진다.block-name
처럼 하이픈 하나만 사용한다.red
가 아닌 error
로 작성한다.block은 문단 전체에 적용된 element, 또는 element를 담고 있는 container이다.
조금 구체적으로 설명하자면, 재사용 가능한 기능적으로 독립적인 페이지 컴포넌트(A functionally independent page component that can be reused)이다(react스러운 느낌이 남).
header
, footer
, sidebar
, content
등이 각각의 block이며 참고로 block은 다른 block을 감쌀 수 있다.
element는 block을 구성하며 block 안에 특정 기능을 수행하는 컴포넌트를 의미한다.
block은 독립적인 형태인 반면, element는 의존적인 형태다.
element는 자신이 속한 block 내에서만 의미를 가진다.
<form class="search-form">
<input class="search-form__input" />
<button class="search-form__button">Search</button>
</form>
위 예시에서 .search-form
은 block이고, .search-form__input
과 .search-form__button
은 element이다.
.search-form
은 여러 페이지에서 반복적으로 사용될 수 있다.
하지만 내부의 input
과 button
은 .search-form
안에서만 의미가 있는 element이다.
modifier는 block이나 element의 속성을 담당한다.
block 또는 element의 외관이나 상태를 변화시켜 다르게 동작하는 block이나 element를 만들 때 사용하면 된다.
<ul class="tab">
<li class="tab__item tab__item--focused">탭 01</li>
<li class="tab__item">탭 02</li>
<li class="tab__item">탭 03</li>
</ul>
위 코드에서 --focused
가 modifier다.
아래처럼 key-value
타입도 '-'을 사용해서 표시 가능하다.
<!-- color-gray, theme-normal이 key-value 타입 -->
<div class="column">
<strong class="title">일반 로그인</strong>
<form class="form-login form-login--theme-normal">
<input type="text" class="form-login__id" />
<input type="password" class="form-login__password" />
</form>
</div>
<div class="column">
<strong class="title title--color-gray">VIP 로그인 (준비중)</strong>
<form class="form-login form-login--theme-special form-login--disabled">
<input type="text" class="form-login__id" />
<input type="password" class="form-login__password" />
</form>
</div>
CSS에 대한 확장형 모듈식 구조의 형태로 5개의 구분된 카테고리로 CSS 코딩 기법 제시하는 방법이다.
어떤 카테고리에 스타일이 속하는지 결정하는데 고민과 숙고가 요구된다.
해당 카테고리들은 다음과 같다.
is-hidden
, is-active
등).body,
p,
h1,
h2,
h3,
h4,
h5,
h6,
ul,
ol,
li,
dl,
dt,
dd,
table,
th,
td,
form,
fieldset,
legend,
input,
textarea,
button,
select {
margin: 0;
padding: 0;
}
body,
input,
textarea,
select,
button,
table {
font-size: 14px;
line-height: 1.25;
}
body {
position: relative;
background-color: #fff;
color: #000;
}
img,
fieldset {
border: 0;
}
ul,
ol {
list-style: none;
}
table {
border-collapse: collapse;
}
em,
address {
font-style: normal;
}
a {
color: inherit;
text-decoration: none;
}
위와 같이 속성 선택자, 가상 선택자, 자식 선택자 등을 사용할 순 있지만 거의 대부분 single element selector(span
, body
등)을 사용한다.
CSS 재설정(reset)은 기본 여백, 패딩 및 기타 속성을 제거하거나 재설정하도록 설계된 기본 스타일 세트다.
다음과 같은 특징이 있다.
!important
를 사용하지 않는다.#article {
width: 80%;
float: left;
}
#sidebar {
width: 20%;
float: right;
}
.l-fixed #article {
width: 600px;
}
.l-fixed #sidebar {
width: 200px;
}
layout style은 재사용 여부에 따라 major / minor 스타일로 나뉜다.
header
, footer
, aside
, container
, content
와 같은 것을 위해 id를 사용할 수도 있다(그리고 SMACSS에서 유일하다).
다음과 같은 특징이 있다.
l-
을 사용한다.버튼, 배너, 아이콘, 박스 등 페이지에서 재사용 가능한 요소들을 이야기한다.
다음과 같은 특징이 있다.
module-
이라는 접두사를 붙인다.같은 module이 다른 section이 사용되는데 약간 차이가 있을 때 부모에 스타일을 지정하면 !important
를 사용하거나 많은 selector를 사용해야 되는 문제가 있다.
subclass를 활용하면 이를 방지할 수 있다.
공식 문서에 나온 예시 상황이다.
Expanding on our example pod, we have an input with two different widths. Throughout the site, the input has a label beside it and therefore the field should only be half the width. In the sidebar, however, the field would be too small so we increase it to 100% and have the label on top. All looks well and good. Now, we need to add a new component to our page. It uses most of the same styling as a .pod and so we re-use that class. However, this pod is special and has a constrained width no matter where it is on the site. It is a little different, though, and needs a width of 180px.
.pod {
width: 100%;
}
.pod input[type='text'] {
width: 50%;
}
#sidebar .pod input[type='text'] {
width: 100%;
}
.pod-callout {
width: 200px;
}
#sidebar .pod-callout input[type='text'],
.pod-callout input[type='text'] {
width: 180px;
}
위 방식은 너무 많은 selector가 사용된다.
.pod-constrained
와 .pod-callout
이라는 subclass를 활용하면 아래와 같이 selector를 줄일 수 있다.
.pod {
width: 100%;
}
.pod input[type='text'] {
width: 50%;
}
.pod-constrained input[type='text'] {
width: 100%;
}
.pod-callout {
width: 200px;
}
.pod-callout input[type='text'] {
width: 180px;
}
<!-- HTML에서 사용 예시 -->
<div class="pod pod-constrained">...</div>
<div class="pod pod-callout">...</div>
.tab {
background-color: purple;
color: white;
}
.is-tab-active {
background-color: white;
color: black;
}
다음과 같은 특징이 있다.
!important
를 사용해도 되며 이 방식이 추천된다.is-tab-active
와 같이 module을 포함한다.is-
라는 접두사를 가진다./* in module-name.css */
.mod {
border: 1px solid;
}
/* in theme.css */
.mod {
border-color: blue;
}
자주 사용되지는 않는다.
전반적인 look and feel을 정의한다.
사용자가 선택 가능하도록 스타일을 재선언하여 사용한다.
background
, color
, border
등을 불변하는 스타일과 분리한다.
theme-
이라는 접두사를 가지거나 theme/
과 같은 디렉토리로 계층을 분리한다.f-
라는 접두사를 붙일 수 있다. 웹 사이트는 보통 3~6개 정도의 폰트 크기만 가지고 있는게 좋다. 그 이상 존재하면 유지 보수가 힘들다.공식 문서에서 저자가 추가한 본인의 좋은 습관(?)이다.
.class {
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid black;
position: relative;
top: 0;
}
#fff;
처럼 3digit으로 표현 가능하면 3digit으로 표현해라. 그리고 hex
나 rgb
는 사용하지 않는다. 왜냐면 #
속성이 더 짧기 때문이다.motion 프로젝트에서 OOCSS와 BEM을 합쳐서 사용할 예정이다.
(개인적으로 BEM은 styled-component
와 같은 느낌이 나서 react스럽다라고 느껴졌다)
내가 생각한 notion은 다음과 같은 특징이 있다.
.d-flex {
display: flex;
justify-content: center;
align-items: center;
}
.m-0 {
margin: 0;
}
.f-16 {
font-size: 16px;
}
위와 같은 코드들은 모든 컴포넌트에서 사용할 수 있을 만한 속성들이다.
반복적인 요소들이기 때문에 따로 선언할 예정이다.
다만 이 때문에 overkill이 나지 않도록 3번 이상 반복적인 요소들에 대해서만 추가할 예정이다.
특정 컴포넌트들은 어떤 컴포넌트 안에서만 의미를 갖는 경우가 있다.
예를 들면 상단 아이콘, private page list 등이다.
class 이름이 길어지는 단점이 생길 수 있지만 해당 컴포넌트가 하는 기능의 명확성을 표시하기 위해 사용할 예정이다.
https://github.com/stubbornella/oocss/wiki
https://www.smashingmagazine.com/2011/12/an-introduction-to-object-oriented-css-oocss/
https://jmjmjm.tistory.com/44
https://dev.to/nouran96/oocss-methodology-92d
https://wit.nts-corp.com/2015/04/16/3538
https://blog.illunex.com/css-%EB%B0%A9%EB%B2%95%EB%A1%A0-oocss/
http://smacss.com/
https://getbem.com/introduction/
https://en.bem.info/methodology/
https://nykim.work/15