OOCSS

좁은 의미로는 니콜 설리반(Nicole Sullivan)이 만든 CSS 프레임워크를 뜻하지만, 이 프레임워크를 만든 접근법을 지칭하는 말로도 쓰인다. 여기서는 접근법을 지칭하겠다. OOCSS는 Object Oriented CSS의 약자이며, 반복되는 시각적 패턴을 독립적인 HTML, CSS, 자바스크립트 코드 조각으로 분리해서 재사용하는 것을 말한다. 이 재사용 되는 코드가 객체 지향 언어에서의 객체에 비유된다.

2009년에 니콜 설리반은 통상 ‘좋은 CSS 코딩 방법’으로 통하던 방식, 말뜻에서 벗어나는 요소를 배제하고, 클래스 사용을 자제하며, CSS의 계단식 세계관에 맞춰서 후손 선택자를 사용하라는 통설에 의문을 제기했다.

니콜 설리반은 이러한 방법이 선택자 점수(specifity) 경쟁을 일으켜서 CSS를 엉망으로 만든다고 주장했다. 요소 선택자와 ID를 이용해서 스타일을 지정하면, 변종을 만들 때 마다 더 점수가 높은 선택자를 써야하기 때문이다. 가령

h3 {
    color: #333;
    font-size: 17px;
    font-weight: bold;
}
#sidebar h3 {
    color: #797979;
    font-size: 12px;
    font-weight: bold;
    border bottom: 1px solid #c5c5c5;
    padding-bottom: 5px;
}
#sidebar .account h3 {
    color: #333;
    font-size: 13px;
    font-weight: bold;
    background-color:#deeef8;
}
#sidebar .weatherMod h3 {
    color: #fff;
    text-transform: uppercase; 
}

/* 출처: http://www.stubbornella.org/content/2011/04/28/our-best-practices-are-killing-us/ */

사이드바에 모듈이 추가될 때마다 원하는 모습을 얻기 위해 점수가 높은 선택자를 사용하게 되고, 이런 상황은 모듈이 중첩될 때 더 악화된다. 결국 개발자들이 파이어버그로 코딩을 하게되고 급기야는 원하는 외양을 얻을 수 없는 지경에 이른다는 것이다. 게다가 상위 모듈이 선언한 스타일을 덮어쓰느라 코드를 중복하게 된다.

니콜 설리반이 밝힌 OOCSS의 두가지 원칙은 다음과 같다.

  1. 구조와 외양의 분리: 반복되는 시각적 특징은 구조와 별개인 외양(skin)으로 분리시켜서, 이것을 결합시키면 다양한 결과물을 얻을 수 있다. 이것은 외양을 위한 클래스를 만들고, 필요하다면 외양을 위한 요소도 추가할 수 있다는 것을 뜻한다.
  2. 내용과 내용을 담는 그릇을 분리하기: 이것은 “위치에 의존하지 않는 스타일”을 뜻한다. 즉 하위 선택자를 되도록 쓰지 않는다는 것을 뜻한다. 예를 들어 .sidebar h3와 같은 선택자보다는 <h3> 요소에 클래스를 매겨서 .article-heading를 선택자로 쓴다는 것이다.

이처럼 OOCSS는 대부분 클래스에 의존해서 스타일을 준다. 클래스 이름을 어떻게 지어야하는지에 대해서 니콜 설리반은 다음과 같은 가이드라인을 제시한다.

  • 간결함: 되도록 짧게
  • 명료함: 스타일과 작동 방식이 고스란히 드러나게
  • 분명한 말뜻(Semantics): 어떻게 생겼는지가 아니라, 어떤 모듈인지
  • 포괄성: 대부분의 사이트에서도 적용되도록
  • 화면 중심성: 종이나 다른 매체가 아닌 모니터를 기준으로

