Skip to content
This page has been auto-translated and may contain errors.View in English

CSS 조직화 및 확장

docs.scrimba.com

새로운 프로젝트에서 첫 번째 스타일시트를 작성하는 것은 즐겁습니다. 몇 백 줄 정도 진행되면 뭔가 변합니다: 한 버튼의 색상을 변경하면 다른 세 버튼도 변하고, 헤딩은 !important를 붙일 때까지 움직이지 않으며, 새로운 규칙마다 이전 규칙을 깨뜨릴 수 있을 것 같습니다. CSS 자체는 여전히 올바릅니다. 부족한 것은 이를 지탱하는 구조이며, 구문이 아닌 바로 이 구조가 스타일시트가 천 줄에서 유지 가능한지 십만 줄에서도 유지 가능한지를 결정합니다.

CSS가 확장하기 어려운 이유

CSS는 기본적으로 전역입니다. 작성하는 모든 규칙은 페이지 어디든 일치하는 모든 요소에 도달할 수 있습니다. p { color: navy; }를 작성하면 의도했는지 여부와 관계없이 전체 프로젝트의 모든 단락이 남색이 됩니다. 작은 페이지에서는 편리합니다. 프로젝트가 성장함에 따라 이것이 대부분의 문제의 근원입니다.

문제는 규칙이 충돌할 때 나타납니다. 두 스타일시트가 모두 p를 대상으로 하거나, 일반적인 규칙과 특정 규칙이 모두 같은 요소에 적용되면, 어느 것이 이기는지 알아내야 합니다. CSS가 작동하는 방식에서 이 메커니즘을 본 적이 있습니다: 브라우저는 특이성과 순서로 충돌을 해결합니다. CSS를 잘 확장하는 것은 대부분 처음부터 이러한 충돌을 만들지 않는 것입니다.

CSS는 기본 제공되는 스코핑이 없습니다. 규칙은 전역입니다: 페이지가 로드하는 모든 파일에서 선택자와 일치하는 모든 요소에 적용됩니다. 언어에 "이 규칙은 이 컴포넌트에 속한다"는 개념이 없기 때문에 한 컴포넌트의 스타일이 다른 컴포넌트에 도달하는 것을 막을 수 없습니다. 이 자유는 CSS를 빨리 시작하게 하고 성장하기 어렵게 만드는 것입니다.

코드베이스가 성장함에 따라 두 가지 힘이 당신을 밀어붙입니다. 더 많은 선택자는 더 많은 겹침을 의미하므로 규칙이 충돌하고, 브라우저는 CSS가 작동하는 방식의 규칙으로 각 충돌을 해결합니다: 먼저 특이성, 그 다음 소스 순서. 그리고 특이성은 상향하는 경향이 있습니다. 오늘날 충돌을 이기는 가장 빠른 방법이 약간 더 구체적인 선택자를 작성하는 것이기 때문이며, 이는 내일 이를 재정의해야 하는 것의 표준을 높입니다. 체크하지 않으면 누구도 !important 없이 이길 수 없는 선택자로 끝나게 되며, 이 시점에서 스타일시트는 유지 가능하다고 느껴지지 않습니다.

CSS는 하나의 평탄한 전역 네임스페이스를 제공합니다. 모든 선택자가 같은 공간에서 경쟁하고, 여러 선택자가 하나의 요소에 적용될 때 승리하는 선언을 선택하는 알고리즘인 캐스케이드는 각 충돌을 오리진으로 해결한 다음 특이성, 그 다음 소스 순서로 해결합니다. 언어 자체에 모듈 경계가 없으므로 한 컴포넌트를 위해 작성된 선택자는 다른 모든 컴포넌트의 요소와 자유롭게 일치할 수 있습니다. 이 장의 모든 확장 기술은 언어가 제공하지 않는 경계를 강제하기 위해 존재합니다.

