BEM 및 최신 CSS 선택기 PlatoBlockchain Data Intelligence를 사용하여 캐스케이드를 길들이세요. 수직 검색. 일체 포함.

BEM 및 최신 CSS 선택기로 캐스케이드 길들이기

벰. 프론트엔드 개발 세계의 모든 기술과 마찬가지로, BEM 형식으로 CSS 작성 양극화 될 수 있습니다. 그러나 그것은 – 적어도 내 Twitter 거품에서는 – 더 좋아하는 CSS 방법론 중 하나입니다.

개인적으로 BEM이 좋은 것 같고, 꼭 써봐야 한다고 생각합니다. 그러나 나는 또한 당신이 왜 그럴 수 없는지 이해합니다.

BEM에 대한 귀하의 의견과 상관없이 BEM은 몇 가지 이점을 제공하며, 가장 큰 이점은 CSS Cascade에서 특이성 충돌을 방지하는 데 도움이 된다는 것입니다. 그 이유는 올바르게 사용한다면 BEM 형식으로 작성된 선택자는 동일한 특이성 점수를 가져야 하기 때문입니다(0,1,0). 저는 수년에 걸쳐 많은 대규모 웹사이트(정부, 대학 및 은행을 생각해 보십시오)를 위한 CSS를 설계했으며 BEM이 정말 빛난다는 것을 알게 된 더 큰 프로젝트에서였습니다. 작성하거나 편집하는 스타일이 사이트의 다른 부분에 영향을 미치지 않는다는 확신이 있을 때 CSS 작성이 훨씬 더 재미있습니다.

특이성을 추가하는 것이 완전히 허용되는 것으로 간주되는 예외가 실제로 있습니다. 예를 들면: :hover:focus 의사 클래스. 그것들은 특이도 점수가 0,2,0. 다른 하나는 의사 요소입니다. ::before::after — 특이도 점수가 0,1,1. 하지만 이 문서의 나머지 부분에서는 다른 특정성 크립을 원하지 않는다고 가정해 보겠습니다. 🤓

그러나 나는 BEM에서 당신을 판매하기 위해 여기에 있는 것이 아닙니다. 대신 최신 CSS 선택기와 함께 사용할 수 있는 방법에 대해 이야기하고 싶습니다. :is(), :has(), :where(), 등 — 심지어 얻기 위해 배우기 통제 캐스케이드.

최신 CSS 선택자는 무엇입니까?

XNUMXD덴탈의 CSS 선택기 레벨 4 사양 요소를 선택하는 몇 가지 강력하고 새로운 방법을 제공합니다. 내가 가장 좋아하는 것 중 일부는 다음과 같습니다. :is(), :where():not(), 각각은 모든 최신 브라우저에서 지원되며 오늘날 거의 모든 프로젝트에서 안전하게 사용할 수 있습니다.

