웹 프론트엔드/CSS

[번역] CSS개선을 위한 SEM과 BIO의 결합

아로리(arori) 2019. 4. 25. 18:01
반응형

원문: Combining the Powers of SEM and BIO for Improving CSS

 

Combining the Powers of SEM and BIO for Improving CSS | CSS-Tricks

CSS is easy, some might argue, but that "easiness" can cause messy code. This is especially true through power of preprocessors like Sass or Less where,

css-tricks.com


CSS가 쉽다고 일부 사람들은 주장하겠지만, 오히려 그 “쉬움”이 코드를 지저분하게 할 수 있습니다. 특히 Sass나 Less와 같은 전처리기의 힘을 빌리면 지저분해지기 쉽습니다. 조심하지 않으면, 당신의 CSS는 쉬워지는게아니라 다루기 더 어려워집니다. Sass? 더 어렵다고? 이 Gist는 Sass 중첩 지옥을 보여주는 좋은 예시입니다.

만약 당신의 Sass코드도 비슷하게 보인다면, SEM과 BIO로 코드를 향상시킬 수 있습니다. 지금부터 그 CSS 기술을 소개하겠습니다!

이 글에서는 아래에 있는 코드 예제를 사용해서, SEM과 BIO가 어떻게 동작하는지, 어떻게 CSS 전략을 향상시키는지 설명합니다.

See the Pen SEM & BIO by Ryan Yu (@iamryanyu) on CodePen.

 

 

일반적으로, SEM은 높은 레벨의 CSS 철학에 초점을 두고 있고, BIO는 SEM을 달성하기 위해 CSS를 더 잘 작성하도록 돕는 실질적인 기술입니다. SEM과 BIO의 주 목적은 CSS에서 이해해야 할 가장 중요한 개념 중 하나인 CSS 명시도를 보다 잘 핸들링하는 것입니다.

만든 이:  Nana Jeon

 

먼저, SEM에 대해 이야기해봅시다.

SEM

SEM은 다음의 줄임말입니다:

  • Scalable
  • Extensible
  • Maintainable

이 세 가지 요소를 달성하려고 하면, CSS코드를 확실히 개선할 수 있고 컴포넌트를 훨씬 견고하게 만들 수 있습니다.

각 요소에 대해 자세히 얘기해 봅시다.

Scalable

재사용 가능한(Scalable) 컴포넌트는 코드를 변경하지 않고도 원하는 곳에 동일한 모양의 컴포넌트를 사용할 수 있어야 한다는 것을 의미합니다.

만든 이:  Nana Jeon

 

위의 코드펜 예제에서 헤더의 “Search” 버튼은 사이드바의 “Link”버튼과 정확하게 동일합니다. HTML 마크업을 비교해보면,

  • “Search” 버튼은 <button> 엘리먼트입니다.
  • 하지만 “Link” 버튼은 <a role="button" ...> 엘리먼트입니다.

… 그리고 마크업이 다르지만, 동일한 클래스(.c-btn.c-btn--yellow )를 사용해서 스타일은 동일합니다.

버튼 스타일은 재사용 가능하고, 부모나 형제 엘리먼트의 영향받지 않았기 때문에 원하는 곳에 동일한 모양의 컴포넌트를 추가할 수 있습니다. 이렇게 하면 완전히 다른 위치의 다른 컴포넌트를 변경해도 관련 없는 컴포넌트가 깨지는 골치 아픈 문제를 피할 수 있습니다.

출처:  Cartoon Network

 

Extensible

확장 가능한(Extensible) 컴포넌트는 처음부터 작성하거나, 기존 것을 부수지 않고도 쉽게 추가 기능을 제공할 수 있습니다.

CodePen의 예제를 다시 살펴 보겠습니다.

See the Pen SEM & BIO by Ryan Yu (@iamryanyu) on CodePen.

 

 

헤더와 메인 섹션에 있는 버튼은 3D효과 빼면 매우 비슷합니다. 이 경우에는, 코드베이스가 완전히 다른 두 세트의 버튼을 만드는 대신, 일반 버튼 스타일에 3D 효과를 추가하여 확장할 수 있습니다.

푸터의 버튼도 동일합니다. 버튼의 색상과 크기가 다르더라도 새로운 기능 추가/다른 기능 제거해서 쉽게 확장할 수 있습니다.