실패 모드는 정확히 이름을 지을 가치가 있습니다. 아래의 습관들이 모두 이에 대한 방어이기 때문입니다. 압박 하에 적용되지 않는 규칙을 고치는 가장 빠른 방법은 선택자를 더 구체적으로 만드는 것입니다: 부모를 추가하고, 다른 클래스를 연결하고, id로 폴백합니다. 이들 각각은 즉각적인 충돌을 이기고 다음 오버라이드의 특이성 기준을 높이므로, 다음 재정의는 더 구체적이어야 합니다. 이것을 **특이성 전쟁**이라고 합니다: 선택자가 오직 상향으로만 이동하는 일방향 래칫으로, !important에서 끝나는 이유는 이를 이길 것이 더 이상 남지 않았기 때문입니다. 탈출은 이런 싸움을 더 영리하게 이기는 것이 아니라 특이성을 낮고 충분히 평탄하게 유지하여 거의 시작되지 않고, 언어가 이제 허용하는 곳에서는 이 장의 끝에서 다루어지는 캐스케이드 레이어로 특이성에서 완전히 순서를 이동하는 것입니다.

css
/* 페이지의 모든 단락에 도달하는 하나의 전역 규칙 */
p {
  color: navy;
}

/* 다른 곳의 두 번째 규칙, 같은 요소들에 경쟁 */
.notice p {
  color: crimson;   /* .notice 내에서 승리: 더 구체적 */
}
JunoCSS가 확장하기 어려운 이유 CSS 규칙은 전역입니다: 하나의 규칙이 페이지 전체의 요소들을 스타일링할 수 있으며, 이는 처음에는 편리하고 나중에는 복잡합니다. 프로젝트가 성장함에 따라 규칙이 충돌하기 시작하고, 브라우저는 특이성과 순서를 사용하여 승자를 선택합니다. CSS 조직화의 대부분은 규칙이 처음부터 서로 충돌하지 않도록 작성하는 것입니다.
JunoCSS가 확장하기 어려운 이유 CSS에는 스코핑이 없으므로 모든 규칙은 전역이고 일치하는 모든 요소에 자유롭게 도달할 수 있습니다. 코드베이스가 성장함에 따라 두 가지가 물어옵니다: 규칙이 충돌하고, 충돌을 해결하기 위한 빠른 수정이 항상 더 구체적인 선택자이므로 특이성이 상향합니다. 이 상향을 체크하면 나머지 확장이 훨씬 쉬워집니다.
JunoCSS가 확장하기 어려운 이유 CSS는 모듈 경계가 없는 하나의 평탄한 전역 네임스페이스이므로, 캐스케이드는 각 충돌을 오리진으로, [특이성](/css/selectors)으로, 그 다음 순서로 해결합니다. 함정은 특이성 래칫입니다: 각 빠른 오버라이드는 기준을 높이므로 다음 오버라이드는 더 높이 올라가야 하고, !important에서 하단에 도달합니다. 이 장의 모든 기술은 래칫이 회전을 시작하지 않을 정도로 특이성을 낮게 유지하는 방법입니다.

특이성을 낮고 평탄하게 유지

가장 유용한 단일 습관은 **클래스**로 스타일을 지정하고, 대부분의 경우 한 번에 하나의 클래스를 사용하는 것입니다. .card와 같은 클래스는 빠르게 적용되고, 재사용 가능하며, 나중에 필요하면 재정의하기 쉬습니다. 단일 클래스는 낮고 온화한 특이성 수준이기 때문입니다.

문제는 두 가지에서 옵니다: ID와 긴 선택자 체인입니다. #header와 같은 ID는 클래스보다 재정의하기 훨씬 어렵고, .sidebar ul li a와 같은 체인은 하나의 정확한 구조에 묶입니다. 원하는 곳 어디든 배치할 수 있는 일반 클래스를 선호하세요:

CSS를 유지 관리 가능하게 유지하기 위한 핵심 습관은 특이성을 낮고 평탄하게 유지하는 것입니다: 단일 클래스로 스타일을 지정하고, 특이성을 올리는 두 가지, ID와 깊은 자손 체인을 피하세요. 단일 클래스는 최적의 지점입니다. 의도한 것을 대상으로 하기에 충분히 구체적이고, 나중에 싸우지 않고 다른 단일 클래스로 재정의할 수 있을 정도로 약합니다.

ID는 클래스보다 훨씬 높은 점수를 매기므로, #id 규칙은 재정의하기 고통스럽고 당신을 상향으로 강제합니다. 긴 자손 체인은 다른 문제를 야기합니다: .sidebar nav ul li a는 특이성을 높이고 규칙을 하나의 정확한 HTML 구조에 용접합니다. 그래서 마크업이 변경되면 규칙이 깨집니다. 요소에 자신의 클래스를 주고 그것을 직접 대상으로 하세요.

