특이성 제어 – 스매싱 잡지

특이성 제어 – 스매싱 잡지

CSS는 거칠고 정말 야생입니다. 그리고 까다 롭습니다. 그러나 구체적으로 이야기합시다 특성.

CSS를 작성할 때 예상대로 적용되지 않는 스타일의 좌절에 직면하지 않은 것은 불가능합니다. 당신은 스타일을 적용하고, 효과가 있었고, 나중에 다른 스타일로 그것을 무시하려고 노력하고 … 아무것도 당신을 무시합니다. 다시, 특이성.

물론, 의지 할 수있는 옵션이 있습니다 !important 깃발이지만 우리 앞에있는 모든 개발자와 마찬가지로 항상 위험하고 낙담합니다. 그렇지 않으면 자신의 중요한 스타일과 싸우기 때문에 그 경로를 내려가는 것보다 특이성을 완전히 이해하는 것이 더 좋습니다.

특이성 101

많은 개발자들이 다른 방식으로 특이성의 개념을 이해합니다.

특이성의 핵심 아이디어는 브라우저에서 사용하는 CSS 캐스케이드 알고리즘이 둘 이상의 규칙이 동일한 요소와 일치 할 때 어떤 스타일 선언이 적용되는지를 결정한다는 것입니다.

그것에 대해 생각하십시오. 프로젝트가 확장됨에 따라 특이성 도전도 확장됩니다. 개발자가 추가한다고 가정 해 봅시다 .cart-button그런 다음 버튼 스타일이 사이드 바에서 사용되는 것이 좋지만 약간의 조정으로 사용하는 것이 좋습니다. 그런 다음 나중에 개발자 B가 추가됩니다 .cart-button .sidebar그리고 거기에서 미래의 변화가 적용됩니다 .cart-button 이에 의해 상인 될 수 있습니다 .cart-button .sidebar그리고 마찬가지로, 특이성 전쟁이 시작됩니다.

다른 요소의 더미로 표시되는 특정 장력
(큰 미리보기)

나는 개발자들이 CSS와 함께 제공되는 특이성 전투를 관리하는 데 사용한 다양한 전략을 목격하기에 충분히 CSS를 썼습니다.

/* Traditional approach */
#header .nav li a.active { color: blue; }

/* BEM approach */
.header__nav-item--active { color: blue; }

/* Utility classes approach */
.text-blue { color: blue; }

/* Cascade Layers approach */
@layer components {
  .nav-link.active { color: blue; }
}

이러한 모든 방법은 CSS 특이성을 제어하거나 최소한 유지하는 방법에 대한 다른 전략을 반영합니다.

  • 좋은: 명시 적으로 특이성을 단순화하려고합니다.
  • 유틸리티 우선 CS: 모든 원자를 유지하여 특이성을 우회하려고합니다.
  • CSS 캐스케이드 층: 계층 그룹에서 스타일을 구성하여 특이성을 관리합니다.

우리는 세 가지를 나란히 놓고 특이성을 어떻게 처리하는지 살펴볼 것입니다.

CSS 특이성을 제어하거나 최소한 유지하는 방법에 대한 다른 전략을 방해하는 차트
(큰 미리보기)

특이성과의 관계

나는 실제로 CSS 특이성의 전체 그림을 얻었다 고 생각했다. 일반적인 인라인과 마찬가지로 ID보다 큰 클래스보다 큰 인라인과 마찬가지로 태그보다 큰 클래스보다 큽니다. 그러나 CSS 캐스케이드가 어떻게 작동하는지에 대한 MDN 문서를 읽는 것은 눈을 뜨는 사람이었습니다.

클라이언트가 제공 한 오래된 코드베이스에서 작업 한 코드가 있습니다.

/* Legacy code */
#main-content .product-grid button.add-to-cart {
  background-color: #3a86ff;
  color: white;
  padding: 10px 15px;
  border-radius: 4px;
}

/* 100 lines of other code here */

