엔지니어링

Kibana UI의 컴포넌트화 1부 : 확장 가능한 CSS 코드

확장 가능한 CSS 코드

수만줄의 CSS 코드가 있습니다. 셀렉터는 8개 레벨까지 중첩되었습니다. 끝없는 오버라이딩 위의 오버라이딩이 계속됩니다… (헥헥) !잠시 주목하십시오! 이 끔찍한 괴물의 목을 어서 따버립시다! 상상만 해도 공포감에 고개를 떨구고 몸서리치는 분도 계시겠지만, 여기 Kibana 팀이 있습니다. 함께 이 괴물을 퇴치합시다! 뱃속 가득 커피를 충전하고 웹 개발자 도구를 장착하고 나아갑시다!

제 말이 너무 드라마틱한가요? 그렇게 느끼실 수 있지만, SCC의 확장성 문제는 현실입니다. Kibana team, 팀은 CSS 작성에 대한 정형화된 접근법을 통해 이 문제를 해결합니다.

  • Kibana UI를 컴포넌트로 간주합니다.
  • 클래스를 사용하여 CSS를 간소화 합니다.
  • BEM 명명 규칙을 사용하여 예측 가능성가독성이높은 마크업 및 CSS를 제작합니다.

컴포넌트로 UI 구성

컴포넌트 는 UI 의 블럭 조각들입니다. 버튼, form 필드, modal 창 등의 여러 가지 시각 요소가 존재하며 엔지니어는 이들을 모아 통합된 기능을 구축합니다.

컴포넌트 형태로 CSS를 작성하면 직접 작성하는 대신에 기존의 CSS 및 마크업을 이용할 수 있어 엔지니어의 삶이 더욱 편리해집니다.

컴포넌트는 특성상 그 스타일의 범위에 한계가 존재하고, 변경을 적용할 때 우연한 부작용이 발생할 가능성을 방지할 수 있어 컴포넌트로 작성된 CSS는 유지보수가 편리합니다.

컴포넌트의 한 예를 보여드리겠습니다. 이것을 우리는 패널이라고 합니다.

Our Panel component

컴포넌트는 시각적인 표기명과 코드 표기명을 가지며, 두 표기명 모두 같은 이름으로 지정되었습니다. 따라서 공통된 어휘들로 UI에 대해 얘기해볼 수 있습니다. 이제 디자이너, 엔지니어, 프로덕트 매니저가 "패널"이라고 할 때마다 대화에 참여 중인 모든 사람은 무엇을 이야기하고 있는지 정확하게 알 수 있습니다.

이제, Kibana에서 CSS를 단순하게 유지하는 방법을 알아본 후, 패널 구성 요소 뒤에 있는 CSS에 대해 살펴보겠습니다.

CSS 확장성의 기초는 단순성에서 시작합니다

단순한 코드는 부품의 수가 적고 의도를 명확하게 표시합니다. 코드의 논리 단위는 서로 분리되어 명시적이고 확실하게 상호 작용하며 명확한 경계를 갖습니다.

간단한 CSS에도 이와 같은 특성들이 있지만, CSS를 간소화하는 방법은 JavaScript나 Python과 같은 명령형 언어로 작성된 코드를 간소화하는 것과 다릅니다. Kibana 팀은 단순성을 위한 도구 상자에서 가장 강력한 도구는 CSS 클래스라는 것을 알게 되었습니다.

다음은 클래스를 사용하여 CSS를 간소화 하는 방법에 관한 일반적인 원칙들입니다.

클래스에 명시적으로 마크업 된 UI 렌더링을 매핑합니다. 컴포넌트를 미리 염두 해 두고 클래스에 이름을 붙이면 클래스명에 기능적인 의미가 추가됩니다. 이 클래스명은 마크업의 랜드마크나 도로 표지판과 같은 기능을 합니다. 브라우저를 계속해서 확인하지 않아도 마크업을 탐색하거나, 엘리먼트 간 관계를 이해하고 UI의 기능적인 이미지를 기억하는데에 도움이 됩니다.

셀렉터를 하나의 클래스로 제한합니다. 셀렉터가 2개 이상의 클래스에 연결되게 되면 컨텍스트에 대해 의존성을 가지게 됩니다. 즉, 스타일이 효과를 가지려면 엘리먼트들 간에 특별한 관계성이 필요하며, 마크업을 읽을 때 이러한 관계성을 찾기 어려울 수 있습니다. Kibana는 각 셀렉터를 하나의 클래스로 제한함으로써, 엘리먼트 간 관계를 간소화하고, 마크업을 더 쉽게 읽고, 컨텍스트에 변경을 가할 때 실수로 깨질 확률을 줄입니다.