특이성을 낮고 평탄하게 유지하는 것은 특이성 전쟁을 이기는 것이 아니라 방지하는 습관입니다. 낮다는 것은 각 규칙이 여전히 올바르게 선택하면서도 가능한 한 적게 점수를 받는다는 뜻입니다. 평탄하다는 것은 규칙이 같은 낮은 무게 주위에 군집하여 어느 것이든 다른 것을 소스 순서만으로 재정의할 수 있다는 뜻입니다. 거의 모든 것이 단일 클래스 선택자인 스타일시트는 이 속성을 가집니다: 이웃 위에 점수가 매겨진 것이 없으므로 아무것도 이기기 어렵습니다.

두 가지 구성이 평탄함을 깨뜨리고 둘 다 기본적으로 피할 가치가 있습니다. ID는 클래스보다 크기 순서로 더 많은 특이성을 기여하므로, 단일 #id 규칙은 모든 클래스 규칙 스택 위에 앉아 있고 다른 ID나 !important로만 이길 수 있습니다; 클래스로 스타일을 지정하고 ID를 프래그먼트 링크와 JavaScript 훅을 위해 예약하세요. 깊은 자손 체인은 선택자당 특이성을 높이고 규칙을 고정된 조상에 연결하므로, .sidebar nav ul li a는 재정의하기 어렵고 취약합니다: 마크업을 변경하면 조용히 일치를 멈춥니다. 다음 섹션의 방법론은 요소를 직접 이름 지을 수 있도록 하기 위해 존재하므로, 체인을 통해 찾기 위해 도달할 필요가 없습니다.

css
/* 선호: 단일 클래스, 낮고 평탄 */
.nav-link {
  color: navy;
}

/* 피하기: ID, 나중에 재정의하기 어려움 */
#nav-link {
  color: navy;
}

/* 피하기: 깊은 체인, 취약하고 더 높은 특이성 */
.sidebar nav ul li a {
  color: navy;
}
Juno특이성을 낮고 평탄하게 유지 클래스로 스타일을 지정하고, 대부분 한 번에 하나씩, card 또는 nav-link처럼. 단일 클래스는 빠르게 재사용하기 쉽고 나중에 재정의하기 쉬우며, 이것이 정확히 원하는 것입니다. #header와 같은 ID와 .sidebar ul li a와 같은 긴 체인을 피하세요. 둘 다 변경하기 훨씬 더 어렵습니다.
Juno특이성을 낮고 평탄하게 유지 단일 클래스는 최적의 지점입니다: 의도한 것을 칠 정도로 구체적이고, 싸움 없이 다른 클래스로 재정의할 수 있을 정도로 약합니다. ID는 특이성을 올리고 당신을 상향으로 끌어가며, .sidebar nav ul li a와 같은 깊은 체인은 마크업이 변경되는 순간 깨집니다. 규칙을 배치하기 어려울 때, 요소에 자신의 클래스를 주고 그것을 대상으로 하세요.
Juno특이성을 낮고 평탄하게 유지 낮고 평탄하다는 것은 모든 규칙이 비슷한 작은 무게 근처에서 점수를 매긴다는 뜻이므로 소스 순서만으로 모든 충돌을 해결할 수 있습니다. ID는 클래스 위의 크기 순서이고 !important 또는 다른 ID만 이기므로, 프래그먼트 링크와 JS 훅을 위해 유지하세요. 깊은 체인은 특이성을 올리고 규칙을 하나의 HTML 모양에 용접하므로, 요소를 직접 이름 짓는 것이 조상을 통해 이를 사냥하는 것을 이깁니다.

명명 규칙

클래스로 스타일을 지정하면 다음 질문은 이름을 무엇으로 지을 것인가 하는 것입니다. .blue 또는 .thing2와 같은 이름은 빠르게 분해됩니다. 클래스가 무엇을 하는지, 어디에 속하는지 아무것도 알려주지 않기 때문입니다. **명명 규칙**은 클래스를 이름 지을 합의된 방법이므로 이름이 클래스가 무엇을 하는지, 어디에 속하는지를 알려줍니다.

