Mức độ cụ thể

The CSS Podcast – 003: Specificity (Podcast về CSS – 003: Tính cụ thể)

Giả sử bạn đang làm việc với HTML và CSS sau:

<button class="branding">Hello, Specificity!</button>
.branding {
  color: blue;
}

button {
  color: red;
}

Có hai quy tắc nhắm đến cùng một phần tử ở đây. Mỗi quy tắc chứa một phần khai báo muốn đặt màu cho nút: một quy tắc cố gắng tô màu nút màu đỏ và quy tắc còn lại cố gắng tô màu nút màu xanh dương. Nội dung khai báo nào được áp dụng cho phần tử này?

Việc hiểu thuật toán về mức độ cụ thể của CSS là chìa khoá để hiểu cách CSS quyết định giữa các nội dung khai báo cạnh tranh.

Tính cụ thể là một trong những giai đoạn khác biệt của thác nước, đã được đề cập trong mô-đun cuối cùng về thác nước.

Tính điểm mức độ cụ thể

Mỗi quy tắc bộ chọn trong một nguồn gốc sẽ được tính điểm. Bạn có thể coi mức độ cụ thể là tổng điểm và mỗi loại bộ chọn sẽ nhận được điểm cho tổng điểm đó. Nội dung khai báo từ các quy tắc có mức độ cụ thể cao nhất sẽ chiến thắng.

Với tính cụ thể trong một dự án thực tế, việc cân bằng là đảm bảo các quy tắc CSS mà bạn dự kiến sẽ áp dụng thực sự áp dụng, đồng thời thường giữ điểm số ở mức thấp để tránh sự phức tạp. Độ cụ thể chỉ nên ở mức chúng ta cần, thay vì nhắm đến độ cụ thể cao nhất có thể. Trong tương lai, có thể bạn sẽ cần áp dụng một số CSS thực sự quan trọng hơn. Nếu chọn độ cụ thể cao nhất, bạn sẽ làm cho công việc đó trở nên khó khăn.

Mức độ cụ thể không phải là số thập phân mà là một bộ ba bao gồm 3 thành phần: A, BC.

  • A: mức độ cụ thể giống như mã nhận dạng
  • B: tính cụ thể giống như lớp
  • C: mức độ cụ thể giống phần tử

Phương thức này thường được biểu thị bằng ký hiệu (A,B,C). Ví dụ: (1,0,2). Ký hiệu A-B-C thay thế cũng thường được sử dụng.

Sơ đồ cho thấy 3 thành phần của tính đặc hiệu (A,B,C). Đối với mỗi thành phần, sơ đồ sẽ cho biết thành phần đó đại diện cho nội dung gì và một số bộ chọn ví dụ ảnh hưởng đến thành phần đó.
Sơ đồ minh hoạ thành phần cụ thể mà các bộ chọn khác nhau ảnh hưởng đến.

So sánh các đặc điểm

Mức độ cụ thể được so sánh bằng cách so sánh ba thành phần theo thứ tự: mức độ cụ thể có giá trị A lớn hơn là cụ thể hơn; nếu hai giá trị A bằng nhau, thì mức độ cụ thể có giá trị B lớn hơn là cụ thể hơn; nếu hai giá trị B cũng bằng nhau, thì mức độ cụ thể có giá trị C lớn hơn là cụ thể hơn; nếu tất cả các giá trị bằng nhau, thì hai mức độ cụ thể bằng nhau.

Ví dụ: (1,0,0) được coi là có độ cụ thể cao hơn (0,4,3) vì giá trị A trong (1,0,0) (là 1) lớn hơn giá trị A trong (0,4,3) (là 0).

Bộ chọn ảnh hưởng đến mức độ cụ thể

Mỗi phần trong bộ ba độ cụ thể bắt đầu bằng giá trị 0, vì vậy, độ cụ thể mặc định là (0,0,0). Mỗi phần của bộ chọn sẽ tăng độ cụ thể, tuỳ thuộc vào loại bộ chọn, giá trị của A, B hoặc C sẽ tăng lên.

Bộ chọn chung

