Young Blog

OOCSS(객체지향적 CSS) 소개


“콘텐츠가 왕이다”라는 말을 들어본 적이 있는가? 웹 개발자라던가, 콘텐츠 창작과 관련된 일을 하고 있다면 들어 보았을 가능성이 크다. 상당히 과도하게 사용되는 면이 있지만, 사이트 방문자를 끌어들이기 위해 중요한 것을 알려주는 사실적인 구절이다.

그러나 웹 개발자의 관점으로 보면, 속도가 왕이라고 주장하는 사람들이 있을 것이다. 나 또한 이 주장을 점점 옹호하게 되었다. 최근 몇 년 동안 기술적으로 숙련된 많은 프론트엔드 엔지니어들이 어떤 식으로 모범적인 성능 개선 방법을 사용하여 사용자 경험 향상을 끌어 낼 것인지에 대해 자신만의 의견을 내놓았다.

불행하게도 많은 개발자가 자바스크립트와 그 외 다른 분야의 성능에 대해 (괜찮은 근거를 곁들이며) 큰 관심을 보인 것에 비해, CSS는 논의 주제에서 제외된 편이다.

이번 포스트를 통해 OOCSS의 개념과 이것이 어떻게 웹 페이지의 성능을 향상하고 유지보수를 원활하게 하는지에 대해 소개함으로써 우리가 놓친 분야를 다루도록 하겠다.

OOCSS 원리

객체를 바탕으로 하는 다른 코딩 방법론과 마찬가지로, OOCSS의 목적은 코드의 재사용성을 높이고 최종적으로는 더 빠르고 효율적인 스타일 시트를 만들어서 유지보수를 원활하게 하는 데 있다.

CSS가 구린 게 아닙니다. 단지 쓰는 사람이 잘못 사용하고 있을 뿐. - 더글러스 크록포드

“CSS자바스크립트가 구린 게 아닙니다. 단지 쓰는 사람이 잘못 사용하고 있을 뿐이죠.” - 더글러스 크록포드

스타일에서 구조를 분리하기

스타일을 입힌 웹 페이지에 존재하는 요소들 대부분이 제각기 자신만의 시각적인 특성인 “스킨”(skins)을 가지고 있는데, 이 스킨은 페이지 안의 여러 곳에서 반복되어 나타난다. 예를 들어보면 웹 사이트의 브랜드 구축을 위해 사용되는 색상, 미묘한 그라디언트, 혹은 시각적인 테두리 요소 등이 있다. 한편으로는 “구조”(structure)라고 하는, 대부분 눈에 띄지 않는 특징들 역시 페이지 안에서 반복된다.

이렇게 상반되는 특징들이 클래스를 기반으로 하는 모듈로 추상화되면, 재사용이 가능해지고 어떠한 요소에도 적용할 수 있으며, 모두 같은 결과물을 만들어낼 것이다. 이제 방법론을 적용하기 전, 후의 코드를 살펴봄으로써 내가 말하고자 하는 바가 무엇인지 이해할 수 있을 것이다.

OOCSS 원리를 적용하기 전의 CSS 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#button {
width: 200px;
height: 50px;
padding: 10px;
border: solid 1px #ccc;
background: linear-gradient(#ccc, #222);
box-shadow: rgba(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, .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, .5) 2px 2px 5px;
}

위의 세 가지 요소들은 개별적으로 고유한 스타일을 가지고 있으며, 스타일 정의를 위해 재사용이 불가능한 ID 선택자를 사용했다. 그러면서도 이들 사이에서는 몇 가지 공통적인 스타일 선언문이 존재한다. 아마 브랜딩 목적이거나 디자인 통일을 위한 것일 가능성이 크다.

잠시 생각을 해 본 결과, 공통 스타일을 추상화하여 코드를 다음과 같이 바꿀 수 있었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.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, .5) 2px 2px 5px;
}

이제 모든 요소가 클래스를 사용하고, 공통으로 적용되는 스타일은 재사용 가능한 “skin”이라 하는 클래스에 들어감으로써 불필요하게 중복되는 코드가 없어진다. 이제 해야 할 일은 그저 “skin” 클래스를 모든 요소에 적용하는 일이다. 위의 코드 예시에서 전자와 후자는 똑같은 화면을 보여주지만 단지 달라진 것은 코드량이 줄어들었고 재사용이 가능해졌다는 점이다.

컨테이너와 콘텐츠를 분리하기

OOCSS 깃허브 위키 페이지에 서술된 두 번째 원리는 바로 컨테이너와 그 안에 있는 콘텐츠를 분리하는 것이다. 이 원리가 중요한 이유를 설명하기 위해 예시 CSS를 들어보겠다.