만든 이:  Nana Jeon

 

Maintanable

과거의 우리가 작성한 CSS나 다른 사람이 작성한 CSS를 이해하는 것은 아마도 대부분의 프론트엔드 개발자들이 직면하게될 가장 큰 과제 중에 하나입니다. 멋지게 작성한 새로운 코드를 추가 하는 것보다 기존 코드를 이해하는 데 더 많은 시간을 소비할 때도 있습니다.

문제는 일반적으로 다음과 같습니다:

  • 어떠한 주석도 없음
  • 오버 엔지니어링(over-engineering)
  • 단일 원본 소스(single source of truth)가 아님
  • 코딩 규칙/모범 사례(best practice)가 없음
  • 또는 위의 내용 전부

만든 이:  Nana Jeon

 

SEM과 BIO를 통해, 코드를 확실히 개선하고 다른 사람들(과 우리를 포함해서!)을 더럽고 유지보수 불가능한 코드로부터 구할 수 있습니다.

BIO

CSS를 작성하는 것을 개선할 수 있는 훌륭한 기술들이 있습니다. 저는 BIO라는 줄임말을 구성하고 있는 서로 잘 어울리는 기술 세 가지를 발견했습니다.

  • BEM
  • ITCSS
  • OOCSS

만든 이:  Nana Jeon

 

많은 개발자/엔지니어들은 이미 이 유명한 기술을 알고 있겠지만, 각각의 기술을 살펴보고 제가 그 기술을 사용하는 방식에 대해 이야기하고 싶습니다.

BEM

BEM은 매우 인기있는 방법론이고, CSS와 Sass/Less에 대한 우리의 생각을 크게 개선하는데 도움을 주고 있습니다.

BEM은 다음의 줄임말입니다:

  • 블록(Block)
  • 엘리먼트(Element)
  • 수정자(Modifier)

만든 이:  Nana Jeon

 

위의 나쁜 예제처럼, 우리는 Sass/Less의 힘을 남용하다가 중첩 지옥에 빠지는 경향이 있습니다. 하지만 BEM을 사용하면, 한 개(혹은 두 개) 깊이의 중첩으로 유지해서 매우 낮은 CSS 명시도를 갖을 수 있게 합니다.

더 높은 CSS 명시도와 싸워본 적이 있다면, 승리하기 위해서는 얼마나 고통스러운지 알 것입니다.

예제로 다시 돌아가서, 다음과 같은 HTML 마크업을 보세요:

<div class="o-grid">
  <div class="o-grid__item o-grid__header">
    ...
  </div>
  <div class="o-grid__item o-grid__main">
    ...
  </div>
  <div class="o-grid__item o-grid__sidebar">
    ...
  </div>
  <div class="o-grid__item o-grid__footer">
    ...
  </div>
</div>

이 예제는 다음으로 구성됩니다:

  • 블록: .o-gird
  • 엘리먼트: .o-grid__item, .o-grid__header, o-grid__main, .o-grid__sidebar, o-grid__footer

BEM은 유니크한 클래스를 강조하는 네이밍 컨벤션을 제공하기 때문에, 다음과 같이 깊게 중첩하지 않아도 됩니다:

.o-grid {
  .o-grid__item {
    ...
  }
}

이것 대신, 낮은 깊이로 스타일을 정의 할 수 있습니다.

.o-grid__item {
  ...
}

이것이 BEM의 가장 큰 장점입니다. CSS 명시도를 낮춰 전체 CSS 코딩의 효율과 경험을 향상시켜줍니다.

BEM을 사용해도 나쁜 네이밍을 가끔 볼 수 있습니다. 주의를 충분히 기울이지 않으면, 다음과 같은 정말 긴 클래스 이름을 쓸 수 있습니다:

/* 으악! */
.o-grid__item-search-button-text-svg-icon {
  ...
}

클래스 이름을 지을 때, BEM의 핵심 컨셉을 기억하세요. 컴포넌트가 블록이고, 내부의 모든 엘리먼트는 각각 블록에 붙어있습니다.

다시 우리의 예제로 돌아가서, .o-grid__item-form대신 .o-grid__form이라고 이름짓겠습니다. 왜냐면 폼 자체가 별도의 컴포넌트이고, o-grid__item의 자식이 될 필요가 없기 때문입니다.