/* My new CSS */
.btn-primary {
  background-color: #4361ee; /* New brand color */
  color: white;
  padding: 12px 20px;
  border-radius: 4px;
  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

이 코드를보고 .btn-primary 클래스는 이전에 작성된 특이성 체인에 대한 기회입니다. 사양이 진행되는 한, CSS는 첫 번째 선택기에게 특이성 점수를 제공합니다. 1, 2, 1: ID의 1 점, 두 클래스의 경우 2 점, 요소 선택기의 1 점. 한편, 두 번째 선택기는 다음과 같이 점수를 받았습니다 0, 1, 0 단일 클래스 선택기로만 구성되므로.

물론, 몇 가지 옵션이있었습니다.

  • 나는 할 수있다 사용 !important 속성에 ~에 .btn-primary 더 강력한 선택기에서 선언 된 것을 무시하려면 발생하는 순간은 어디서나 사용할 준비를하십시오. 그래서, 나는 그것을 피하고 싶습니다.
  • 나는 시도 할 수있다 더 구체적으로 진행됩니다그러나 개인적으로, 그것은 단지 다음 개발자에게 잔인합니다 (나도 나일 수도 있습니다).
  • 나는 할 수있다 기존 코드의 스타일을 변경하십시오그러나 그것은 특이성 문제에 추가되고 있습니다.
#main-content .product-grid .btn-primary {
  /* edit styles directly */
}

결국, 나는 전체 CSS를 처음부터 작성하게되었습니다.

레거시 버튼 대 현대 버튼
(큰 미리보기)

언제 둥지 소개되었고, 그런 식으로 특이성을 제어하려고 시도했습니다.

.profile-widget {
  // ... other styles
  .header {
    // ... header styles
    .user-avatar {
      border: 2px solid blue;
      &.is-admin {
        border-color: gold; // This becomes .profile-widget .header .user-avatar.is-admin
      }
    }
  }
}

그리고 마찬가지로, 나는 의도하지 않은 고해상도 규칙을 만들었습니다. 그것이 우리가 특이성 복잡성을 향해 표류 할 수있는 쉽고 자연스럽게

따라서 이러한 문제를 많이 저장하기 위해 항상 다음과 같은 원칙이 있습니다. 가능한 한 적은 특이성을 유지하십시오. 그리고 선택기 복잡성이 복잡한 체인이되면 모든 것을 다시 생각합니다.

BEM : 및 시스템

블록 요소 모디퍼 (BEM, 짧은)는 오랫동안 블록 주위에있었습니다. CSS를 작성하는 방법 론적 시스템으로 모든 스타일 계층을 명시 적으로 만들 수 있습니다.

/* Block */
.panel {}

/* Element that depends on the Block */
.panel__header {}
.panel__content {}
.panel__footer {}

/* Modifier that changes the style of the Block */
.panel--highlighted {}
.panel__button--secondary {}

내가 BEM을 처음 경험했을 때, 나는 그것이 못 생겼다는 반대 의견에도 불구하고 놀랍다 고 생각했다. 이중 하이픈이나 밑줄에 아무런 문제가 없었습니다. CSS를 예측할 수 있고 단순화했기 때문입니다.

BEM 방법 론적 시스템에 대한 그림
(큰 미리보기)

BEM이 특이성을 처리하는 방법

이 예를 살펴보십시오. BEM없이 :

/* Specificity: 0, 3, 0 */
.site-header .main-nav .nav-link {
  color: #472EFE;
  text-decoration: none;
}

/* Specificity: 0, 2, 0 */
.nav-link.special {
  color: #FF5733;
}

잘 : :

/* Specificity: 0, 1, 0 */
.main-nav__link {
  color: #472EFE;
  text-decoration: none;
}

/* Specificity: 0, 1, 0 */
.main-nav__link--special {
  color: #FF5733;
}

모든 선택기가 동일하게 생성 될 때 BEM이 코드를 예측할 수있게하는 방법을 알 수 있으므로 코드를 더 쉽게 유지 관리하고 확장 할 수 있습니다. 그리고 버튼을 추가하고 싶다면 .main-nav난 그냥 추가합니다 .main-nav__btn장애인 버튼 (수정 자)이 필요한 경우 .main-nav__btn--disabled. 캐스케이드와 싸울 필요가 없기 때문에 특이성은 낮습니다. 나는 단지 새로운 수업을 씁니다.