1
2
3
4
5
6
7
#sidebar h3 {
font-family: Arial, Helvetica, sans-serif;
font-size: .8em;
line-height: 1;
color: #777;
text-shadow: rgba(0, 0, 0, .3) 3px 3px 6px;
}

위의 코드는 #sidebar 요소의 자식 요소 중 h3에 무조건 적용될 것이다. 그렇지만 이 스타일을 꼬리말(footer) 영역에 속하는 h3에도 적용하고 싶은데, 폰트 크기와 텍스트 그림자만 수정해서 적용하고 싶은 상황이라면 어떻게 해야 할까?

아마 다음과 같은 코드를 작성해야 할 것이다.

1
2
3
4
5
6
7
8
9
10
11
#sidebar h3, #footer h3 {
font-family: Arial, Helvetica, sans-serif;
font-size: 2em;
line-height: 1;
color: #777;
text-shadow: rgba(0, 0, 0, .3) 3px 3px 6px;
}
#footer h3 {
font-size: 1.5em;
text-shadow: rgba(0, 0, 0, .3) 2px 2px 4px;
}

더 헛다리 짚으면 코드가 다음과 같아질 수도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#sidebar h3 {
font-family: Arial, Helvetica, sans-serif;
font-size: 2em;
line-height: 1;
color: #777;
text-shadow: rgba(0, 0, 0, .3) 3px 3px 6px;
}
/* 중간 코드 생략... */
#footer h3 {
font-family: Arial, Helvetica, sans-serif;
font-size: 1.5em;
line-height: 1;
color: #777;
text-shadow: rgba(0, 0, 0, .3) 2px 2px 4px;
}

이제 쓸데없이 스타일을 중복 적용하고 있는 상황이 되어버렸고, 이를 눈치채지 못하고 있을 수도 있다. (아니면 아예 신경 쓰고 있지 않거나) OOCSS를 적용한다면, 서로 다른 요소 간에 공통으로 적용해야 할 스타일이 어떤 것인지, 또 이러한 특징을 모듈 혹은 객체로 분리하여 어디에서나 적용 가능하도록 만들어 볼 기회를 얻을 수 있다.

위의 예시처럼 자손 선택자를 사용하여 선언된 스타일은 재사용이 불가능하다. 특정한 컨테이너에 종속되기 때문이다. (위의 경우에는 사이드바 혹은 푸터 영역에 종속된다)

OOCSS의 클래스 기반 모듈 설계를 적용하면 어떠한 컨테이너 요소에도 종속하지 않는 스타일임을 확신할 수 있다. 다시 말해 HTML 구조가 어떻게 되어있는지 따질 필요 없이, 클래스를 문서 안의 어디에서든 재사용할 수 있다는 뜻이다.

실제 적용 예시

OOCSS 적용 방법에 관해 좀 더 설명해보기 위해, 최근에 나의 사이트 디자인을 수정하면서 사용한 방법과 비슷한 것을 예시로 들어보겠다. 사이트의 헤더 안쪽 요소 코드를 작성하고 나니 여기에 적용한 기본 구조 스타일을 페이지의 다른 부분에서도 다시 쓸 수 있을 거라고 생각했다.

다음 코드는 헤더 영역을 꾸미는 데 사용하려고 쓴 코드다.

1
2
3
4
5
6
7
8
.header-inside {
width: 980px;
height: 260px;
padding: 20px;
margin: 0 auto;
position: relative;
overflow: hidden;
}

위의 코드 중 몇몇 선언문은 .header-inside 요소에만 유일하게 적용했다. 하지만 그 나머지는 재사용 가능한 모듈로 꾸릴 수 있다. 따라서 구조적인 스타일을 추상화하여 고유한 클래스로 만들었다. 그 결과는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
.globalwidth {
width: 980px;
margin: 0 auto;
position: relative;
padding-left: 20px;
padding-right: 20px;
overflow: hidden;
}
.header-inside {
padding-top: 20px;
padding-bottom: 20px;
height: 260px;
}

.globalwidth 클래스에 속하는 스타일은 다음과 같다.

  • 고정 width
  • 마진을 사용하여 중앙정렬: auto
  • 자식 요소의 위치 컨텍스트 생성을 위한 relative 포지셔닝
  • 왼쪽, 오른쪽 패딩 20px
  • 클리어픽스 사용을 위해 overflow: hidden

이제 이 스타일을 또 다른 요소에 추가하고자 한다면 코드를 한 줄이라도 더 쓸 필요 없이 그저 이 클래스를 추가하기만 하면 된다.