Chọn viên phổ quát (*) thêm không có độ cụ thể, để giá trị của nó ở độ cụ thể ban đầu của (0,0,0).

* {
  color: red;
}

Bộ chọn phần tử hoặc phần tử giả

Bộ chọn phần tử (loại) hoặc phần tử giả sẽ thêm tính cụ thể giống phần tử, làm tăng thành phần C thêm 1.

Các ví dụ sau đây có mức độ cụ thể tổng thể là (0,0,1).

Bộ chọn loại

div {
  color: red;
}

Bộ chọn phần tử giả

::selection {
  color: red;
}

Bộ chọn lớp, lớp giả hoặc thuộc tính

Bộ chọn lớp, lớp giả hoặc thuộc tính sẽ thêm tính cụ thể giống như lớp, làm tăng thành phần B thêm 1.

Các ví dụ sau đây có đặc điểm là (0,1,0).

Bộ chọn lớp

.my-class {
  color: red;
}

Bộ chọn lớp giả

:hover {
  color: red;
}

Bộ chọn thuộc tính

[href='#'] {
  color: red;
}

Bộ chọn mã nhận dạng

Bộ chọn mã nhận dạng sẽ thêm tính cụ thể giống mã nhận dạng, làm tăng thành phần C thêm 1, miễn là bạn sử dụng bộ chọn mã nhận dạng (#myID) chứ không phải bộ chọn thuộc tính ([id="myID"]).

Trong ví dụ sau, độ cụ thể là (1,0,0)

#myID {
  color: red;
}

Bộ chọn khác

CSS có nhiều bộ chọn. Không phải từ khoá nào cũng giúp tăng độ cụ thể. Ví dụ: chính lớp giả :not() không thêm gì vào việc tính toán độ cụ thể.

Tuy nhiên, các bộ chọn được truyền vào dưới dạng đối số sẽ được thêm vào phép tính độ cụ thể.

div:not(.my-class) {
  color: red;
}

Mẫu này có độ đặc trưng là (0,1,1) vì mẫu này có một bộ chọn loại (div) và một lớp bên trong :not().

Kiểm tra mức độ hiểu biết

Kiểm tra kiến thức của bạn về cách tính điểm theo mức độ cụ thể

a[href="#"] có đặc điểm gì?

(0,0,1)
a có giá trị (0,0,1), nhưng [href="#"] có giá trị (0,1,0).
(0,1,0)
Hãy thử lại! a có giá trị (0,0,1), nhưng [href="#"] có giá trị (0,1,0).
(0,1,1)
a có giá trị (0,0,1)[href="#"] có giá trị (0,1,1), tổng độ cụ thể là (0,1,1).

Các yếu tố không ảnh hưởng đến mức độ cụ thể

Có một số quan niệm sai lầm thường gặp về các yếu tố sau đây ảnh hưởng đến mức độ cụ thể.

Thuộc tính kiểu cùng dòng

CSS được áp dụng trực tiếp cho thuộc tính style của một phần tử không ảnh hưởng đến mức độ cụ thể vì đây là một bước khác trong loạt được đánh giá trước mức độ cụ thể.

<div style="color: red"></div>

Để ghi đè nội dung khai báo này từ trong một trang kiểu, bạn phải sử dụng cách khai báo thắng trong một bước trước đó của loạt.

Ví dụ: bạn có thể thêm !important vào đó để thuộc nguồn gốc !important do tác giả tạo.

Nội dung khai báo !important

!important ở cuối phần khai báo CSS không ảnh hưởng đến mức độ cụ thể, nhưng đặt phần khai báo đó vào một nguồn gốc khác, cụ thể là !important do tác giả tạo.

Trong ví dụ sau, tính cụ thể của .my-class không liên quan đến việc khai báo !important để giành chiến thắng.

.my-class {
  color: red !important;
  color: white;
}

Khi hai nội dung khai báo là !important, thì tính cụ thể lại xuất hiện, vì bước gốc từ thác nước chưa thể xác định được người chiến thắng.

.branding {
  color: blue !important;
}

button {
  color: red !important;
}

Tính cụ thể theo bối cảnh

