Bạn đã bao giờ rơi vào tình huống viết CSS, chắc mẩm rằng quy tắc của mình sẽ thay đổi màu sắc hay kích thước của một phần tử, nhưng rồi nhìn vào trình duyệt và… không có gì xảy ra? Phần tử đó vẫn giữ nguyên style cũ, mặc kệ những dòng code bạn vừa thêm vào. Đây là một trải nghiệm quen thuộc và đôi khi gây nản lòng cho nhiều lập trình viên web, từ người mới bắt đầu đến cả những người đã có kinh nghiệm. Thủ phạm đằng sau hiện tượng này thường chính là CSS Specificity – hay còn gọi là Độ ưu tiên/Độ đặc hiệu của CSS.

Việc hiểu và làm chủ CSS Specificity không chỉ là kỹ năng cơ bản mà còn là yếu tố then chốt để viết code CSS hiệu quả, dễ đoán và dễ bảo trì. Nó là quy tắc nền tảng quyết định xem style nào sẽ “thắng” khi có nhiều quy tắc cùng nhắm vào một phần tử. Trong bài viết này, chúng ta sẽ cùng nhau mổ xẻ khái niệm CSS Specificity, tìm hiểu cách trình duyệt tính toán độ ưu tiên, cách giải quyết xung đột và những phương pháp tốt nhất để bạn thực sự làm chủ được khía cạnh quan trọng này của CSS.
1. CSS Specificity Là Gì? Tại Sao Nó Quan Trọng?
CSS Specificity (Độ ưu tiên/Độ đặc hiệu) là một hệ thống quy tắc được trình duyệt web sử dụng để xác định xem quy tắc CSS nào sẽ được áp dụng cho một phần tử HTML cụ thể khi có nhiều quy tắc cùng định nghĩa các thuộc tính xung đột cho phần tử đó.
Hãy hình dung thế này: bạn có một phần tử <h1> và bạn viết hai quy tắc CSS khác nhau, một quy tắc đặt màu chữ là red và một quy tắc khác đặt màu chữ là blue. Trình duyệt cần một cơ chế để quyết định màu nào sẽ được hiển thị cuối cùng. CSS Specificity chính là cơ chế đó. Nó gán một “trọng số” hay “điểm ưu tiên” cho mỗi bộ chọn (selector) CSS. Bộ chọn nào có điểm Specificity cao hơn sẽ được ưu tiên áp dụng style của nó.
Nắm vững CSS Specificity mang lại nhiều lợi ích:
- Giải quyết xung đột hiệu quả: Bạn sẽ hiểu rõ tại sao một style lại ghi đè (override) lên style khác và biết cách kiểm soát thứ tự ưu tiên này.
- Gỡ lỗi (Debugging) nhanh chóng: Khi giao diện không hiển thị đúng như mong đợi, CSS Specificity thường là nguyên nhân gốc rễ. Biết cách tính toán độ ưu tiên giúp bạn xác định vấn đề nhanh hơn rất nhiều.
- Viết code dễ bảo trì: Hiểu rõ CSS Specificity giúp bạn viết code CSS có cấu trúc tốt, tránh việc tạo ra các bộ chọn quá phức tạp hoặc lạm dụng !important, làm cho code dễ đọc, dễ sửa đổi và mở rộng hơn trong tương lai.