널리 사용되는 것을 BEM이라고 합니다. Block, Element, Modifier를 나타냅니다. 블록은 카드와 같은 컴포넌트입니다. 엘리먼트는 그 안의 부분으로, 두 개의 밑줄로 작성됩니다. 모디파이어는 변형으로, 두 개의 대시로 작성됩니다:

클래스를 스타일링 단위로 사용하면 명명이 이를 조직화된 상태로 유지하는 것이 됩니다. **명명 규칙**은 클래스 이름의 공유 패턴이며, 이름을 예측 가능하고 충돌 없게 만드는 것이 일입니다: 클래스 이름을 보면 어느 컴포넌트에 속하는지, 어느 부분을 스타일하는지 알 수 있으며, 두 컴포넌트는 절대로 같은 이름을 실수로 재사용하지 않습니다.

가장 널리 채택된 규칙은 BEM(Block, Element, Modifier)입니다. 블록은 컴포넌트(.card)이고, 엘리먼트는 두 개의 밑줄로 연결된 부분(.card__title)이며, 모디파이어는 두 개의 대시로 연결된 변형(.card--featured)입니다. 보상은 평탄한 특이성입니다: 모든 부분이 자신의 단일 클래스를 받으므로, .card__title에 도달하기 위해 자손 체인이 필요하지 않으므로, BEM과 저-평탄 습관은 서로를 강화합니다.

**명명 규칙**은 언어가 부족한 스코핑을 대체합니다. 클래스 이름 자체에 컴포넌트 경계를 인코딩함으로써, 언어 기능 없이 충돌 없는 자체 문서화 이름을 제공합니다: 클래스를 읽으면 이를 구성하는 컴포넌트, 부분 및 변형을 알 수 있습니다. 일관된 규칙은 이를 전달합니다; 가치는 일관성에 있지, 정확한 구두점이 아닙니다.

BEM(Block, Element, Modifier)이 가장 널리 사용됩니다. 블록은 컴포넌트(.card)를 이름 짓고, 엘리먼트는 이중 밑줄로 부분을 이름 짓고(.card__title), 모디파이어는 이중 대시로 변형을 이름 짓습니다(.card--featured). BEM이 단순히 명명 이상으로 그 무게를 당기는 것은 구성상 특이성을 평탄하게 유지한다는 것입니다: 모든 엘리먼트는 자신의 단일 클래스 선택자를 얻으므로, .card .title을 작성하는 대신 .card__title을 직접 대상으로 하고, 컴포넌트의 모든 규칙이 같은 무게에 앉습니다. 이것은 이전 섹션의 같은 저-평탄 속성이며, 이제 명명 체계에서 자유롭게 나옵니다. 비용은 HTML의 장황한 클래스 목록입니다. 대부분의 팀은 이것이 구매하는 예측 가능성을 위해 이를 수용합니다.

css
/* 블록: 컴포넌트 자체 */
.card { }

/* 엘리먼트: 블록의 부분, 두 개의 밑줄 */
.card__title { }
.card__body { }

/* 모디파이어: 블록의 변형, 두 개의 대시 */
.card--featured { }
html
<article class="card card--featured">
  <h2 class="card__title">주말 워크숍</h2>
  <p class="card__body">레이아웃에 대한 짧은 소개.</p>
</article>
Juno명명 규칙 명명 규칙은 클래스 이름이 무엇을 하는지 알 수 있도록 클래스를 이름 짓는 합의된 방법입니다. BEM이 일반적인 것입니다: card와 같은 블록, 두 개의 밑줄이 있는 card__title과 같은 그 안의 엘리먼트, 두 개의 대시가 있는 card--featured와 같은 변형. BEM을 사용할 필요는 없지만, 일관된 체계를 선택하고 그것을 고수하세요.
Juno명명 규칙 규칙은 클래스 이름을 예측 가능하고 충돌 없게 만듭니다. 그래서 이름이 이를 구성하는 컴포넌트와 부분을 알려줍니다. BEM이 널리 사용되는 것입니다: 블록 card, 엘리먼트 card__title, 모디파이어 card--featured. 또한 특이성을 평탄하게 유지합니다. 모든 부분이 자손 체인 대신 자신의 단일 클래스를 받기 때문입니다.
Juno명명 규칙 규칙은 CSS가 절대로 제공하지 않은 스코핑을 대체합니다: 컴포넌트 경계는 클래스 이름에 있으므로 이름은 충돌 없이 유지되고 자체 문서화됩니다. BEM은 .card, .card__title, .card--featured로 블록, 엘리먼트 및 모디파이어를 인코딩하며, 이의 실제 보상은 구성상 평탄한 특이성입니다. 모든 부분이 단일 클래스이기 때문입니다. 대가는 마크업의 장황한 클래스 목록이며, 이는 보통 예측 가능성만큼 가치가 있습니다.