**상속된 속성은 "리프(단말)" 노드에서만 사용합니다. ** CSS가 "폰트 크기"나 "색상"과 같은 속성을 엘리먼트에 적용하는 경우, 상속을 통해 하위 엘리먼트에도 적용됩니다. 이러한 부작용은 예측이 불가능하며 잘못 된 결과를 초래할 수도 있습니다. Kibana는 상속된 속성을 하위 엘리먼트가 포함되지 않은 UI 요소(예: 레이블, 버튼)에 대해서만 사용하도록 하여 UI 외형에 대한 상속을 방지하는 방법을 해결책으로 사용합니다.

이 원칙들이 패널 컴포넌트 코드에 적용되는 방식을 알아보겠습니다. 다음은 패널 생성에 대한 마크업입니다.

<div class="panel">
  <div class="panelHeader">
    <div class="panelHeader__title">
      Panel title
    </div>
  </div>

  <div class="panelBody">
    <!-- Content goes here -->
  </div>
</div>

마크업에서 클래스 이름을 사용해서 UI를 명확하게 지정한 것에 주목하십시오. 이것은 머리글과 본문이 포함된 패널 구성 요소인 게 확실합니다. Kibana 팀은 마크업 가독성을 개선함으로써 UI를 더 신속하고 안정적으로 구축할 수 있다는 것을 알게 되었습니다.

다음은 이 마크업의 외형을 정의하는 CSS입니다.

.panel {
  border-left: 2px solid #e4e4e4;
  border-right: 2px solid #e4e4e4;
  border-bottom: 2px solid #e4e4e4;
}

.panelHeader {
  display: flex;
  align-items: center;
  padding: 10px;
  height: 50px;
  background-color: #e4e4e4;
}

  /*
   * FYI, we indent child classes like this to emphasize its role
   * in the markup as a tightly-coupled child of the .panel class.
   */
  .panelHeader__title {
    font-size: 18px;
    line-height: 1.5;
  }

.panelBody {
  padding: 10px;
}

각 셀렉터를 단일 클래스로 지정한 것에 주목하십시오. CSS가 마크업에 대해 작용하는 방식과 비주얼 UI 구성 요소의 결과를 정말 쉽게 이해할 수 있습니다.

마지막으로, 상속된 성질을 가지는 유일한 셀렉터는 .panelHeader__title 클래스인 점에 주목하십시오. 이 셀렉터가 적용될 엘리먼트에는 패널 제목의 텍스트 이상의 하위 요소가 절대 포함되지 않다는 것을 압니다. 이는 CSS의 상속 모델이 도입될 수 있는 문제를 회피하는 방법을 보여주는 한 가지 사례입니다.

BEM 명명 규칙

BEM 명명 규칙은 2007년 Yandex에서 처음 개발된 후 널리 퍼져왔습니다. 이 블로그에서는 BEM에 대해 설명하지 않으므로, 관심이 있으시다면 Harry Roberts의 기사 또는 CSS-Tricks 기사에서 자세한 내용을 읽어보시길 바랍니다.

마크 업을 해독 할 때 컴포넌트를 구성하는 다양한 클래스 사이의 정리를 식별하는 방법이 필요했기 때문에 우리는 BEM을 CSS의 명명 규칙으로 선택했습니다. 이와 동시에, 각 클래스가 마크업에서 수행하는 역할을 구별할 수 있는 방법도 필요했습니다. 어떤 클래스는 구조적 역할을, 어떤 클래스는 다른 클래스를 수정하는 역할을, 어떤 클래스는 JavaScript를 통해 동적으로 적용되게 되어있습니다. BEM은 이러한 서로 다른 클래스를 구분해주는 패턴을 제공합니다.

BEM 작동 방식에 대한 자세한 내용은 위에 언급된 링크를 참조하십시오.

다음 단계: 컴포넌트화 프로세스

이 기사는 여러 파트로 연재되는 게시물의 1부입니다. 다음 화에서는 재사용성과 요소성을 고려한 컴포넌트의 설계 방법과 컴포넌트의 구성 요소화 과정에서 배운 것을 공유합니다. 읽어주셔서 감사합니다!

그리고 Kibana 팀에서는 언제나 훌륭한 인재를 찾고 있습니다. 관심 있는 분은 꼭 문의해 주십시오.