2. Cách Trình Duyệt Xác Định Độ Ưu Tiên CSS
Trình duyệt không đánh giá độ ưu tiên một cách ngẫu nhiên. Nó tuân theo một hệ thống phân cấp rõ ràng dựa trên các loại thành phần tạo nên một bộ chọn CSS. Dưới đây là thứ tự ưu tiên từ cao xuống thấp:
- Style Nội Tuyến (Inline Styles):
- Định nghĩa: Các style được viết trực tiếp trong thuộc tính style của thẻ HTML (ví dụ: <p style=”color: red;”>).
- Độ ưu tiên: Cao nhất (chỉ thua !important). Chúng ghi đè hầu hết các quy tắc khác.
- Bộ Chọn ID (ID Selectors):
- Định nghĩa: Sử dụng ký tự # theo sau là giá trị ID của phần tử (ví dụ: #main-content).
- Độ ưu tiên: Rất cao. ID được thiết kế để là duy nhất trên một trang, do đó bộ chọn ID có trọng số lớn.
- Bộ Chọn Lớp (Class Selectors), Bộ Chọn Thuộc Tính (Attribute Selectors), Lớp Giả (Pseudo-classes):
- Định nghĩa: Bao gồm:
- Các lớp (ví dụ: .button, .nav-item).
- Các thuộc tính (ví dụ: [type=”submit”], [href^=”https://”]).
- Các lớp giả mô tả trạng thái hoặc vị trí (ví dụ: :hover, :focus, :nth-child(2n), :active).
- Độ ưu tiên: Trung bình. Đây là nhóm bộ chọn được sử dụng phổ biến nhất để styling.
- Định nghĩa: Bao gồm:
- Bộ Chọn Phần Tử (Element Selectors), Phần Tử Giả (Pseudo-elements):
- Định nghĩa: Bao gồm:
- Tên thẻ HTML (ví dụ: h1, p, div, a).
- Các phần tử giả cho phép style một phần cụ thể của phần tử (ví dụ: ::before, ::after, ::first-letter).
- Độ ưu tiên: Thấp nhất. Các bộ chọn này có tính tổng quát cao nhất.
- Định nghĩa: Bao gồm:
Lưu ý quan trọng:
- Bộ chọn Universal (*): Không có giá trị specificity.
- Các Combinator ( (hậu duệ), >, +, ~): Không có giá trị specificity, chúng chỉ kết hợp các bộ chọn khác.
- Lớp giả :not(): Bản thân :not() không có specificity, nhưng bộ chọn bên trong dấu ngoặc của nó thì có và được tính vào điểm tổng.
- Kế thừa (Inheritance): Các thuộc tính được kế thừa từ phần tử cha có độ ưu tiên bằng 0, nghĩa là bất kỳ quy tắc nào được định nghĩa trực tiếp cho phần tử đó (dù yếu đến đâu) cũng sẽ ghi đè lên giá trị kế thừa.
3. Tính Điểm CSS Specificity: Hệ Thống 4 Cột
Để định lượng và so sánh độ ưu tiên, trình duyệt (và chúng ta) có thể sử dụng một hệ thống tính điểm, thường được biểu diễn dưới dạng 4 giá trị (A, B, C, D):
- Cột A (Inline Styles): Là 1 nếu style được áp dụng nội tuyến, ngược lại là 0.
- Cột B (IDs): Số lượng bộ chọn ID trong selector.
- Cột C (Classes, Attributes, Pseudo-classes): Tổng số lượng bộ chọn lớp, thuộc tính và lớp giả.
- Cột D (Elements, Pseudo-elements): Tổng số lượng bộ chọn phần tử và phần tử giả.
Cách So Sánh Điểm:
Trình duyệt so sánh điểm Specificity của các bộ chọn từ trái sang phải (A -> B -> C -> D):
- So sánh giá trị ở Cột A. Bộ chọn nào có giá trị cao hơn sẽ thắng. Nếu bằng nhau, chuyển sang bước 2.
- So sánh giá trị ở Cột B. Bộ chọn nào có giá trị cao hơn sẽ thắng. Nếu bằng nhau, chuyển sang bước 3.
- So sánh giá trị ở Cột C. Bộ chọn nào có giá trị cao hơn sẽ thắng. Nếu bằng nhau, chuyển sang bước 4.
- So sánh giá trị ở Cột D. Bộ chọn nào có giá trị cao hơn sẽ thắng.
Điểm Mấu Chốt: Hệ thống này không phải là phép cộng cơ số 10. Một giá trị cao hơn ở cột bên trái luôn “mạnh” hơn bất kỳ giá trị nào ở các cột bên phải, bất kể giá trị đó lớn đến đâu.
- Ví dụ: (0, 1, 0, 0) (1 ID) luôn mạnh hơn (0, 0, 100, 0) (100 classes).
- Ví dụ: (0, 0, 1, 0) (1 class) luôn mạnh hơn (0, 0, 0, 1000) (1000 elements).
Ví dụ Tính Toán:
Hãy xem xét các bộ chọn sau và điểm Specificity của chúng:
<!DOCTYPE html>
<html>
<head>
<title>CSS Specificity Demo 2</title>
<style>
nav { border: 1px dashed blue; padding: 10px; } /* Visual aid */
ul { margin: 0; padding: 0; }
/* Quy tắc 1: (0, 0, 1, 1) */
li.item {
font-weight: normal;
padding: 5px;
list-style: none;
margin-bottom: 5px;
border: 1px solid #ccc;
}
/* Quy tắc 2: (0, 0, 2, 0) */
.item.active {
font-weight: bold; /* Bị ghi đè bởi quy tắc 4 */
}
/* Quy tắc 3: (0, 1, 1, 0) */
#main-nav .item {
padding: 10px; /* Ghi đè padding 5px */
}
/* Quy tắc 4: (0, 1, 2, 1) - Mạnh nhất */
#main-nav li.item.active {
background-color: #eee;
font-weight: bolder; /* Ghi đè bold */
border-color: #999;
}
/* Base link style */
a.nav-link {
color: blue;
text-decoration: none;
display: block; /* Dễ nhìn hơn */
}
/* Quy tắc 5: (0, 0, 2, 1) */
a.nav-link.current {
text-decoration: underline; /* Thắng text-decoration: none */
color: purple; /* Thắng color: blue */
}
</style>
</head>
<body>
<nav id="main-nav">
<ul>
<li class="item active"><a href="#" class="nav-link current">Trang chủ</a></li>
<li class="item"><a href="#" class="nav-link">Giới thiệu</a></li>
</ul>
</nav>
</body>
</html>