파일 구조화

스타일시트가 성장함에 따라 하나의 긴 파일은 탐색하기 어려워집니다. 일반적인 해결책은 CSS를 몇 개의 폴더로 나누는 것입니다. 규칙이 수행하는 역할에 따라: 기본 스타일(body 및 제목과 같은 일반 요소의 기본값), 컴포넌트(카드, 버튼 및 기타 조각), 유틸리티(간격 또는 텍스트 정렬 클래스와 같은 작은 단일 목적 헬퍼).

파일을 나눌 때 한 가지 세부 사항이 중요합니다: 로드하는 순서입니다. 두 규칙이 같은 특이성을 가지면, 나중에 오는 것이 승리합니다. 따라서 나중에 로드된 스타일시트는 이전 규칙을 재정의할 수 있습니다. 가장 일반적인 것부터 가장 구체적인 것까지 파일을 로드하세요:

CSS를 역할별 폴더로 나누는 것은 성장하는 코드베이스를 탐색 가능하게 유지합니다. 일반적인 구조는 세 가지 그룹입니다: 기본(리셋 및 body, 제목 및 링크와 같은 요소 기본값), 컴포넌트(.card.btn과 같은 자체 포함 조각), 유틸리티(.text-center 또는 .mt-4와 같은 단일 목적 헬퍼).

이들 파일을 연결하거나 import하는 순서는 미용적이지 않습니다. 소스 순서는 캐스케이드 동점으로 결정됩니다: 두 규칙이 동일한 특이성을 가질 때, 나중의 규칙이 승리합니다. 그래서 당신은 최소에서 최대 특이성 순서로 로드합니다. 기본 먼저, 그 다음 컴포넌트, 그 다음 유틸리티가 마지막이므로, 유틸리티는 컴포넌트를 재정의할 수 있고 컴포넌트는 기본 기본값을 재정의할 수 있으며, 특이성을 강제로 올리지 않고도. 순서를 올바르게 얻는 것이 모든 것을 단일 클래스 특이성으로 유지하면서도 재정의가 예상대로 착지할 수 있게 합니다.

역할별로 파일을 구조화하는 것은 저-평탄 CSS를 규모에서 탐색 가능하게 유지하는 방법이며, 로드 순서는 하중을 담당합니다. 전통적인 분할은 기본(리셋 및 베어 요소 기본값), 컴포넌트(캡슐화된 조각, 파일당 하나), 유틸리티(원자 단일 속성 헬퍼)입니다. 순서 규칙은 캐스케이드에서 직접 나옵니다: 특이성이 의도적으로 평탄하게 유지되면, 소스 순서가 주요 동점이 되므로, 파일이 로드되는 순서는 동일 가중 규칙이 어느 것이 승리하는지 결정합니다.

이것이 순서가 최소에서 최대 의도 특이성으로 실행되는 이유입니다. 기본, 그 다음 컴포넌트, 그 다음 유틸리티이므로, 나중의 그룹이 이전 그룹을 특이성 범프 없이 재정의할 수 있습니다. .text-center 유틸리티는 컴포넌트의 자신의 텍스트 정렬을 이겨야 하며, 그것은 같은 무게로 마지막에 로드되기 때문에 할 수 있습니다. 이것은 작동하지만, 이것은 규율에 의해 강제된 규칙입니다: 언어의 아무것도 누군가가 유틸리티를 컴포넌트 전에 import하는 것을 중지하지 않으며 조용히 전체 체계를 반전시킵니다. 큰 팀에서 소스 순서에 의존하는 것은 정확히 이 이유 때문에 취약합니다. 이것이 마지막 섹션의 주제인 위치가 아닌 명시적으로 순서를 만드는 것을 동기화합니다.

css
/* main.css: 순서는 최소에서 최대 특이성으로 실행 */
@import "base/reset.css";        /* 요소 기본값 */
@import "base/typography.css";

@import "components/card.css";    /* 자체 포함 조각 */
@import "components/button.css";