위에서 예시로 든 구조적인 스타일은 내가 만든 웹사이트에서 중요한 콘텐츠 요소와 푸터 안쪽에 위치하는 요소에 적용했다. 디자인에 따라서 이 스타일을 헤더와 콘텐츠 사이에 나타나는 수평 내비게이션 요소나 고정 너비를 가지면서 중앙 정렬을 해야 하는 다른 요소에 적용할 수도 있다.

“globalwidth” 스타일을 적용하고자 하는 요소에 입힌 후의 마크업은 다음과 같을 것이다.

1
2
3
4
5
6
7
8
9
10
<header>
<div class="header-inside globalwidth">
</div>
</header>
<div class="main globalwidth">
</div>
<footer>
<div class="footer-inside globalwidth">
</div>
</footer>

일부 사람들은 이를 보고 HTML이 빽빽해졌다거나 구조에서 스타일을 분리해야 한다는 마크업 작성 원칙에 어긋난다고 생각할 것 같다.

그러나 OOCSS가 마크업에 끼칠 영향에 대한 논의는 잠시 옆으로 미뤄두고, 이러한 추상화 과정을 통해 위의 세 가지 요소에 적용된 공통 스타일을 유지 보수하는 것이 얼마나 쉬워졌는지에 대해 이견을 말할 사람은 없을 것이다.

미디어 객체

니콜 설리번(Nicole Sullivan)은 OOCSS 방법론의 선구자 중 한 명이다. 니콜은 미디어 객체(media object)라고 하는 재사용 가능한 모듈을 고안해냈는데 그녀의 설명에 따르면 이것을 사용함으로써 수백 줄의 코드를 줄일 수 있다고 한다.

설리반의 미디어 객체 소개 그림

미디어 객체는 크기에 상관없이 어떠한 콘텐츠도 적절하게 담을 수 있는 미디어 요소를 담아내기 때문에 OOCSS의 막강한 위력을 보여주는 훌륭한 예시이다. 객체 내부의 콘텐츠에 적용되는 스타일은 (더불어 미디어 요소 자체의 크기도) 변경될 수도 있지만, 미디어 객체에 자체적으로 적용된 공통 스타일은 불필요한 반복을 줄이는 데 도움이 된다.

OOCSS가 주는 혜택들

이미 OOCSS의 몇 가지 장점을 언급했지만, 좀 더 알아보도록 하자.

웹사이트 속도가 더 빨라진다.

OOCSS를 사용함으로써 얻을 수 있는 혜택은 꽤 분명하다. CSS 내에서 반복되는 스타일 선언문이 적을수록 파일 크기가 작아지며 이로 인해 리소스를 더 빨리 내려받을 수 있다.

마크업이 더 빽빽해지기 때문에 HTML 파일의 크기가 늘어나는 것은 사실이다. 하지만 대부분의 경우 마크업 때문에 생기는 성능 손실보다 스타일 시트 쪽에서 얻는 성능 향상이 월등하다.

알아두어야 할 다른 개념은 OOCSS 위키에서 소위 성능 사은품이라고 칭하는 것이다. 이 말인즉슨 우리가 매번 CSS에서 무엇인가를 재사용하면, 이것이 본질적으로 CSS 코드를 한 줄도 작성하지 않으면서 새로운 스타일 요소를 만들어내는 것과 같다는 뜻이다. 프로젝트의 크기가 크고 파일 전송량이 커지면, 이러한 “사은품”들이 성능 개선의 여지를 제공해주는 중요한 요소가 될 수도 있다.

스타일시트 관리가 가능해진다.

구체성(specificity)과 씨름하느라 계속해서 불어나는 스타일 시트 대신에 OOCSS를 사용함으로써, 관리가 쉬운 모듈화 된 코드를 얻을 수 있다. 이 모듈에서는 순수한 캐스케이딩이 중요하게 작동한다.

이미 운영되고 있는 사이트에 무언가를 새로 만들고자 할 때, 기존 코드에 어떤 것들이 있는지 보지도 않고 맨 밑에 새로운 스타일을 추가하는 일을 방지할 수 있다. 대신 이미 존재하는 스타일 모듈을 다시 쓰면 되고 이를 바탕으로 확장해나가면 된다.

이런 식으로 미래에 닥칠 일들을 생각하면서 작업을 하면, CSS 코드를 매우 조금만 작성하고도 전체 페이지를 만들 수 있다. 이미 존재하는 CSS 모듈이 나중에는 새로운 페이지의 바탕이 될 것이며, 그 어떤 새로운 CSS 코드라도 최소한으로 작성하게 될 것이다. 심지어 어떤 경우에는 CSS 작성을 할 필요도 없이 완전히 새로운 스타일을 적용한 페이지를 만들 수도 있을 것이다.