BEM의 이름 지정 원칙은 구성 요소가 고립 된 상태로 살았으며, CSS의 일부인 특이성 부분, 즉 효과적으로 작동했습니다. .card__title 클래스는 실수로 a와 충돌하지 않습니다 .menu__title 수업.

부족했다

나는 BEM의 아이디어를 좋아하지만 완벽하지는 않으며 많은 사람들이 그것을 알아 차렸다.

  • 클래스 이름은 얻을 수 있습니다 정말 긴.
  • 재사용 성이 우선하지 않을 수 있습니다그것은 고유 한 CSS 이데올로기와 다소 모순됩니다. 카드 내부의 버튼이 있어야합니다 .card__button 또는 글로벌을 재사용하십시오 .button 수업? 전자의 경우 스타일이 복제되고 후자는 BEM 엄격한 모델이 깨지고 있습니다.
  • 소프트웨어 개발의 핵심 고통 중 하나는 현실이되기 시작합니다. 이름 지정. 나는 당신이 이미 그것의 좌절감을 알고 있다고 확신합니다.

BEM은 좋지만 때로는 유연해야 할 수도 있습니다. 에이 하이브리드 시스템 (핵심 구성 요소에 BEM을 사용하지만 다른 곳에서 더 간단한 클래스)는 여전히 필요한만큼 특이성을 유지할 수 있습니다.

/* Base button without BEM */
.button {
  /* Button styles */
}

/* Component-specific button with BEM */
.card__footer .button {
  /* Minor overrides */
}

유틸리티 클래스 : 회피에 의한 특이성

이것을 원자 CSS라고도합니다. 그리고 전체적으로, 그것은 특이성을 피하십시오.

유틸리티 우선 클래스의 아이디어는 모든 유틸리티 클래스가 동일한 특이성을 가지며, 이는 하나의 클래스 선택기입니다. 각 클래스는 단일 목적을 가진 작은 CSS 속성입니다.

p-2? 패딩, 더 이상. text-red? 텍스트의 경우 색상 빨간색. text-center? 텍스트 정렬. 레고가 작동하는 방식과 같지만 스타일링을위한 것입니다. 원하는 외관을 얻을 때까지 클래스를 서로 쌓습니다.

제목이있는 그림 : Specifity 피피 - 한 번에 하나의 유틸리티
(큰 미리보기)

유틸리티 클래스가 특이성을 처리하는 방법

유틸리티 클래스는 특이성을 해결하지 않고 오히려 낮은 특이성의 BEM 이데올로기를 극단으로 가져갑니다. 거의 모든 유틸리티 클래스는 가능한 가장 낮은 특이성 수준의 (0,,, 1,,, 0). 이로 인해 재정의가 쉬워집니다. 더 많은 패딩이 필요한 경우, 범프 .p-2 에게 .p-4.

Another example:


다른 수업이라면 hover:bg-red-500추가로 CSS가 사용할 것인지 결정하는 주문이 추가됩니다. 따라서 유틸리티 클래스는 특이성을 피하지만 CSS 캐스케이드의 다른 부분이 등장하는데, 이는 외관 순서입니다. 마지막 일치하는 선택기는 승자라고 선언했습니다.

유틸리티 클래스 트레이드 오프

유틸리티 클래스에서 가장 일반적인 문제는 그 것입니다 그들은 코드를 못 생겼습니다. 그리고 솔직히, 나는 동의합니다. 그러나 구성 요소가 렌더링되지 않고 어떻게 보이는지를 상상할 수 있다는 것은 귀중한 일입니다.

재사용 가능성의 주장도 있습니다. 매번 자신을 반복합니다. 그러나 반복이 발생하면 해당 부분을 재사용 가능한 구성 요소로 바꾸십시오. 그것은 또한 진짜가 있습니다 제한 특이성에 관해서는 :

  • 브랜드 색상이 전 세계적으로 변경되고 코드베이스에 깊은 브랜드 색상이 변경되면 하나만 바꿀 수 없으며 다른 사람들이 기본 CSS처럼 팔로우 할 수 없습니다.
  • 원시 CSS에서 자연스럽게 발생하는 부모-자식 관계는 원자 유틸리티 클래스의 행동 방식으로 인해 창 밖으로 나옵니다.
  • 일부는 HTML 부분이 스타일링을위한 마크 업 및 CSS 부분으로 남겨 져야한다고 주장합니다. 이제 스캔 할 마크 업이 더 많아서 정리하기로 결정한 경우 :

