oocss는 객체 지향에 따라 고안된 설계 방식이다.
기본적인 구조와 반복 정의되는 외형은 따로 정의해둔다. (공통 스타일 추상화)
기본 구조가 독립적으로 지정되어 있기 때문에 향후 다른 색의 버튼이 추가되더라도 외형 스타일만 추가로 정의한다.
예를 들어 설명해보자.
<a href="#" class="btnbase cart">장바구니</a>
<a href="#" class="btnbase buy">바로 구매</a>
/* 버튼 구조: 공통적인 구조 지정 */
.btnbase {
display: inline-block;
padding: 10px 20px;
color: #fff;
border: 3px solid #000;
border-radius: 10px;
}
/* 버튼 외형 */
.cart {
background-color: blue;
}
.buy {
background-color: red;
}
이러한 방법은 객체 지향형 CSS로, 공통적인 버튼의 구조를 만들어두고 외향은 따로 정의해주는 방법이다.
그렇다면 의미론적 CSS를 살펴보자.
<a href="#" class="cartbtn">장바구니</a>
<a href="#" class="buybtn">바로 구매</a>
.cartbtn{
display: inline-block;
padding: 10px 20px;
color: #fff;
border: 3px solid #000;
border-radius: 10px;
background-color: blue;
}
.buybtn{
display: inline-block;
padding: 10px 20px;
color: #fff;
border: 3px solid #000;
border-radius: 10px;
background-color: red;
}
클래스 이름을 구체적으로 설정했고, 구조와 외형을 분리하지 않고 css를 작성했다. 의미론적 css는 중복되는 코드가 많아진다. 또, 재사용이 어려워 어떤 요소를 추가로 삽입할때 처음부터 모든 스타일링을 다시 입혀줘야 한다.
컨테이너와 내용은 분리되어야 한다. 이 둘을 분리하려면 다음을 만족해야 한다.
무슨 말인지 예를 들어 자세히 설명해보도록 하자.
위치에 의존하지 않는 스타일 정의란 무엇일까?
먼저, 위치에 의존하는 스타일을 예를 들어 살펴보자.
(안좋은 예)장소를 한정한 스타일 지정
.header .logo {
background-image: url(img/logo.png);
width: 250px;
height: 25px;
}
.footer .logo {
background-image: url(img/logo-small.png);
width: 100px;
height: 15px;
}
header의 logo, footer의 logo를 직접 스타일링해주는 방법이다.
만약 로고를 다른 영역에서 사용하게 된다면 그때 또 다시 클래스를 지정해서 배경이미지와 크기를 설정해줘야 한다. 중복되는 코드들이 남발하고 있다.
그렇다면 위치에 의존하지 않은 스타일이란?
(좋은 예)장소를 한정하지 않은 스타일 정의
.logo-large {
background-image:url(img/logo.png);
width: 250px;
height: 25px;
}
.logo-small {
background-image:url(img/logo-small.png);
width: 100px;
height:15px;
}
header, footer라는 장소를 한정해주지 않아 클래스 이름만 조립해주면 어디서든 로고 이미지를 이용할 수 있다.
그렇다면, 어떤 태그라도 동일한 외형을 제공하려면 어떻게 해야할까?
(안좋은 예) 태그에 스타일 지정
<h2>부제목입니다.</h2>
h2 {font-size: 1.6rem;}
태그에 직접 스타일링을 해주게 되면 또 코드가 중복되는 단점이 생긴다.
만약 span태그를 사용했는데 h2와 같은 스타일링을 해주길 원하면 또 span태그를 지정하고 font-size:1.6rem
을 입혀줘야 한다.
(좋은 예) 클래스명을 부여하고 스타일 지정
<h3 class="subtitle"> 부제목입니다. </h3>
<span class="subtitle"> 부제목 추가설명입니다. </span>
.subtitle { font-size:16rem; }
태그 이름을 직접 선택하지 않고 클래스 명에 스타일링을 입히면 원하는 부분에 .subtitle만 삽입해주면 간단히 꾸며줄 수 있다.
장점: 앞에서도 계속 설명했듯이, 코드를 재사용하기 용이하다. 이로 인해 스타일시트의 용량축소로 속도가 향상된다.
단점: 원하는 스타일을 입히기 위해 여러 가지 클래스명을 가져다 써야하기 때문에 html에서 클래스 이름 부분이 길어질 수 있다.
또, 같은 맥락이지만 어떤 태그에 스타일링을 추가하고 싶으면 마크업에 클래스를 추가해야 한다.
<div class="stick-man"> ...내용...<div>
.stick-man {...}
<div class="stick-man">
<div class="stick-man__head"></div>
<div class="stick-man__arms"></div>
<div class="stick-man__feet"></div>
</div>
/* Good */
.stick-man__head { ... }
.stick-man__arms { ... }
.stick-man__feet { ... }
/* Bad: 의존성 X */
.stick-man .stick-man__head { ... }
div.stick-man__head { ... }
요소의 요소를 만들어야 한다면(blockelementelemet)
DOM 트리를 모방 하려고 하지 마세요
<!-- Bad -->
<div class="stick-man">
...
<div class="stick-man__arms">
<span class="stick-man__arms__left"></span>
<span class="stick-man__arms__right"></span>
</div>
...
</div>
DOM 트리는 보통 container > header > navigation > ul > li
이런 방식으로 요소 안의 요소 안의 요소로 이루어져 있다.
BEM 방식은 DOM 트리 같은 방법을 지양한다. 그렇다면 어떻게 해야할까?
<!-- Good -->
<div class="stick-man">
...
<div class="arms">
<span class="arms__left"></span>
<span class="arms__right"></span>
</span>
...
</div>
stick-man 안에 있는 arms를 하나의 블록으로 만들었다.
요소 안에 요소를 만드는 경우, 블록 안에 또다른 블록을 만들어 해결할 수 있다.
만약, DOM 트리 형식을 모방할 경우 발생하는 문제점에 대해 알아보자.
<!-- Bad -->
<div class="stick-man">
...
<div class="stick-man-arms">
<span class="stick-man-arms__left"></span>
<span class="stick-man-arms__right"></span>
</div>
...
</div>
<!-- 블록 이동을 시도 할 때, 이상한 이름으로 문제 발생 -->
<div class="iron-man">
...
<div class="stick-man-arms">
<span class="stick-man-arms__left"></span>
<span class="stick-man-arms__right"></span>
</div>
...
</div>
부연 설명을 하자면, 앞서 블록은 재사용 가능한 컴포넌트여야 한다고 설명했다.
그 개념에 따라 stick-man-arms를 iron-man 블록에서 재사용 하려고 하자 iron-man 블록 안에 stick-man-arms가 들어있는 이상한 구조가 완성되었다.
이 경우, 유지 보수 단계나 시간이 지난 후에 코드를 봤을 때 한눈에 파악할 수 없게 된다.
<div class="stick-man stick-man--blue"> ... </div>
<div class="stick-man stick-man--red"> ... </div>
.stick-man--blue { ... }
.stick-man--red { ... }
블록에서 수정을 한 경우
<div class="stick-man">
<div class="stick-man__head stick-man__head--small"></div>
또는..
<div class="stick-man__head stick-man__head--big"></div>
</div>
.stick-man__head--small { ... }
.stick-man__head--big { ... }
요소에서 수정을 한 경우
CSS를 모듈화하고 확장 가능하게 만드는 것을 목표
OOCSS, BEM의 핵심 컨셉을 차용하고 좀 더 자세한 사항 추가
클래스명을 통한 예측, 재사용, 쉬운 유지보수, 확장성을 통해 스타일 체계화
5개의 구분된 카테고리로 CSS 코딩 기법 제시.
어떤 카테고리에 스타일이 속하는지 결정하는데 숙고 요구
l-
, layout-
명시 요구l-fixed
유무에 따라 가변 폭으로 할지 고정 폭으로 할지 결정하는 레이아웃 #content { width: 80%; float: left;}
#aside { width: 20%;}
.l-fixed #content {
width: 600px;
margin-right: 10px;
}
.l-fixed #aside {
width: 200px;
}
<div class="box">
<span class="box-name">...</span>
<span class="box-items">...</span>
</div>
.box { ... }
.box-name { ... }
.box-items { ... }
is-
등을 명시 (is-hidden, is-collapsed) <!-- 레이아웃 요소, 접힌 상태 -->
<div id="header" class="is-collapsed">
<form>
<!-- 모듈, 오류 상태 -->
<div class="msg is-error">
There is an error!
</div>
<!-- 연관된 라벨이 숨겨진 상태 -->
<label for="search" class="is-hidden">Search</label>
<input type="text" id="search">
</form>
</div>
theme-
등의 접두어를 명시 또는 theme/
과 같은 디렉토리로 계층 분리 /* main.css */
.box {
border: 1px solid;
}
/* theme.css - main.css 뒤에서 읽도록 */
.box {
border-color: blue;
}
이러한 접근법 중 완벽하게 이상적인 것은 없다. 각 방법론 중 유용한 방법을 가져와 적절히 섞어 사용할 수 있다.