또한, 스타일을 더욱 효율적으로 컨트롤하기 위해, o-grid__item과 함께 또 다른 클래스 네임 o-grid__header을 추가하여 스타일을 확장했습니다. 또한, 버튼에는 OOCSS 방식의 BEM 스타일의 클래스가 포함되어 있습니다. OOCSS는 다음에 알아 볼 것입니다.

OOCSS

이미 이야기 했듯이, CSS 작성 방법을 개선하는데 도움을 주는 CSS 전략과 방법론이 많이 있습니다. 하지만, 많은 사람들이 스스로 하나의 방법론을 정해야한다고 강요하고 있습니다.

내 경험에 비추어 볼 때, 방법론을 결합시키는 것은 실제로 여러 세계의 좋은 점을 결합하여 장점을 향상시킬 수 있습니다. 예를 들어, 저는 개인적으로 BEM과 OOCSS은 함께 잘 동작한다는 것을 알게 되었습니다.

OOCSSObject Oriented CSS(객체 지향 CSS)의 약자로, 레고 블럭처럼 작동한다고 생각하면 됩니다:

출처:  Flickr

 

OOCSS는 각각의 파트를 개별적으로 생성한 다음에, 결합해서 컴포넌트를 만듭니다.

위의 예제에서, OOCSS 네이밍 컨벤션을 사용하여 버튼을 만들었습니다.

  • .c-btn
  • .c-btn--yellow
  • .c-btn--blue
  • .c-btn--3d
  • .c-btn--large

예제의 헤더에서 노란색 검색 버튼을 렌더링하기위해 다음 클래스를 결합합니다.

  • .c-btn
  • .c-btn--yellow

만약 메인 섹션에 3D 버튼을 두고싶다면, 우리는 3D 클래스, .c-btn--3d를 추가하면 끝입니다.

푸터의 파란색 버튼의 경우에는, 노란색 수정자를 파란색 수정자와 큰 수정자로 바꾸면 됩니다. 보시다시피, 버튼은 헤더 블록에 의존하지 않으므로 컴포넌트를 사용하고 용도를 바꾸는 데에 유연성을 높일 수 있습니다. 또한, 이렇게 함으로써 우리는 다른 컴포넌트나 패턴에 영향을 주지 않고 버튼을 구성할 수 있고, 다른 색상이나 모양과 같이 새로운 생김새를 쉽게 확장할 수 있는 장점을 얻을 수 있습니다.

다음은 OOCSS를 사용하여 변형한 다양한 버튼 모음의 예시입니다:

See the Pen Modern Button Collection by Ryan Yu (@iamryanyu) on CodePen.

 

 

BEM과 OOCSS외에도 ITCSS의 도움을 받아 CSS 전략을 더 개선할 수 있습니다. 그 방법은 다음에 살펴보겠습니다.

ITCSS

ITCSSInverted Triangle CSS(역삼각형 CSS) 약자입니다. 특정한 컴포넌트를 어떤 명시도로 접근할 것인지를 정하는 구조를 적용함으로써 CSS의 구성에 도움을 줍니다. Lubos Kmetko가 읽을 만한 ITCSS에 대한 훌륭한 개요를 작성했습니다.

이 Gist에서 ITCSS를 이용하여 스타일 명시도의 레벨로 그룹화해서 나누는 방법을 확인할 수 있습니다.

이 예제에 기반해서, 클래스에 네임스페이스를 추가하여 컴포넌트 이름을 짓는 방법을 알 수 있습니다. 예를 들어, “버튼” 컴포넌트는 “c”(.c-button)라는 접두사가 붙어서 컴포넌트임을 나타내며, 다른 항목으로 착각하지 않도록 합니다. 그렇게 함으로써, 프로젝트에서 일하고 있는 사람들은 그 특정 클래스의 기능과 속성을 변경하는 것이 다른 영역에 어떤 영향을 미치는지 알게 됩니다.

다음은 ITCSS의 모든 레벨을 보여주는 일러스트레이션입니다:

각 섹션을 살펴보겠습니다.

Settings