Trong ví dụ trên, thẻ li đầu tiên có class item và active:
- Nó sẽ nhận font-weight: bolder; từ Quy tắc 4 (vì có specificity cao nhất (0, 1, 2, 1)).
- Nó sẽ nhận background-color: #eee; từ Quy tắc 4.
- Nó sẽ nhận padding: 10px; từ Quy tắc 3 (vì Quy tắc 4 không định nghĩa padding, Quy tắc 3 là mạnh nhất tiếp theo có padding).
4. Quy Tắc Thứ Tự Nguồn (Source Order Rule)
Điều gì xảy ra nếu hai quy tắc có cùng điểm CSS Specificity? Lúc này, quy tắc Thứ Tự Nguồn sẽ được áp dụng:
Quy tắc nào được khai báo cuối cùng trong mã nguồn CSS sẽ thắng.
Điều này có nghĩa là nếu bạn có hai quy tắc với cùng selector hoặc cùng điểm specificity, quy tắc bạn viết sau (hoặc được import sau) sẽ ghi đè lên quy tắc trước đó.
<!DOCTYPE html>
<html>
<head>
<title>CSS Specificity Demo 3 - Source Order</title>
<style>
/* Quy tắc 1 - Specificity: (0,0,1,0) */
.action-button {
background-color: blue;
color: white;
padding: 12px 25px;
border: none;
border-radius: 4px;
font-size: 1em;
cursor: pointer;
}
/* Quy tắc 2 - Specificity: (0,0,1,0) - Xuất hiện sau */
.action-button {
background-color: green; /* Ghi đè màu nền */
}
</style>
</head>
<body>
<button class="action-button">Hành động (Nền phải xanh lá)</button>
</body>
</html>

