SMACSS(이하 ‘스맥스’)는 대규모 프로젝트를 위한 스타일링 지침이다.

스타일의 다섯가지 유형

스맥스는 스타일을 다섯가지로 분류하고, 각 유형에 맞는 선택자(selector)와 작명법(naming convention), 코딩 기법을 제시한다.

  1. 기초(Base)
  2. 레이아웃(Layout)
  3. 모듈(Module)
  4. 상태(States)
  5. 테마(Theme)

(1) 기초 스타일

흔히 말하는 reset 스타일류를 말하는 것이다.

  • 기능: 요소(elements) 스타일의 기본값 지정
  • 선택자
    • 주로 요소 선택자(ex. input[type=text] 같은 것)
    • 필요에 따라서 자식(child) 선택자, 자매 선택자, 어트리뷰트(attribute) 선택자 등
    • !important를 쓸 이유가 없다.

html, body, form { margin: 0; padding: 0; }
input[type=text] { border: 1px solid #999; }
a { color: #039 }
a:hover { color: #03C; }

(2) 레이아웃 스타일

  • 기능: 페이지를 구획하는 스타일(예: 헤더, 푸터, 그리드 …)
  • 선택자: 아이디나 클래스
    • 아이디는 CSS에서 클래스와 성능 차이가 없으며, 오히려 선택자 우선순위 점수(specificity) 때문에 함정에 빠질 우려가 있으므로, 신중하게 써야 한다.
  • 작명법
    • 아이디에는 이름 공간(namespace)을 할당하지 않아도 무방(이름 공간은 SMACSS에서 사용하는 접두어를 말한다. 예컨대 layout은 l-이라는 접두어를 붙인다.)
    • 클래스는 ‘l-‘을 앞에 붙여서 다른 유형의 클래스와 구분

레이아웃 스타일은 재사용성에 따라 큰 레이아웃 스타일과 작은 레이아웃 스타일로 구분된다.

큰 레이아웃 스타일

예시:

#header, #article, #footer {
    width: 960px;
    margin: auto;
}

#article {
    border: solid #CCC;
    border-width: 1px 0 0;
}

작은 레이아웃 스타일

960.gs와 같은 레이아웃 프레임워크를 쓸 경우다. 아이디가 아니라 클래스를 매겨서 요소를 재사용한다.

재사용성

저자는 아이디를 매기기 전에 해당 요소의 재사용성을 숙고하라고 한다. 예시:

<div id="featured">
<h2>Features</h2>
<ul>
    <li><a href="...">...</a></li>
    <li><a href="...">...</a></li>
    ...
</ul>
</div>

div#featured ul {
    margin: 0;
    padding: 0;
    list-style-type: none;
}
div#featured li {
    float: left;
    height: 100px;
    margin-left: 10px;
}

위 코드는 다음과 같은 가정이 깔려있다.

  1. 격자가 딱 한번만 사용된다.
  2. 항목은 왼쪽부터 띄운다(float).
  3. 항목의 높이는 100픽셀이다.

위 코드를 아래와 같이 개선하면

.l-grid {
    margin: 0;
    padding: 0;
    list-style-type: none;
}

.l-grid > li {
    display: inline-block;
    margin: 0 0 10px 10px;

    /* IE7 hack */
    *display: inline;
    *zoom: 1;
}

다음과 같은 이점이 있다.

  1. 어느 박스에서나 그리드 레이아웃을 만들어낼 수 있다
  2. depth of applicability(나중에 다룰 것임)를 1로 줄였다
  3. 선택자의 우선순위 점수를 줄였다
  4. 가장 높은 항목의 높이에 따라 열의 높이가 바뀐다

다음과 같은 단점이 있긴 하지만

  1. 자식 선택자(>) 때문에 IE6이 배제된다(자식 선택자를 쓰지 않는 식으로 이 문제를 해결할 수 있다).
  2. CSS의 크기와 복잡성이 증가했다.

재사용성이 증가했기 때문에, 코드를 중복하지 않아도 되고, 선택자의 우선순위 점수를 줄였기 때문에 레이아웃을 확장하기에 좋다.

(3) 모듈 스타일

  • 기능: 레이아웃 요소 안에 들어가는 더 작은 부분들(예: 네비게이션 바, 말풍선, 대화 상자, 위젯 …)
  • 선택자
    • 클래스
    • 모듈에 포함된 요소는 후손 선택자나 자식 선택자로. (그냥 띄어쓰는 게 후손 선택자고, >로 연결하는 게 자식 선택자다. 후손 선택자는 .my-module li, 후손 선택자는 .my-ul>li)
    • 요소 선택자(a 같은 태그 선택자)는 피한다.(충돌을 피할 자신이 없다면)
    • 내용을 반영하는 선택자일수록 좋다.

하위 클래스 만들기(sub-classing)

모듈의 변종은 언제나 하위 클래스로 스타일링한다.

나쁜 예:

.pod {
    width: 100%;
}
.pod input[type=text] {
    width: 50%;
}
#sidebar .pod input[type-text] {
    width: 100%;
}

위 예에서 새로운 하위 클래스를 추가하면 선택자가 번잡해진다.

.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;
}

다음은 좋은 예다:

.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;
}

하위 클래스 적용하기:

.pod.pod-callout { }

<div class="pod pod-callout"> ... </div>

(4) 상태별 스타일

  • 기능: 다른 스타일에 덧붙이거나 덮어 씌워서 상태를 나타냄(예: 펼침과 접힘, 성공과 실패 등)
  • 선택자
    • 클래스 선택자 한개
    • !important를 쓸 수도 있다(최소화 할 것)
    • 같은 모듈에 두 상태를 적용하지 말 것
  • 작명법
    • is-‘를 앞에 붙인다
    • 특정 모듈에 한정된 상태는 모듈 이름도 그 뒤에 붙인다.(예: is-tab-active)
  • 유의: 전역 상태 스타일은 모듈 상태 스타일과 구분한다. 모듈 상태 스타일은 모듈 스타일과 병기한다.

예시

<div id="header" class="is-collapsed">
    <form>
        <div class="msg is-error">
            There is an error!
        </div>
        <label for="searchbox" class="is-hidden">Search</label>
        <input type="search" id="searchbox">
    </form>
</div>
  • #header
    • 레이아웃 요소임을 알 수 있다.
    • .is-collapsed로 접힌 상태임을 알 수 있다.
  • .msg
    • 모듈이다.
    • .is-error로 오류 상태임을 알 수 있다.
  • #searchbox
    • 연관된 라벨은 숨겨져 있다.
    • 라벨이 마크업 된 이유는 스크린 리더기를 위한 것

모듈과 다른 점

  • 모듈과 레이아웃 둘 다에 적용할 수 있다
  • 페이지가 로드된 이후의 상태 변화를 나타내므로 자바스크립트에 의존한다.

(5) 테마 스타일

사용자가 테마를 선택할 수 있는 경우를 염두에 두고, 색상이나 이미지를 불변하는 스타일과 분리하는 것이다. 거의 사용할 일은 없지만 필요할 때가 있다.

예시

/* 모듈 스타일 */
.mod {
    border: 1px solid;
}

/* 테마 스타일 */
.mod {
    border-color: blue;
}
  • 적용 범위가 넒은 테마는 theme-를 접두어로 붙여서 혼란을 피한다
  • i18n 등을 염두에 두고 글꼴도 사용자가 바꿀 수 있게 하기 위해 글꼴 스타일도 따로 분류할 수 있다. 그러나 굳이 글꼴 별로 클래스를 만들 것 까지는 없다