셋팅(Settings)은 일반적으로 CSS를 생성하지 않지만, 클래스에 적용되는 변수의 모음입니다. 예를 들면:

  • 베이스(Base)
  • 색상(Color)
  • 폰트(Typography)
  • 애니메이션(Animation)

Tools

툴(Tools)도 아직 CSS를 생성하지 않으며, 일반적으로 클래스의 속성을 작성/확장하는데 도움을 주는 전처리 함수를 말합니다.

  • 함수(Functions)
  • 플레이스홀더(Placeholders)
  • 믹스인(Mixins)

Vendors

벤더(Vendors)은 프로젝트에 사용되는 서드파티 스타일입니다. reset.css, normalize.css나 Foundation이나 Bootstrap 같은 것을 생각하면 됩니다.

이러한 스타일이 구조 상에 더 위쪽에 있는 이유는 필요에 따라 이런 스타일을 재정의 할 수 있기 때문입니다. 알고 있겠지만, 속성이 완전히 동일하다고 가정하고, 같은 클래스가 두 번 호출 되면 캐스케이딩 되어서 두번째 인스턴스의 속성을 렌더링합니다.

.btn--large {
  padding: 3em;
}

/* 이것이 이깁니다 */
.btn--large {
  padding: 5em;
}

사족으로, Sass에서 ~를 사용하여 node_modules폴더를 가리킬 수 있습니다. 그래서 스타일 에셋을 자신의 디렉터리로 이동시킬 필요 없이 원본 디렉토리에서 가져올 수 있습니다.

@import '~modern-normalize/modern-normalize';

Objects

객체(Objects)는 (네임스페이스: o-) 레이아웃과 같이 꾸미는 것보다 아이템을 정렬하는 디자인 패턴에 사용됩니다. 객체 클래스는 모든 페이지에서 사용되므로, 객체 클래스를 변경할 경우, 웹사이트의 전체 각 페이지에 영향을 미치므로 매우 주의해야 합니다.

제가 사용하는 가장 일반적인 오브젝트 클래스는 다음과 같습니다:

  • .o-page: 최상위 컨테이너로 보통 max-width: 100vwoverflow: hidden을 포함하고 있습니다.
  • .o-main: 메인 영역의 컨테이너.
  • .o-container: 컴포넌트의 컨테이너로 일반적으로 고정 폭을 가지고 있습니다.
  • .o-content: 실제 컨텐츠 영역에 추가적인 설정이 필요한 경우에 사용합니다.
  • .o-grid: 열 갯수가 다른 그리드 레이아웃이 필요한 경우.

또 다른 객체 클래스를 사용하고있습니까? 그렇다면 저에게 공유해주세요 😃

Elements

엘리먼트(Elements)는 (네임스페이스: e-)는 클래스의 이름에 따라 스타일링을 하지 않는 HTML 기본 엘리먼트입니다. 예를 들면, 우리는 .link클래스보다 <a>클래스에 기본 스타일을 지정해야합니다.

// 기본 링크 스타일에 대해 작동합니다.
a {
  text-decoration: none;

  &:hover {
    background-color: blue;
    color: white;
  }
}

// 기본 링크 스타일을 클래스로 제공하지 마세요.
.link {
  text-decoration: none;

  &:hover {
    background-color: blue;
    color: white;
  }
}

특히 WordPress와 같은 CMS(Content Management System)에서, 콘텐츠에 들어가는 링크에 매번 클래스를 추가하고 싶지 않기 때문에 작성합니다. 따라서 <a> 엘리먼트에 클래스 없어도 기본 스타일을 주므로 링크에는 여전히 보기 좋은 스타일이 적용되어 있습니다.

Components

컴포넌트(Components)는 (네임스페이스: c-) 웹 사이트의 일부를 구성하는 작은 기능입니다. 버튼, 아코디언 메뉴, 슬라이더, 모달 다이얼로그 등을 생각해보세요. 각 컴포넌트는 완전한 기능을 혼자 수행하며, 다른 컴포넌트에 의존하지 않습니다. 컴포넌트의 이름을 정할 때 이러한 점을 고려해야 합니다.

예를 들어, 위의 예제에서 메인 섹션의 버튼은 .c-main-button이라고 불러서는 안됩니다. main 섹션 내부에서 사용이 종속되고, 사이드 바와 같은 다른 위치에서의 사용하는 것을 제한하기 때문입니다. 버튼이 더 이상 페이지의 특정 섹션에 종속되어 있지 않기 때문에 .c-btn과 같은 것이 훨씬 좋습니다.