Just like that, we’ve ended up writing CSS. Circle of life.

In my experience with utility classes, they work best for:

  • Speed
    Writing the markup, styling it, and seeing the result swiftly.
  • Predictability
    A utility class does exactly what it says it does.

Cascade Layers: Specificity By Design

Now, this is where it gets interesting. BEM offers structure, utility classes gain speed, and CSS Cascade Layers give us something paramount: control.

Anyways, Cascade Layers (@layers) groups styles and declares what order the groups should be, regardless of the specificity scores of those rules.

Looking at a set of independent rulesets:

button {
  background-color: orange; /* Specificity: 0, 0, 1 */
}

.button {
  background-color: blue; //* Specificity: 0, 1, 0*/
}

#button {
  background-color: red; /* Specificity: 1, 0, 0 */
}

/* No matter what, the button is red */

그러나 @layer내가 우선 순위를 정하고 싶다고 가정 해 봅시다 .button 클래스 선택기. 특이성 순서가 어떻게 진행되어야하는지를 형성 할 수 있습니다.

@layer utilities, defaults, components;

@layer defaults {
  button {
    background-color: orange; /* Specificity: 0, 0, 1 */
  }
}

@layer components {
  .button {
    background-color: blue; //* Specificity: 0, 1, 0*/
  }
}

@layer utilities {
  #button {
    background-color: red; /* Specificity: 1, 0, 0 */
  }
}

어떻게 @layer 공장, .button 이기 때문에 이길 것입니다 components 그래도 층이 가장 높은 우선 순위입니다 #button 특이성이 높습니다. 따라서 CSS가 일반적인 특이성 규칙을 확인하기 전에 레이어 순서가 먼저 존중됩니다.

W3C에서 사람들을 존중해야합니다. !important. 매력적인.

캐스케이드 레이어 뉘앙스

CSS 캐스케이드 레이어에 대해 이야기 할 때 전화 할 가치가있는 것들이 다음과 같습니다.

  • 특이성은 여전히 ​​게임의 일부입니다.
  • !important 예상과 다르게 행동합니다 @layer (그들은 반대로 작동합니다!).
  • @layers 선택기 별이 아니라 스타일-프로페티에 따라 다릅니다.
@layer base {
  .button {
    background-color: blue;
    color: white;
  }
}

@layer theme {
  .button {
    background-color: red;
    /* No color property here, so white from base layer still applies */
  }
}
  • @layer 쉽게 학대 할 수 있습니다. 20 개 이상의 레이어 선언이 괴물로 성장한 개발자가 있다고 확신합니다.

세 가지를 모두 비교합니다

이제 TL; Dr 사람들의 경우 여기에 BEM, 유틸리티 클래스 및 CSS 캐스케이드 레이어의 세 가지 비교가 있습니다.

특징 좋은 유틸리티 클래스 캐스케이드 레이어
핵심 아이디어 네임 스페이스 구성 요소 단일 목적 수업 캐스케이드 주문을 제어하십시오
특이성 제어 낮고 평평합니다 완전히 피합니다 레이어 우위로 인한 절대 제어
코드 가독성 명명으로 인한 명확한 구조 클래스 이름에 익숙하지 않은지 불분명합니다 층 구조가 따를 지 명확합니다
HTML의 진실성 적당한 클래스 이름 (오래 걸릴 수 있음) 빠르게 추가되는 많은 작은 수업 직접적인 영향은 없으며 CSS에만 유지됩니다
CSS 조직 구성 요소에 의해 재산 별 우선 순위에 따라
학습 곡선 규칙을 이해해야합니다 유틸리티 이름을 알아야합니다 픽업하기 쉽지만 CSS에 대한 깊은 이해가 필요합니다.
도구 종속성 순수한 CSS 종종 타사, 예를 들어 꼬리 바람에 따라 다릅니다 네이티브 CSS
리팩토링 용이성 높은 중간 낮은
최고의 사용 사례 설계 시스템 빠른 빌드 레거시 코드 또는 타사 코드가 필요합니다
브라우저 지원 모두 모두 모두 (IE 제외)

