Một trong những tính năng của trình xử lý trước CSS mà chúng tôi yêu thích hiện đã được tích hợp vào ngôn ngữ: lồng ghép các quy tắc kiểu.
Trước khi lồng, bạn cần khai báo rõ ràng từng bộ chọn, tách biệt với nhau. Điều này dẫn đến việc lặp lại, tệp kiểu lớn và trải nghiệm soạn thư bị phân tán.
.nesting { color: hotpink; } .nesting > .is { color: rebeccapurple; } .nesting > .is > .awesome { color: deeppink; }
Sau khi lồng nhau, bạn có thể tiếp tục sử dụng bộ chọn và nhóm các quy tắc kiểu liên quan vào bên trong.
.nesting { color: hotpink; > .is { color: rebeccapurple; > .awesome { color: deeppink; } } }
Việc lồng giúp nhà phát triển giảm nhu cầu lặp lại bộ chọn, đồng thời cùng định vị các quy tắc kiểu cho các phần tử có liên quan. Điều này cũng có thể giúp các kiểu khớp với HTML mà chúng nhắm đến. Nếu thành phần .nesting
trong ví dụ trước đã bị xoá khỏi dự án, bạn có thể xoá toàn bộ nhóm thay vì tìm kiếm các tệp cho các thực thể bộ chọn có liên quan.
Việc lồng có thể giúp: - Sắp xếp - Giảm kích thước tệp - Tái cấu trúc
Tính năng lồng nhau có trong Chrome 112 và bạn cũng có thể thử trong Bản dùng thử kỹ thuật Safari 162.
Làm quen với tính năng lồng ghép CSS
Trong phần còn lại của bài đăng này,hộp cát minh hoạ sau đây sẽ được dùng để giúp bạn hình dung các lựa chọn. Ở trạng thái mặc định này, không có mục nào được chọn và mọi mục đều hiển thị. Bằng cách chọn nhiều hình dạng và kích thước, bạn có thể luyện tập cú pháp và xem cú pháp đó hoạt động như thế nào.
Bên trong hộp cát là các hình tròn, tam giác và hình vuông. Một số có kích thước nhỏ, trung bình hoặc lớn. Các màu khác là xanh dương, hồng hoặc tím. Tất cả đều nằm bên trong phần tử chứa .demo
. Sau đây là bản xem trước các phần tử HTML mà bạn sẽ nhắm đến.
<div class="demo">
<div class="sm triangle pink"></div>
<div class="sm triangle blue"></div>
<div class="square blue"></div>
<div class="sm square pink"></div>
<div class="sm square blue"></div>
<div class="circle pink"></div>
…
</div>
Ví dụ về cách lồng
Tính năng lồng CSS cho phép bạn xác định kiểu cho một phần tử trong ngữ cảnh của một bộ chọn khác.
.parent {
color: blue;
.child {
color: red;
}
}
Trong ví dụ này, bộ chọn lớp .child
được lồng trong bộ chọn lớp .parent
. Điều này có nghĩa là bộ chọn .child
lồng nhau sẽ chỉ áp dụng cho các phần tử là phần tử con của các phần tử có lớp .parent
.
Bạn cũng có thể viết ví dụ này bằng ký hiệu &
để biểu thị rõ ràng vị trí đặt lớp mẹ.
.parent {
color: blue;
& .child {
color: red;
}
}
Hai ví dụ này có chức năng tương đương và lý do bạn có các tuỳ chọn sẽ trở nên rõ ràng hơn khi các ví dụ nâng cao hơn được khám phá trong bài viết này.
Chọn các vòng tròn
Đối với ví dụ đầu tiên này, nhiệm vụ của bạn là thêm các kiểu để làm mờ và làm mờ chỉ các vòng tròn bên trong bản minh hoạ.
Không lồng nhau, CSS hiện nay:
.demo .circle {
opacity: .25;
filter: blur(25px);
}
Với cách lồng nhau, có hai cách hợp lệ:
/* & is explicitly placed in front of .circle */
.demo {
& .circle {
opacity: .25;
filter: blur(25px);
}
}
hoặc
/* & + " " space is added for you */
.demo {
.circle {
opacity: .25;
filter: blur(25px);
}
}
Kết quả, tất cả các phần tử bên trong .demo
có lớp .circle
đều bị làm mờ và gần như không nhìn thấy:
Chọn bất kỳ hình tam giác và hình vuông nào
Nhiệm vụ này yêu cầu bạn chọn nhiều phần tử lồng nhau, còn gọi là bộ chọn nhóm.
Không lồng nhau, CSS hiện có hai cách:
.demo .triangle,
.demo .square {
opacity: .25;
filter: blur(25px);
}
hoặc sử dụng :is()
/* grouped with :is() */
.demo :is(.triangle, .square) {
opacity: .25;
filter: blur(25px);
}
Với cách lồng nhau, sau đây là hai cách hợp lệ:
.demo {
& .triangle,
& .square {
opacity: .25;
filter: blur(25px);
}
}
hoặc
.demo {
.triangle, .square {
opacity: .25;
filter: blur(25px);
}
}
Kết quả, chỉ các phần tử .circle
còn lại bên trong .demo
:
Chọn tam giác và hình tròn lớn
Nhiệm vụ này yêu cầu một bộ chọn phức hợp, trong đó các phần tử phải có cả hai lớp để được chọn.
Không lồng nhau, CSS hiện nay:
.demo .lg.triangle,
.demo .lg.square {
opacity: .25;
filter: blur(25px);
}
hoặc
.demo .lg:is(.triangle, .circle) {
opacity: .25;
filter: blur(25px);
}
Với cách lồng nhau, sau đây là hai cách hợp lệ:
.demo {
.lg.triangle,
.lg.circle {
opacity: .25;
filter: blur(25px);
}
}
hoặc
.demo {
.lg {
&.triangle,
&.circle {
opacity: .25;
filter: blur(25px);
}
}
}
Kết quả, tất cả hình tam giác và hình tròn lớn đều được ẩn bên trong .demo
:
Mẹo chuyên nghiệp về bộ chọn phức hợp và lồng nhau
Biểu tượng &
là bạn của bạn ở đây vì biểu tượng này cho thấy rõ cách nối các bộ chọn lồng nhau. Hãy xem ví dụ sau đây:
.demo {
.lg {
.triangle,
.circle {
opacity: .25;
filter: blur(25px);
}
}
}
Mặc dù đây là cách lồng hợp lệ, nhưng kết quả sẽ không khớp với các phần tử mà bạn có thể mong đợi.
Lý do là nếu không có &
để chỉ định kết quả mong muốn của .lg.triangle,
.lg.circle
kết hợp với nhau, thì kết quả thực tế sẽ là .lg .triangle, .lg
.circle
; bộ chọn con cháu.
Chọn tất cả các hình dạng trừ hình màu hồng
Tác vụ này yêu cầu một lớp giả lập chức năng phủ định, trong đó các phần tử không được có bộ chọn được chỉ định.
Không lồng nhau, CSS hiện nay:
.demo :not(.pink) {
opacity: .25;
filter: blur(25px);
}
Với cách lồng nhau, sau đây là hai cách hợp lệ:
.demo {
:not(.pink) {
opacity: .25;
filter: blur(25px);
}
}
hoặc
.demo {
& :not(.pink) {
opacity: .25;
filter: blur(25px);
}
}
Kết quả, tất cả các hình dạng không phải màu hồng đều bị ẩn bên trong .demo
:
Độ chính xác và tính linh hoạt với &
Giả sử bạn muốn nhắm đến .demo
bằng bộ chọn :not()
. &
là bắt buộc đối với:
.demo {
&:not() {
...
}
}
Thao tác này kết hợp .demo
và :not()
thành .demo:not()
, trái ngược với ví dụ trước cần .demo :not()
. Lời nhắc này rất quan trọng khi bạn muốn lồng một lượt tương tác :hover
.
.demo {
&:hover {
/* .demo:hover */
}
:hover {
/* .demo :hover */
}
}
Ví dụ khác về cách lồng
Quy cách CSS để lồng nhau có nhiều ví dụ hơn. Nếu bạn muốn tìm hiểu thêm về cú pháp thông qua các ví dụ, tài liệu này sẽ trình bày nhiều ví dụ hợp lệ và không hợp lệ.
Vài ví dụ tiếp theo sẽ giới thiệu ngắn gọn về tính năng lồng CSS để giúp bạn hiểu được phạm vi chức năng mà tính năng này mang lại.
Lồng ghép @media
Việc di chuyển đến một khu vực khác của tệp kiểu để tìm điều kiện truy vấn nội dung đa phương tiện sửa đổi bộ chọn và kiểu của bộ chọn đó có thể gây mất tập trung. Sự phân tâm đó sẽ biến mất khi bạn có thể lồng các điều kiện ngay bên trong ngữ cảnh.
Để thuận tiện cho cú pháp, nếu truy vấn nội dung đa phương tiện lồng nhau chỉ sửa đổi các kiểu cho ngữ cảnh bộ chọn hiện tại, thì bạn có thể sử dụng cú pháp tối thiểu.
.card {
font-size: 1rem;
@media (width >= 1024px) {
font-size: 1.25rem;
}
}
Bạn cũng có thể sử dụng &
một cách rõ ràng:
.card {
font-size: 1rem;
@media (width >= 1024px) {
&.large {
font-size: 1.25rem;
}
}
}
Ví dụ này cho thấy cú pháp mở rộng với &
, đồng thời nhắm đến các thẻ .large
để minh hoạ các tính năng lồng ghép bổ sung tiếp tục hoạt động.
Tìm hiểu thêm về cách lồng @rules.
Lồng ghép ở bất cứ đâu
Tất cả các ví dụ cho đến thời điểm này đều tiếp tục hoặc thêm vào ngữ cảnh trước đó. Bạn có thể thay đổi hoặc sắp xếp lại hoàn toàn ngữ cảnh nếu cần.
.card {
.featured & {
/* .featured .card */
}
}
Ký hiệu &
biểu thị tham chiếu đến đối tượng bộ chọn (không phải chuỗi) và có thể được đặt ở vị trí bất kỳ trong bộ chọn lồng nhau. Bạn thậm chí có thể đặt nhiều lần:
.card {
.featured & & & {
/* .featured .card .card .card */
}
}
Mặc dù ví dụ này có vẻ hơi vô dụng, nhưng chắc chắn có những trường hợp mà việc lặp lại ngữ cảnh bộ chọn sẽ rất hữu ích.
Ví dụ về cách lồng không hợp lệ
Có một số tình huống cú pháp lồng nhau không hợp lệ và có thể khiến bạn ngạc nhiên nếu bạn đã lồng trong trình xử lý trước.
Lồng ghép và nối
Nhiều quy ước đặt tên lớp CSS dựa vào việc lồng ghép có thể nối hoặc thêm các bộ chọn như thể chúng là chuỗi. Cách này không hoạt động trong CSS lồng nhau vì các bộ chọn không phải là chuỗi mà là tham chiếu đối tượng.
.card {
&--header {
/* is not equal to ".card--header" */
}
}
Bạn có thể xem thêm nội dung giải thích chi tiết trong quy cách.
Ví dụ về cách lồng ghép khó khăn
Lồng trong danh sách bộ chọn và :is()
Hãy xem xét khối CSS lồng nhau sau:
.one, #two {
.three {
/* some styles */
}
}
Đây là ví dụ đầu tiên bắt đầu bằng một danh sách bộ chọn, sau đó tiếp tục lồng ghép. Các ví dụ trước chỉ kết thúc bằng một danh sách bộ chọn. Không có gì không hợp lệ trong ví dụ lồng nhau này, nhưng có một chi tiết triển khai có thể khó khăn về việc lồng nhau bên trong danh sách bộ chọn, đặc biệt là những danh sách có bộ chọn mã nhận dạng.
Để ý định lồng nhau hoạt động, trình duyệt sẽ gói bất kỳ danh sách bộ chọn nào không phải là lồng nhau nhất bên trong bằng :is()
. Thao tác gói này duy trì việc nhóm danh sách bộ chọn trong bất kỳ ngữ cảnh nào do tác giả tạo. Hiệu ứng phụ của hoạt động nhóm này, :is(.one, #two)
, là việc áp dụng tính cụ thể của điểm số cao nhất trong các bộ chọn trong dấu ngoặc đơn. Đây là cách :is()
luôn hoạt động, nhưng có thể gây ngạc nhiên khi sử dụng cú pháp lồng nhau vì đó không phải là nội dung chính xác đã được tạo. Tóm tắt mẹo: việc lồng ghép với mã nhận dạng và danh sách bộ chọn có thể dẫn đến bộ chọn có độ cụ thể rất cao.
Để tóm tắt rõ ràng ví dụ khó hiểu này, khối lồng trước đó sẽ được áp dụng cho tài liệu như sau:
:is(.one, #two) .three {
/* some styles */
}
Hãy chú ý hoặc hướng dẫn trình tìm lỗi mã nguồn cảnh báo khi lồng bên trong danh sách bộ chọn đang sử dụng bộ chọn mã nhận dạng, độ cụ thể của tất cả các phần lồng trong danh sách bộ chọn đó sẽ rất cao.
Kết hợp việc lồng và khai báo
Hãy xem xét khối CSS lồng nhau sau:
.card {
color: green;
& { color: blue; }
color: red;
}
Màu của các phần tử .card
sẽ là blue
.
Mọi nội dung khai báo kiểu được kết hợp sẽ được chuyển lên trên cùng, như thể chúng được tạo trước khi có bất kỳ hoạt động lồng ghép nào. Bạn có thể xem thêm thông tin chi tiết trong quy cách.
Có một số cách để giải quyết vấn đề này. Phần sau đây gói ba kiểu màu trong &
, giúp duy trì thứ tự lũy tiến như tác giả có thể dự định. Màu của các phần tử .card
sẽ là màu đỏ.
.card {
color: green;
& { color: blue; }
& { color: red; }
}
Trên thực tế, bạn nên gói mọi kiểu theo cách lồng nhau bằng &
.
.card {
color: green;
@media (prefers-color-scheme: dark) {
color: lightgreen;
}
& {
aspect-ratio: 4/3;
}
}
Phát hiện tính năng
Có hai cách hay để phát hiện tính năng lồng ghép CSS: sử dụng tính năng lồng ghép hoặc sử dụng @supports
để kiểm tra khả năng phân tích cú pháp bộ chọn lồng ghép.
Sử dụng tính năng lồng ghép:
html {
.has-nesting {
display: block;
}
.no-nesting {
display: none;
}
}
Sử dụng @supports
:
@supports (selector(&)) {
/* nesting parsing available */
}
Đồng nghiệp của tôi Bramus có một Codepen tuyệt vời cho thấy chiến lược này.
Gỡ lỗi bằng Công cụ của Chrome cho nhà phát triển
Hiện tại, DevTools hỗ trợ rất ít cho việc lồng nhau. Hiện tại, bạn sẽ thấy các kiểu được thể hiện trong ngăn Kiểu như dự kiến, nhưng tính năng theo dõi quá trình lồng ghép và ngữ cảnh bộ chọn đầy đủ của kiểu đó chưa được hỗ trợ. Chúng tôi có thiết kế và kế hoạch để làm rõ vấn đề này.
Chrome 113 dự định hỗ trợ thêm tính năng lồng CSS. Hãy chú ý theo dõi nhé.
Tương lai
Lồng CSS chỉ ở phiên bản 1. Phiên bản 2 sẽ giới thiệu nhiều cú pháp đơn giản hơn và có thể ít quy tắc hơn để ghi nhớ. Có rất nhiều yêu cầu về việc phân tích cú pháp lồng nhau để không bị giới hạn hoặc gặp phải những thời điểm khó khăn.
Lồng nhau là một điểm cải tiến lớn đối với ngôn ngữ CSS. Phương thức này có tác động đến việc tạo tác giả đối với hầu hết mọi khía cạnh cấu trúc của CSS. Bạn cần tìm hiểu và hiểu rõ tác động lớn này trước khi có thể chỉ định phiên bản 2 một cách hiệu quả.
Cuối cùng, dưới đây là một bản minh hoạ sử dụng @scope
, lồng nhau và @layer
cùng nhau. Mọi thứ đều rất thú vị!