만약 추가 기능이 필요하다면, BEM 수정자 (ITCSS와 BEM의 힘의 결합!)나 곧 배울 Scope를 이용하여 속성을 확장할 수 있습니다.

Patterns

많은 개발자/엔지니어들이 컴포넌트패턴(Patterns)을 동의어로 사용합니다. 당신이 그것에 더 익숙해도 괜찮습니다. 이 두 용어를 나누는 것은 내 취향입니다.

일반적인 경험을 봤을 때, 패턴(Patterns)은 (네임스페이스: p-) 컴포넌트의 조합으로 생각하지만, 재사용할 수는 없습니다.

예를 들어, 아코디언 메뉴를 컴포넌트로 생각합니다. 이것은 자체적으로 재사용할 수 있는데, 이것은 아코디언이 버튼과 같은 다른 컴포넌트를 포함하고 있더라도 별다른 수정없이 웹사이트의 다른 장소에서 사용할 수 있습니다.

반면에, 헤더를 예를 들면 재사용 불가능하고 (헤더는 컨텐츠와 사이드바 영역에 사용되지 않음) 또한 검색 폼, 로고, 메뉴, 아코디언, 버튼과 같은 다른 컴포넌트들이 포함되기 때문에 패턴이 됩니다.

Scope

경고합니다. 나는 스코프(Scope)를 꼭 필요한 경우에 사용합니다. 스코프(네임스페이스: s-)의 목적은 특정한 목적을 위해 모든 스타일을 덮어 쓸 수있도록 높은 명시도를 주는 것입니다.

기억하세요. 만약 스코프 클래스를 많이 사용하는 경우, 너무 명시도가 높은 스타일을 작성하고 있는 것일 수 있습니다. 그리고 CSS 구조를 리팩토링하는 것을 고려해야 합니다.

다음은 스코프 클래스인, .s-home의 간단한 사용 예입니다:

.c-accordion {
  .s-home & {
    // 홈 페이지에서 특별히 배경색을 변경
    background-color: tomato;
  }
}

사족으로, 위의 예제는 스코프 클래스를 사용하는 대신 아코디언 메뉴의 수정자(예: .c-accordion–bg-tomato)를 제공하도록 리팩토링할 수 있습니다. 이것은 훨씬 확장성 있는 방법이며 컴포넌트를 더욱 모듈화합니다.

Utility

때로는 특정 장소의 특정 스타일에 대해서만 변경하고 싶을 수있습니다. 이 경우, 유틸리티(utility)클래스(네임스페이스: u-)가 전체 CSS구조를 변경하지않고 업데이트하는 것을 도울 것입니다.

예를 들어, 아코디언 메뉴 제목의 font-size는 32px로 설정됩니다.

.c-accordion__heading {      
  font-size: rem(32);        
}

그러나 글꼴의 크기가 사이트의 뉴스 섹션에서만 다르고 다른 곳에서는 바뀌지 않는다면, 상위클래스나 스코프 클래스를 이용하여 높은 명시도를 갖게 하는 대신 유틸리티 클래스를 적용할 수 있습니다.

<button aria-expanded="false" class="c-accordion__heading u-font-size--24" aria-controls="sect1" id="accordion1id" type="button">...</button>

.u-font-size--24 {       
  font-size: rem(24) !important;         
}

우리 모두 !important가 나쁘다는 것을 알지만, 저는 !important를 추가했습니다. 왜냐면 유틸리티 클래스를 사용할 때는, 특정한 스타일로 확실하게 업데이트하기 원할 때이기 때문입니다. 또한 유틸리티 클래스는 다른 클래스의 스타일을 덮어써야 하므로, !important가 유틸리티 클래스에서는 사실 잘 작동합니다. 즉, 유틸리티 클래스는 헬퍼로써의 역할을 해야합니다. CSS를 구성하는데 사용해서는 안됩니다.

스코프 클래스와 마찬가지로, 너무 많은 유틸리티 클래스를 사용하는 경우, 사이트 전체가 일관성있게 디자인이 되었는지 디자이너와 함께 확인해봐야 합니다.