스타일을 클래스에 의존하기 때문에 클래스 작명은 CSS 설계의 핵심이 된다. OOCSS는 클래스 이름에서도 말뜻을 분명히 할 것을 권장하기 때문에, 클래스 범벅(classitis)과는 다르다. 다음은 말뜻이 분명치 않은 클래스 이름의 전형적인 사례다.(예시 출처는: http://takazudo.github.com/presentation-oocss-sass/)

<a class="blackborder redbg">Twitter</a>
<a class="blackborder bluebg">Facebook</a>

전통적인 방법론에서는 이런 클래스를 피하고 최대한 말뜻이 분명하게 할 것을 요구한다.

<a class="twitterbtn">Twitter</a>
<a class="facebookbtn">Facebook</a>

그러나 이는 많은 중복을 낳는다.

    .twitterbtn {
        border: 3px solid #000;
        padding: 10px; 20px;
        color: #fff;
        border-radius: 10px;
        background: red;
    }

    .facebookbtn {
        border: 3px solid #000;
        padding: 10px; 20px;
        color: #fff;
        border-radius: 10px;
        background: blue;
}

OOCSS에서는 말뜻이 분명한 클래스에서 시각적 패턴을 분리한 새로운 클래스를 신설한다. 이렇게 하면 코드를 재사용할 수도 있다.

<a class="btnbase twitter">Twitter</a>
<a class="btnbase facebook">Facebook</a>

.btnbase {
    border: 3px solid #000;
    padding: 10px; 20px;
    color: #fff;
    border-radius: 10px;
}

.twitter  { background: red;  }
.facebook { background: blue; }

그러나 때로는 설리반 자신도 .md-hd(medium heading)처럼 말뜻에 표현 방식(presentation)이 포함된 클래스 이름을 쓰기도 한다. 실제로 마이크로포맷을 제외하면 클래스 이름은 검색 엔진이나 스크린리더에게 아무런 의미가 없다. 그래서 니콜 설리반이 말하듯 가이드라인이 충돌할 때에는 실용적으로 접근할 수 밖에 없다고 본다.

OOCSS에서의 객체는 SMACSS에서 말하는 모듈과 비슷하다. 다만 SMACSS에서는 모듈을 구성하는 컴포넌트에 매길 클래스에 모듈의 클래스를 접두어로 쓸 것을 요구한다. 이렇게 하면 일단 모듈의 독립성을 보장할 수 있고, 다른 컴포넌트들과 이름이 충돌하는 것을 막을 수 있다. 그리고 각 컴포넌트들은 모듈화 해야할 시점이 왔을 때 하면 되지 않을까 추측한다.

이처럼 클래스에 의존하면 선택자 점수가 균일하기 때문에 재사용할 수 있는 코드 조각을 만들 수 있다. 덕분에 수많은 컴포넌트들이 중첩돼 있고, 중첩 관계가 다양해서 모든 컴포넌트를 계층화할 수 없는 대규모 사이트에서 빠른 속도로 개발을 할 수 있다.

한편 재사용되는 코드가 많다는 것은 사이트 어느 곳에서나 사용되는 코드가 많다는 것이고, 이것은 브라우저가 캐싱할 가능성이 높아진다는 것을 뜻한다. 그래서 사이트의 성능을 크게 향상시키는 데에 도움이 된다.

하지만 다중 클래스에 크게 의존하는만큼 HTML 마크업을 어질러서 유지 보수성을 떨어뜨린다는 비판도 있다. 게다가 OOCSS는 HTML 측에 대한 완전한 통제력을 전제하기 때문에, HTML 마크업을 건드릴 수 없는 경우에는 적용하기 어렵다. 그러나 전처리자를 사용하면 가능하다. Sass에서는 @extend를 이용해서 HTML쪽에 클래스를 추가하지 않고도 객체를 적용한 효과를 낼 수 있다. (예시 출처는: http://takazudo.github.com/presentation-oocss-sass/)

.btnbase {
    border: 3px solid #000;
    padding: 10px; 20px;
    color: #fff;
    border-radius: 10px;
}

.twitter  { @extend .btnbase; background: red;  }
.facebook { @extend .btnbase; background: blue; }

위 파일을 Sass로 컴파일하면 다음과 같은 css가 생성된다.

.btnbase, .twitter, .facebook {
    border: 3px solid #000;
    padding: 10px; 20px;
    color: #fff;
    border-radius: 10px;
}

.twitter  { background: red;  }
.facebook { background: blue; } 

sass가 컴파일해준 css는 공유하는 시각적 특징으로 선택자를 몰아줬다. 이것은 사실 DRY CSS의 방법론이기도 하다. 서로 다른 접근법이 하나로 만나는 순간이다.

sass 3.2부터는 가상 객체를 만들 수도 있다. 이 가상 객체는 호출될 때에만 css를 출력한다. 이것을 이용하면 말뜻 없는 클래스를 하나도 만들지 않고서도, OOCSS를 구현할 수 있다.

컴파일 전:

%btnbase {
    border: 3px solid #000;
    padding: 10px; 20px;
    color: #fff;
    border-radius: 10px;
}

.twitter  { @extend %btnbase; background: red;  }
.facebook { @extend %btnbase; background: blue; }

컴파일 후:

.twitter, .facebook {
    border: 3px solid #000;
    padding: 10px; 20px;
    color: #fff;
    border-radius: 10px;
}

.twitter  { background: red;  }
.facebook { background: blue; }     

물론 이런 방식을 쓸 경우에도 몇가지 한계는 있다.

  1. 어떤 클래스가 어느 클래스에서 상속을 받았는지가 불분명해질 수 있다(SMACSS에서 제시하는 작명 규칙을 따르면, 번거롭기는 하지만 클래스 이름을 이용해서 어느 정도 이 단점을 보완할 수는 있다. 물론 자바스크립트를 걸 때에는 더더욱 번거로울 수도 있다).
  2. @extend가 선택자 점수를 바꿔주진 않기 때문에, 선택자 점수가 낮은 규칙으로 높은 규칙을 확장하려는 헛된 시도를 할 수 있다.
  3. 확장된 규칙이 확장하기 전의 규칙과 선택자 점수가 같기 때문에 규칙을 어디서 선언하느냐가 중요하게 된다.

그 밖에 참고한 문헌