@import "utilities/spacing.css";  /* 마지막에 로드되므로 재정의할 수 있음 */
@import "utilities/text.css";
Juno파일 구조화 CSS를 규칙이 수행하는 역할별로 폴더로 나누세요: 요소 기본값의 기본, 카드 및 버튼과 같은 조각의 컴포넌트, 작은 헬퍼의 유틸리티. 그 다음 로드 순서를 살펴보세요. 특이성이 동점이면 나중의 규칙이 승리합니다. 일반을 먼저, 구체적을 마지막으로 로드하세요. 그래서 헬퍼는 조각을 재정의할 수 있습니다.
Juno파일 구조화 역할별로 파일을 그룹화하세요: 기본, 컴포넌트, 그 다음 유틸리티. 최소에서 최대 특이성으로 로드하세요. 특이성이 동점일 때 소스 순서가 동점이므로, 마지막에 로드된 유틸리티가 특이성 범프 없이 컴포넌트를 재정의할 수 있습니다. 순서를 올바르게 얻는 것이 모든 것을 단일 클래스 무게로 유지하면서도 재정의가 착지합니다.
Juno파일 구조화 특이성이 의도적으로 평탄하면, 소스 순서가 주요 동점이 되므로 파일 로드 순서는 동일 가중 규칙이 어느 것이 승리하는지 결정합니다. 기본, 그 다음 컴포넌트, 그 다음 유틸리티는 나중의 그룹이 특이성 범프 없이 이전 그룹을 재정의합니다. 그 catch는 그것이 규율에 의해 유지되는 규칙이라는 것입니다: 유틸리티를 너무 빨리 import하고 당신은 전체 체계를 반전시킵니다. 이것이 정확히 다음 단계를 위치가 아닌 순서를 명시적으로 만드는 이유입니다.

캐스케이드를 명시적으로 만들기

지금까지 모든 것은 규칙에 의해 캐스케이드를 관리 가능하게 유지합니다: 낮은 특이성, 좋은 이름, 신중한 파일 순서. 더 깊이 나가면서 더 많은 것이 있으며, 여행 방향을 알 가치가 있습니다. 최신 CSS는 파일이 앉는 곳에 의존하는 대신 직접 순서를 제어하고, 더 많은 사람들이 같은 스타일시트에서 작업할 때 캐스케이드를 예측 가능하게 유지하는 방법을 제공합니다. 당신은 프로젝트가 성장함에 따라 이러한 도구들을 만날 것이고, 위의 습관들이 당신을 그것들을 위해 준비합니다.

지금까지의 기술은 간접적으로 캐스케이드를 관리합니다. 특이성과 소스 순서를 통해. 최신 CSS는 이를 직접 관리하게 합니다. 캐스케이드 레이어, @layer 규칙으로 작성되고, 명명된 순서 버킷입니다: 레이어를 미리 선언하면 이기기를 원하는 순서로, 모든 규칙은 레이어 안에 있으며 이전 레이어의 모든 규칙을 이기며, 특이성과 관계없이.

css
/* 승리 순서를 한 번 선언하세요. 최소 손실에서 최대 승리로 */
@layer base, components, utilities;

@layer components {
  .card { padding: 16px; }
}

@layer utilities {
  .p-0 { padding: 0; }   /* 동일 특이성에도 불구하고 .card 승리 */
}

나중의 레이어가 항상 승리하므로, 더 이상 파일 순서가 완벽할 필요가 없으며, 재정의를 강제하기 위해 !important를 거의 필요하지 않습니다. 이것이 실질적인 이점입니다: 레이어는 순서를 "어느 파일이 먼저 로드되었나"의 취약한 영역에서 이동하고 모든 사람이 읽을 수 있는 명시적 선언으로 이동합니다.

소스 순서는 위치적이기 때문에 취약합니다: import를 재정렬할 때까지 작동합니다. 캐스케이드 레이어, @layer 규칙은 특이성 위의 캐스케이드에 앉는 명시적 순서로 대체합니다. 레이어 순서를 한 번 선언하면, 캐스케이드는 특이성을 절대 보기 전에 레이어 순서를 참조하므로, 나중의 레이어의 규칙이 이전 레이어의 규칙을 이기며, 이전 규칙이 더 구체적이어도. 순서는 파일 위치의 부작용이 아니라 명명되고 읽을 수 있는 결정이 됩니다.