이렇게 관리 가능해진 스타일 시트는 견고성을 띄게 된다. 스타일을 모듈 단위로 짰기 때문에, OOCSS를 바탕으로 한 페이지는 새로 개발자가 와서 유지보수를 하더라도 깨질 가능성이 작다.

짚고 넘어갈 만한 것들

OOCSS는 개발 커뮤니티에 큰 파문을 일으켰고, 많은 논란의 여지를 남기고 있다. 여기서 몇 가지 OOCSS에 대한 오해를 바로잡고자 한다.

ID는 여전히 사용가능하다.

OOCSS의 방식대로 일을 진행하고자 결심했다면, 대부분 스타일이 ID 선택자 없이 클래스를 바탕으로 이루어질 것이다.

이러한 이유로 OOCSS는 ID 사용에 반대한다고 오도하는 주장이 많이 보이는데, 그렇지 않다.

ID 사용을 자제하라는 말을 좀 더 구체적으로 풀자면 ID를 선택자로 사용하지 말라는 뜻이다. HTML 내에서 자바스크립트나 부분 표시자(fragment identifier)로 사용하기 위해 ID 값을 사용하는 것은 OOCSS를 따르는 데 있어서 전혀 문제를 일으키지 않는다.

당연히 일부 경우에는 페이지를 통틀어 유일한 ID 값이 적용된 요소가 있을 것이다. 이런 경우, ID를 스타일 선택자로 사용함으로써 클래스 추가에 소모되는 몇 바이트를 줄일 수 있을 것이다. 그러나 이런 때에도 마찬가지로 후에 구체성과 씨름하는 경우가 생기지 않게 클래스를 이용하는 편이 훨씬 안전한 선택이다.

소규모 프로젝트에 적용하기

사이트나 앱의 규모가 작다면 OOCSS를 적용하기에는 과분하다고 생각할 수도 있다. 그렇기에 이 글을 OOCSS를 항상 사용하라고 주장하는 옹호의 글로 받아들이면 안 되고, 프로젝트마다 그 특성에 맞게 적용을 해야 한다.

그렇지만 최소한 OOCSS의 관점에서 모든 프로젝트를 살펴보는 것은 좋은 선택이라고 생각한다. 일단 한번 적용 방법을 익혀둔다면, 좀 더 큰 규모의 프로젝트를 수월하게 진행하여 분명한 이득을 취할 수 있을 것이다.

적용 가이드라인

OOCSS와 익숙해지는 데는 시간이 좀 걸릴 것이다. 필자 역시 여전히 노력하는 중이므로, 이 분야의 전문가가 되기에는 아직 멀었다.

다음 목록은 OOCSS를 도입하고자 할 때 도움이 될 만한 것들이다:

  • 자손 선택자 사용하지 말기 (예: .sidebar h3 사용 하지 말기)
  • ID를 스타일을 주기 위해 사용하지 말기
  • 요소에 클래스를 붙여서 사용하지 말기 (예: div.headerh1.title과 같은 것들)
  • 몇몇 특별한 경우를 제외하고는, !important 쓰지 말기
  • CSS Lint를 사용하여 CSS 검사해보기 (옵션 설정 가능)
  • CSS grids 사용하기

위에서 언급한 규칙이 적용되지 않을 사례가 분명 있을 것이지만, 전반적으로 좋은 개발습관을 길러줄 것이며 좀 더 용량이 작고 유지 보수하기 쉬운 스타일 시트를 만드는 데 도움이 될 것이다.

니콜 설리반(Nicole Sullivan) 팔로우하기

OOCSS에 대해 계속 알아보고 싶다면, 니콜 설리번을 제일 먼저 팔로우 해보자.

니콜은 자신의 블로그에 정기적으로 OOCSS에 대한 글을 올리면서 발표도 몇 번 했다. 다음은 그녀가 지금까지 한 발표 중 필자가 추천하는 것들이다.

결론

많은 사람이 OOCSS가 지금까지 배워 온 소위 “모범 사례”라 불리는 것들에 대치된다고 여기기 때문에 이 개념에 대한 두려움을 가지고 있다. 그러나 일단 한번 OOCSS를 사용함으로써 거시적인 혜택을 얻을 수 있다는 것을 깨달으면 많은 개발자들이 전향하리라고 확신한다.

전체적으로 보았을 때 OOCSS는 CSS 개발 분야에서 장래성이 밝으며, 좀 더 빠르고, 성능 좋고, 유지 보수하기 쉬운 웹 페이지를 만들기 위해 개발자들이 이 개념을 적어도 최소한 어느 정도까지는 프로젝트에 적용하기 시작해야 한다고 생각한다.

Comments