5. Vũ Khí Tối Thượng (Và Nguy Hiểm): !important
CSS cung cấp một cách để bỏ qua hoàn toàn hệ thống Specificity và Source Order: đó là sử dụng khai báo !important. Khi bạn thêm !important vào cuối một giá trị thuộc tính, khai báo đó sẽ được ưu tiên áp dụng, bất kể điểm Specificity của selector thấp đến đâu.
/* Điểm: (0, 1, 0, 0) - Rất cao */
#special-button {
background-color: purple;
}
/* Điểm: (0, 0, 1, 0) - Thấp hơn, nhưng có !important */
.button {
background-color: red !important;
}
/* Kết quả: Nút có id="special-button" và class="button" sẽ có màu nền đỏ */
Giải quyết xung đột giữa các !important:
Nếu nhiều quy tắc cùng sử dụng !important cho cùng một thuộc tính trên cùng một phần tử, thì lúc này trình duyệt lại quay về áp dụng CSS Specificity và Source Order chỉ giữa các quy tắc có !important đó.
Cảnh báo: Nguy Cơ Của !important
!important giống như một “lựa chọn hạt nhân” trong CSS. Nó giải quyết vấn đề ngay lập tức nhưng để lại hậu quả lâu dài. Hãy tránh sử dụng !important hết mức có thể.
- Phá vỡ Cascade: Nó làm mất đi tính tầng lớp và dự đoán của CSS.
- Khó Ghi Đè: Cách duy nhất để ghi đè một !important là dùng một !important khác với specificity cao hơn hoặc đặt sau nó, dẫn đến “cuộc chiến !important” và code trở nên hỗn loạn.
- Khó Bảo Trì: Việc tìm hiểu tại sao một style lại được áp dụng trở nên cực kỳ khó khăn.
Chỉ nên dùng !important trong các trường hợp rất hiếm:
- Ghi đè style từ thư viện bên thứ ba không thể sửa đổi (giải pháp cuối cùng).
- Trong user stylesheet (cho phép người dùng tùy chỉnh).
- Tạm thời khi gỡ lỗi.
6. Gỡ Lỗi CSS Specificity Với DevTools
Công cụ tốt nhất để hiểu và gỡ lỗi CSS Specificity là Công cụ Phát triển (Developer Tools) của trình duyệt (thường là F12 hoặc Inspect Element).
Khi kiểm tra một phần tử:
- Tab Styles/Elements: Hiển thị tất cả các quy tắc CSS áp dụng cho phần tử đó, theo thứ tự độ ưu tiên (thường là từ cao xuống thấp).
- Gạch Ngang: Các thuộc tính bị ghi đè sẽ có đường gạch ngang qua.
- Nguồn: Cho biết quy tắc đến từ file nào, dòng nào.
- Tab Computed: Hiển thị giá trị cuối cùng được tính toán cho từng thuộc tính CSS của phần tử, và bạn có thể xổ ra để xem quy tắc nào đã định nghĩa giá trị đó.
Việc sử dụng DevTools giúp bạn trực quan hóa “cuộc chiến” specificity và hiểu rõ quy tắc nào đang thắng thế.

7. Mẹo Viết CSS Tối Ưu Specificity (Best Practices)
Để viết CSS hiệu quả và dễ quản lý hơn liên quan đến CSS Specificity:
- Giữ Specificity Càng Thấp Càng Tốt: Bắt đầu với các bộ chọn đơn giản nhất. Chỉ tăng độ phức tạp khi thực sự cần thiết để ghi đè hoặc nhắm mục tiêu chính xác hơn.
- Ưu Tiên Sử Dụng Class: Class là lựa chọn linh hoạt, có thể tái sử dụng và có độ ưu tiên vừa phải, dễ dàng ghi đè khi cần. Đây nên là công cụ chính của bạn.
- Hạn Chế Dùng ID Để Styling: ID có độ ưu tiên rất cao, gây khó khăn cho việc ghi đè. Hãy dành ID cho việc định danh duy nhất, anchor link hoặc nhắm mục tiêu bằng JavaScript.
- Tránh Style Nội Tuyến: Giữ CSS tách biệt khỏi HTML để code sạch sẽ và dễ quản lý hơn.
- Cẩn Thận Với Bộ Chọn Phần Tử Lồng Nhau Dài: Selector như nav ul li a span có thể có specificity cao không cần thiết và dễ bị ảnh hưởng nếu cấu trúc HTML thay đổi.
- Áp Dụng Phương Pháp Luận: Sử dụng các quy ước đặt tên và cấu trúc như BEM (Block, Element, Modifier) giúp giảm thiểu xung đột specificity một cách tự nhiên.
- Tuyệt Đối Tránh !important: Hãy xem nó như một “cờ đỏ” và chỉ dùng khi không còn lựa chọn nào khác sau khi đã cố gắng điều chỉnh specificity hoặc cấu trúc.
Kết Luận
CSS Specificity là một phần không thể thiếu của việc làm chủ CSS. Ban đầu có thể hơi khó nắm bắt, nhưng một khi bạn hiểu được các quy tắc về thứ tự ưu tiên (Inline > ID > Class/Attribute/Pseudo-class > Element/Pseudo-element), cách tính điểm và quy tắc thứ tự nguồn, bạn sẽ có khả năng kiểm soát giao diện trang web của mình một cách chính xác và hiệu quả hơn.
Hãy nhớ sử dụng Công cụ Phát triển của trình duyệt thường xuyên để kiểm tra và gỡ lỗi, đồng thời áp dụng các phương pháp tốt nhất để giữ cho CSS Specificity trong code của bạn luôn ở mức hợp lý. Làm chủ được CSS Specificity đồng nghĩa với việc bạn đang tiến một bước dài trên con đường trở thành một lập trình viên front-end giỏi.
Nguồn: https://www.youtube.com/watch?v=CHyPGSpIhSs