:is():where() 특이성에 영향을 미치는 방식을 제외하면 기본적으로 동일합니다. 구체적으로, :where() 항상 특이성 점수가 0,0,0. 그래, 심지어 :where(button#widget.some-class) 특이성이 없습니다. 한편, 특이점은 :is() 가장 높은 특이성을 가진 인수 목록의 요소입니다. 그래서 우리는 이미 우리가 작업할 수 있는 두 개의 최신 선택자 사이에 캐스케이드 랭글링 구분이 있습니다.

엄청나게 강력한 :has() 관계형 의사 클래스도 빠르게 브라우저 지원 확보 (그리고 이후 CSS의 가장 큰 새로운 기능입니다. 그리드, 내 소견에). 그러나 작성 당시 브라우저 지원은 :has() 아직 생산에 사용하기에 충분하지 않습니다.

내 BEM에 의사 클래스 중 하나를 추가하고…

/* ❌ specificity score: 0,2,0 */
.something:not(.something--special) {
  /* styles for all somethings, except for the special somethings */
}

이런! 특이성 점수가 보이시나요? 기억하세요. BEM을 사용하면 선택자가 모두 특정성 점수를 갖기를 원합니다. 0,1,0. 왜 0,2,0 나쁜? 확장된 이 동일한 예를 고려하십시오.

.something:not(.something--special) {
  color: red;
}
.something--special {
  color: blue;
}

두 번째 선택자가 소스 순서에서 마지막이지만 첫 번째 선택자의 더 높은 특이성(0,2,0)이 이기고 색상이 .something--special 요소는 다음으로 설정됩니다. red. 즉, BEM이 제대로 작성되었고 선택한 요소에 .something 기본 클래스와 .something--special HTML에서 수정자 클래스가 적용되었습니다.

부주의하게 사용하면 이러한 의사 클래스가 예상치 못한 방식으로 캐스케이드에 영향을 미칠 수 있습니다. 특히 더 크고 복잡한 코드베이스에서 골칫거리를 일으킬 수 있는 것은 이러한 종류의 불일치입니다.

댕. 그래서 지금 무엇?

내가 무슨 말을 했는지 기억해 :where() 특이성이 XNUMX이라는 사실? 우리는 그것을 우리의 장점으로 사용할 수 있습니다:

/* ✅ specificity score: 0,1,0 */
.something:where(:not(.something--special)) {
  /* etc. */
}

이 선택기의 첫 번째 부분(.something)의 일반적인 특이성 점수를 얻습니다. 0,1,0. 하지만 :where() — 그리고 그 안에 있는 모든 것 — 의 특이성을 가지고 있습니다. 0, 선택기의 특이성을 더 이상 증가시키지 않습니다.

:where() 둥지를 틀 수 있게 해준다

특이성에 대해 나만큼 신경 쓰지 않는 사람들(공평하게 말하면 아마도 많은 사람들일 것입니다)은 중첩과 관련하여 꽤 좋은 경험을 했습니다. 일부 평온한 키보드 스트로크로 다음과 같은 CSS를 사용할 수 있습니다(간결성을 위해 Sass를 사용하고 있습니다).

.card { ... }

.card--featured {
  /* etc. */  
  .card__title { ... }
  .card__title { ... }
}

.card__title { ... }
.card__img { ... }

이 예에서 우리는 .card 요소. "추천" 카드인 경우( .card--featured 클래스), 카드의 제목과 이미지는 다르게 스타일을 지정해야 합니다. 하지만, 우리처럼 지금 위의 코드는 시스템의 나머지 부분과 일치하지 않는 특이성 점수를 생성합니다.

완고한 특이성 괴짜가 대신 이렇게 했을 수도 있습니다.

.card { ... }
.card--featured { ... }
.card__title { ... }
.card__title--featured { ... }
.card__img { ... }
.card__img--featured { ... }

그렇게 나쁘지 않죠? 솔직히 이것은 아름다운 CSS입니다.

그러나 HTML에는 단점이 있습니다. 노련한 BEM 작성자는 수정자 클래스를 여러 요소에 조건부로 적용하는 데 필요한 투박한 템플릿 논리를 고통스럽게 알고 있을 것입니다. 이 예에서 HTML 템플릿은 조건부로 --featured 수정자 클래스를 세 가지 요소(.card, .card__title.card__img) 아마도 실제 예에서는 훨씬 더 많을 것입니다. 그것은 많은 if 진술.

XNUMXD덴탈의 :where() 선택기는 특정 수준을 추가하지 않고도 훨씬 적은 템플릿 논리를 작성하고 부팅할 BEM 클래스를 줄이는 데 도움이 될 수 있습니다.

.card { ... }
.card--featured { ... }

.card__title { ... }
:where(.card--featured) .card__title { ... }

.card__img { ... }
:where(.card--featured) .card__img { ... }

다음은 Sass에서 동일하지만(후행에 유의하십시오. 앰퍼샌드):

.card { ... }
.card--featured { ... }
.card__title { 
  /* etc. */ 
  :where(.card--featured) & { ... }
}
.card__img { 
  /* etc. */ 
  :where(.card--featured) & { ... }
}

다양한 하위 요소에 수정자 클래스를 적용하는 것보다 이 접근 방식을 선택해야 하는지 여부는 개인 취향의 문제입니다. 하지만 적어도 :where() 지금 우리에게 선택권을 줍니다!

비 BEM HTML은 어떻습니까?

우리는 완벽한 세상에 살고 있지 않습니다. 제어할 수 없는 HTML을 처리해야 하는 경우가 있습니다. 예를 들어 스타일을 지정해야 하는 HTML을 삽입하는 타사 스크립트입니다. 해당 마크업은 종종 BEM 클래스 이름으로 작성되지 않습니다. 경우에 따라 이러한 스타일은 클래스를 전혀 사용하지 않고 ID만 사용합니다!

다시 한번, :where() 우리의 등이 있습니다. 이 솔루션은 우리가 알고 있는 DOM 트리의 위쪽 어딘가에 있는 요소의 클래스를 참조해야 하기 때문에 약간 해킹적입니다.

/* ❌ specificity score: 1,0,0 */
#widget {
  /* etc. */
}

/* ✅ specificity score: 0,1,0 */
.page-wrapper :where(#widget) {
  /* etc. */
}

하지만 상위 요소를 참조하는 것은 약간 위험하고 제한적입니다. 해당 부모 클래스가 변경되거나 어떤 이유로 존재하지 않으면 어떻게 됩니까? 더 나은 (그러나 아마도 똑같이 해키한) 솔루션은 다음을 사용하는 것입니다. :is() 대신에. 의 특이성을 기억하십시오. :is() 선택기 목록에서 가장 구체적인 선택기와 같습니다.

따라서 우리가 알고 있는(또는 바라는!) 클래스를 참조하는 대신 :where(), 위의 예에서와 같이 구성된 클래스를 참조할 수 있으며 꼬리표.

/* ✅ specificity score: 0,1,0 */
:is(.dummy-class, body) :where(#widget) {
  /* etc. */
}

항상 존재하는 body 우리가 선택하는 데 도움이 될 것입니다 #widget 요소 및 존재 .dummy-class 같은 내부의 클래스 :is() 에게 제공 body 선택자 클래스와 동일한 특이성 점수(0,1,0)… 그리고 사용 :where() 선택기가 그보다 더 구체적이지 않도록 합니다.

그게 다야!

이것이 우리가 최신 특이성 관리 기능을 활용할 수 있는 방법입니다. :is():where() BEM 형식으로 CSS를 작성할 때 얻을 수 있는 특이성 충돌 방지와 함께 의사 클래스. 그리고 그리 멀지 않은 미래에, 일단 :has() Firefox 지원 획득 (이 글을 쓰는 시점에서 현재 플래그 뒤에서 지원됩니다.) :where()와 쌍을 이루어 특정성을 취소하고 싶을 것입니다.

BEM 이름 지정에 올인하든 안 하든 선택자 특정성에 일관성을 갖는 것이 좋다는 데 동의할 수 있기를 바랍니다!

타임 스탬프 :

더보기 CSS 트릭