Khi sử dụng bộ chọn phức tạp hoặc phức hợp, mỗi phần của bộ chọn đó sẽ tăng thêm mức độ cụ thể. Hãy xem xét mã HTML mẫu sau:

<a class="my-class another-class" href="#">A link</a>

Đường liên kết này có hai lớp. Quy tắc trong CSS sau đây có đặc điểm là (0,0,1):

a {
  color: red;
}

Nếu bạn tham chiếu một trong các lớp trong bộ chọn, thì bộ chọn đó hiện có tính cụ thể là (0,1,1):

a.my-class {
  color: green;
}

Thêm lớp khác vào bộ chọn, giờ đây, bộ chọn này có độ cụ thể là (0,2,1):

a.my-class.another-class {
  color: rebeccapurple;
}

Thêm thuộc tính href vào bộ chọn, thuộc tính này hiện có độ cụ thể là (0,3,1):

a.my-class.another-class[href] {
  color: goldenrod;
}

Cuối cùng,hãy thêm một lớp giả :hover vào tất cả các lớp đó, bộ chọn sẽ kết thúc bằng một đặc điểm của (0,4,1):

a.my-class.another-class[href]:hover {
  color: lightgrey;
}

Kiểm tra mức độ hiểu biết

Kiểm tra kiến thức của bạn về cách tính điểm theo mức độ cụ thể

Bộ chọn nào sau đây có độ cụ thể là (0,2,1)?

article > section
Các phần tử thêm tính cụ thể giống phần tử (thành phần `C`). Có 2 phần tử trong bộ chọn, khiến bộ chọn này có độ cụ thể là (0,0,2).
article.card.dark
Các phần tử thêm tính cụ thể giống phần tử (thành phần `C`) và các lớp thêm tính cụ thể giống lớp (thành phần `B`). Với 2 lớp và 1 phần tử, bộ chọn này có độ cụ thể là (0,2,1).
article:hover a[href]
Các phần tử thêm tính cụ thể giống phần tử (thành phần `C`), lớp giả và thuộc tính thêm tính cụ thể giống lớp (thành phần `B`). Có 2 bộ chọn phần tử (2 × (0,0,1)), một bộ chọn thuộc tính (có giá trị (0,0,1)) và một bộ chọn lớp (có giá trị (0,0,1)). Điều này khiến bộ chọn này có tổng độ cụ thể là (0,2,2).

Tăng tính cụ thể một cách thực tế

Giả sử bạn có một số CSS như sau:

.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

Với HTML có dạng như sau:

<button class="my-button" onclick="alert('hello')">Click me</button>

Nút có nền màu xám, vì bộ chọn thứ hai có tính cụ thể là (0,1,1). Nguyên nhân là do lớp này có một bộ chọn loại (button) là (0,0,1) và một bộ chọn thuộc tính ([onclick]) là (0,1,0).

Quy tắc trước đó – .my-button – bằng (0,1,0) vì quy tắc này có một bộ chọn lớp, cụ thể hơn (0,1,1).

Nếu muốn tăng cường quy tắc này, bạn có thể lặp lại bộ chọn lớp như sau:

.my-button.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

Bây giờ, nút này sẽ có nền màu xanh dương, vì bộ chọn mới nhận được một giá trị cụ thể (0,2,0)

Mức độ cụ thể giống nhau sẽ quay lại bước tiếp theo trong trình tự

Hãy tiếp tục với ví dụ về nút và chuyển đổi CSS thành:

.my-button {
  background: blue;
}

[onclick] {
  background: grey;
}

Nút có nền màu xám, vì cả hai bộ chọn đều có độ cụ thể giống hệt nhau(0,1,0).

Nếu bạn chuyển đổi các quy tắc theo thứ tự nguồn, thì nút này sẽ chuyển sang màu xanh dương.

[onclick] {
  background: grey;
}

.my-button {
  background: blue;
}

Điều này là do cả hai bộ chọn đều có cùng mức độ cụ thể. Trong trường hợp này, trình tự lồng nhau sẽ quay lại bước thứ tự xuất hiện.

Tài nguyên