css
/* 한 줄이 전체 코드베이스의 승리 순서를 고칩니다 */
@layer reset, base, components, utilities;

@layer components {
  .card__title { font-size: 1.25rem; }
}

@layer utilities {
  .text-lg { font-size: 1.5rem; }   /* 승리: 유틸리티는 나중의 레이어 */
}

이것은 두 가지 습관을 재구성합니다. 첫 번째, 이것은 특이성 전쟁을 완화합니다: 레이어 순서가 특이성을 상위하므로, 당신은 충돌을 이기기 위해 더 구체적인 선택자에 도달하는 것을 멈추고, 당신은 거의 절대로 !important를 필요로 하지 않습니다. 이의 전체 일은 그 외의 방법을 이길 수 없는 특이성을 탈출하는 것이었습니다. (레이어는 !important 자체를 길들입니다, 그의 선행을 반전시켜서 이전 레이어의 중요한 선언이 승리하도록, 그러나 목표는 그것을 거의 필요하지 않게 이해하는 것이므로 이것은 잡학 질문으로 남습니다.) 두 번째, 이것은 두 가지 조직 스타일 사이의 오래 진행된 선택을 명확히 합니다: 많은 원자 단일 속성 클래스에서 페이지를 구성하는 유틸리티 먼저 접근, 그리고 하나의 의미론적 클래스 뒤에 번들되는 스타일을 하는 컴포넌트 접근. 대부분의 프로덕션 코드베이스는 둘을 실행하고, 레이어는 그들이 설계로 공존하게 합니다: 컴포넌트를 components 레이어에 두고 유틸리티를 나중의 utilities 레이어에 두세요, 그리고 유틸리티는 어느 쪽도 특이성을 상향하지 않고도 컴포넌트를 확실히 재정의합니다. 결정은 "캐스케이드 싸움에서 누가 이기나"가 아니라 "이 UI 조각에서 어느 것이 더 잘 읽히나"가 됩니다. 캐스케이드는 더 화나고 선택자가 아니라 레이어 순서에 의해 결정됩니다. 그 예측 가능성이 팀이 성장할 때 실제 보상입니다: 승리 순서는 모든 사람이 읽을 수 있는 하나의 선언이지, import 시퀀스에 대한 부족 지식이 아닙니다. 색상 및 간격과 같은 값을 이러한 레이어 전체에서 공유해야 할 때, 사용자 정의 속성은 중복하는 대신 한 번 정의하게 합니다.

Juno캐스케이드를 명시적으로 만들기 지금까지 모든 것이 습관으로 캐스케이드를 길들입니다: 낮은 특이성, 명확한 이름, 신중한 로드 순서. 더 멀리 나가면, CSS는 파일이 먼저 로드되는 것에 의존하는 대신 승리 순서를 직접 설정할 수 있게 합니다. 당신은 아직 그것들을 필요로 하지 않으며, 이 장의 습관들이 정확히 당신을 그것들을 위해 준비합니다.
Juno캐스케이드를 명시적으로 만들기@layer를 가진 캐스케이드 레이어는 명명된 순서 버킷입니다: 레이어 순서를 미리 선언하고 나중의 레이어는 특이성에 관계없이 이전 것을 이깁니다. 이것은 파일 순서가 완벽할 필요가 없다는 뜻이며, 당신은 거의 재정의를 강제하기 위해 !important를 필요로 하지 않습니다. 그것은 순서를 취약한 파일 위치에서 이동하고 모든 사람이 읽을 수 있는 하나의 줄로 이동합니다.
Juno캐스케이드를 명시적으로 만들기 캐스케이드 레이어는 특이성 위에 앉으므로, 나중의 레이어는 더 구체적인 규칙에도 불구하고 이전 것을 이기고, 이것은 특이성 래칫을 배포하고 대부분의 !important 사용을 은퇴합니다. 그들은 또한 유틸리티 먼저와 컴포넌트 스타일이 공존하게 합니다: 컴포넌트 하나에, 유틸리티 나중에, 그리고 유틸리티는 어느 쪽도 상향하지 않고도 재정의합니다. 팀이 성장할 때 승리는 순서가 하나의 읽을 수 있는 선언이라는 것이지, import 시퀀스에 대한 부족 지식이 아닙니다.