추가적인 네임스페이스

위에서 언급한 네임 스페이스 외에도 제가 자주 사용하는 네임 스페이스가 두 개 있습니다:

  • is-: 이것은 블록이나 엘리먼트의 상태를 나타냅니다. 가장 일반적으로 사용되는 클래스는 네비게이션의 활성화된 링크(.is-active)입니다.
  • js-: 이것은 특정 엘리먼트가 자바스크립트 이벤트에 바인딩 되어 있음을 나타냅니다. 예를 들어, js-menu-click은 엘리먼트가 클릭 이벤트에 바인딩 되어 있음을 나타냅니다.

Linting

마지막으로 .stylelinteslint를 사용해서 규칙을 만드는 것은 코드의 질을 상당히 높여줄 수 있습니다.

프론트엔드 작업 과정에서, 이것은 단순히 권장하는 것이 아닙니다. 규칙을 지키도록 강제합니다.

이 방법으로, 우리는 코드의 품질이 언제나 최상의 상태를 유지하고, 미래의 당신을 포함한 다른 개발자들에게 더 나은 코드를 제공할 수 있습니다.

실제로

이 섹션에서는, 우리가 SEM과 BIO를 어떻게 사용할 수 있는지 논의하려고 합니다. 시작하기 위해 간단하고 실용적인 예를 만들어 보았습니다:

See the Pen Accordion used with SEM & BIO by Ryan Yu (@iamryanyu) on CodePen.

 

 

이 예제에서는 다음과 같은 용도로 사용할 수 있는 아코디언 메뉴를 만드는 것이 주 목적입니다:

  • 일반적이지만 메인 섹션에서 다른 색상 테마들을 가지는 아코디언 메뉴
  • 사이드 바 내의 메뉴
  • 푸터에서 소셜 미디어 아이콘을 보여주는 블록

우리가 달성하고자 하는 것은 다음과 같습니다:

  • (S)재사용 가능: 어떠한 코드도 바꾸지 않고 페이지의 어느 부분에나 추가될 수 있음
  • (E)확장 가능: 주요 기능을 바꾸지 않고 다른 기능을 제공할 수 있음
  • (M)유지보수 가능: 이해하기 쉽게 구성되어 있음

SEM을 달성하기 위해, BIO가 다음과 같이 사용되었습니다:

  • BEM: .c-accordion을 블록으로 사용하고 그 자식을 엘리먼트로 사용하였습니다. 또한 .c-accordion—light.c-accordion—dark와 같은 수정자를 사용하였습니다.
  • ITCSS: SASS 파일을 정렬하는 것은 CSS 명시도를 꽤 잘 처리해줍니다. 예를 들어 사이드 바의 아코디언 버튼은 class="c-accordion__trigger p-sidebar-menu__button" 를 갖고있고, 이는 패턴(p-)가 컴포넌트(c-)를 이슈 없이 덮어쓸 수 있게 합니다.
  • OOCSS: 아코디언 메뉴는 여러 클래스로 구성됩니다. 예를 들어 class="c-accordion c-accordion--dark c-accordion--single" 는 어두운 테마의 열려있는 패널 한 개를 만들어줍니다.

맺으며

나는 대학, 정부 기관, 유통 업체, 그 외 많은 웹사이트를 포함한 대부분의 프로젝트에서 이 접근법을 사용했습니다. 나는 모든 프로젝트를 성공적으로 고객에게 전달하였습니다.(고객이 승인할 때까지 거의 문제 없었고, 시간 내에 전달하는 데에도 거의 문제가 없었습니다.) 이 접근법이 저에겐 꽤나 효과가 있었고, 당신에게도 도움이 될 수 있을 것 같습니다.

말 하는 김에 더하자면, 기술은 항상 바뀌고 있으니(특히 프론트엔드에서) 당신이 잘 사용한 아이디어/접근법/전략에 대해 이야기 듣고 토론할 수 있으면 더 기쁠 것입니다. 댓글로 알려주세요!


Scalable, Extensible 모두 한국어로 번역하면 "확장 가능한"이란 뜻이라서 번역에 고민이 있었습니다. 구분을 위해서 Scalable은 "재사용 가능한" 정도로 정의해서 사용했습니다.

반응형