세 가지 중 각각은 달콤한 지점이 있습니다.

  • 좋은 다음과 같은 경우에 가장 좋습니다.
    • 일관성이 있어야하는 명확한 설계 시스템이 있습니다.
    • CSS에 대한 철학이 다른 팀이 있습니다 (BEM은 중간 근거 일 수 있음).
    • 스타일은 구성 요소간에 누출 될 가능성이 적습니다.
  • 유틸리티 클래스 다음과 같은 경우 가장 잘 작동합니다.
    • 프로토 타입이나 MVP와 같이 빠르게 구축해야하며
    • React와 같은 구성 요소 기반 JavaScript 프레임 워크 사용.
  • 캐스케이드 레이어 다음과 같은 경우 가장 효과적입니다.
    • 전체 특이성 제어가 필요한 레거시 코드베이스 작업,
    • 다른 소스에서 타사 라이브러리 또는 스타일을 통합해야합니다.
    • 장기 유지 보수를 갖는 대형 복잡한 응용 프로그램 또는 프로젝트 작업.

내가 그들을 선택하거나 순위를 정해야한다면, 나는 BEM을 사용하여 캐스케이드 레이어로 유틸리티 클래스로 갈 것입니다. 하지만 그게 나야!

그들이 교차하는 곳 (함께 일할 수있는 방법)

세 가지 중 캐스케이드 층은 다른 두 가지 전략과 함께 작동 할 수 있으므로 오케스트레이터로 간주되어야합니다. @layer CSS Cascade의 아키텍처의 기본 원조는 Cascade의 행동을 통제하기위한 방법론 인 BEM 및 유틸리티 클래스와 달리 CSS Cascade의 아키텍처입니다.

/* Cascade Layers + BEM */
@layer components {
  .card__title {
    font-size: 1.5rem;
    font-weight: bold;
  }
}

/* Cascade Layers + Utility Classes */
@layer utilities {
  .text-xl {
    font-size: 1.25rem;
  }
  .font-bold {
    font-weight: 700;
  }
}

반면에, 유틸리티 클래스와 함께 BEM을 사용하면 충돌이 발생합니다.

나는 모든 카드를 테이블 위에 올려 놓고 있습니다. 저는 유틸리티 우선 개발자입니다. 그리고 대부분의 유틸리티 클래스 프레임 워크 사용 @layer 무대 뒤에서 (예 : 꼬리 바람). 그래서 그 두 사람은 이미 가방에 함께 있습니다.

하지만 BEM을 싫어합니까? 별말씀을요! 나는 그것을 많이 사용했지만 필요한 경우에도 여전히 그렇습니다. 나는 단지 지명이 지친 운동이라고 생각합니다.

즉, 우리는 모두 다르며, 당신은 당신이 생각하는 것에 대한 반대 생각을 가질 수 있습니다. 그것은 정말로 중요하지 않으며 이것이이 웹 개발 공간의 아름다움입니다. 여러 경로가 동일한 대상으로 이어질 수 있습니다.

결론

따라서 BEM, 유틸리티 클래스 및 CSS 캐스케이드 레이어를 비교할 때 캐스케이드의 특이성을 제어하기위한 진정한 "승리"접근 방식이 있습니까?

우선, CSS 캐스케이드 레이어는 아마도 우리가 몇 년 동안 얻은 가장 강력한 CSS 기능 일 것입니다. CSS 기능 세트의 일부가 아닌 전략 인 BEM 또는 유틸리티 클래스와 혼동해서는 안됩니다.

그렇기 때문에 BEM을 캐스케이드 레이어 또는 유틸리티 클래스와 캐스케이드 레이어와 결합한다는 아이디어가 마음에 듭니다. 어느 쪽이든, 아이디어는 특이성을 낮게 유지하고 캐스케이드 레이어를 활용하여 해당 스타일에서 우선 순위를 설정하십시오..

스매싱 편집
(GG, YK)

출처 참조

Post Comment

당신은 놓쳤을 수도 있습니다