Lồng ghép CSS

Một trong những tính năng của bộ tiền xử lý CSS mà chúng tôi yêu thích hiện được tích hợp vào ngôn ngữ: quy tắc về kiểu lồng.

Adam Argyle
Adam Argyle

Trước khi lồng nhau, bạn cần khai báo rõ ràng mọi bộ chọn, tách biệt với nhau. Điều này dẫn đến tình trạng lặp lại, hàng loạt biểu định kiểu và việc soạn thảo rải rác của bạn.

Trước
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

Sau khi lồng nhau, bộ chọn có thể là quy tắc kiểu liên quan và có liên quan đến đoạn mã đó có thể được nhóm lại.

Sau
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

Thử cách này trong trình duyệt.

Tính năng lồng nhau giúp nhà phát triển giảm bớt nhu cầu lặp lại bộ chọn, đồng thời cùng xác định vị trí 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 phù hợp với HTML mà họ nhắm mục tiêu. Nếu thành phần .nesting trong ví dụ trước là bị loại bỏ khỏi dự án, bạn có thể xoá toàn bộ nhóm thay vì tìm kiếm cho các thực thể liên quan của bộ chọn.

Tính năng lồng ghép có thể giúp: - Tổ chức - Giảm kích thước tệp - Tái cấu trúc

Bạn có thể sử dụng tính năng lồng nhau trên Chrome 112 cũng như thử trong Bản dùng thử kỹ thuật Safari 162.

Bắt đầu sử dụng CSS Nesting

Trong suốt phần còn lại của bài đăng này,hộp cát minh hoạ sau đây được dùng để giúp bạn trực quan hoá 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 thứ đề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ể thực hành cú pháp và xem cú pháp đó hoạt động như thế nào.

Một lưới nhiều màu sắc gồm các hình tròn nhỏ và lớn, hình tam giác và hình vuông.

Bên trong hộp cát là hình tròn, hình tam giác và hình vuông. Một số quy tắc là nhỏ, trung bình hoặc lớn. Một số khác có màu xanh dương, hồng hoặc tím. Tất cả đều nằm trong .demo chứa phần tử. Sau đây là bản xem trước các phần tử HTML bạn sẽ nhắm mục tiêu.

<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 ghép

Lồng ghép 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ó thể viết ví dụ này bằng cách sử dụng ký hiệu & để thể hiện rõ biểu thị 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 khiến bạn có các lựa chọn sẽ trở nên rõ ràng hơn khi bạn có thể tìm hiểu thêm nhiều ví dụ nâng cao trong bài viết này.

Chọn vòng kết nối

Trong ví dụ đầu tiên này, nhiệm vụ là thêm các kiểu để làm mờ và làm mờ bên trong bản minh hoạ.

Nếu không lồng ghép, CSS hiện nay:

.demo .circle {
  opacity: .25;
  filter: blur(25px);
}

Khi lồng ghép, 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 là mờ đi và gần như không nhìn thấy được:

Lưới nhiều màu sắc gồm các hình dạng không còn có vòng tròn,
    chúng rất mờ trong nền.
Thử bản minh họa

Chọn hình tam giác và hình vuông bất kỳ

Nhiệm vụ này yêu cầu chọn nhiều phần tử lồng nhau, còn được gọi là bộ chọn nhóm.

Nếu không lồng ghép, CSS hiện nay 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);
}

Khi lồng ghép, 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ả là chỉ còn phần tử .circle bên trong .demo:

Lưới nhiều màu sắc gồm nhiều hình dạng chỉ còn lại các hình tròn,
    tất cả các hình dạng khác gần như không nhìn thấy được.
Thử bản minh họa

Chọn hình tam giác và hình tròn lớn

Nhiệm vụ này cần có 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.

Nếu không lồng ghép, 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);
}

Khi lồng ghép, 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ả là tất cả hình tam giác và hình tròn lớn bị ẩn bên trong .demo:

Lưới nhiều màu sắc chỉ hiển thị các hình dạng nhỏ và trung bình.
Thử bản minh họa
Mẹo nâng cao với bộ chọn phức hợp và cách lồng

Biểu tượng & là bạn của bạn vì nó thể hiện rõ cách nối liền với các ô lồng nhau bộ chọn. Hãy xem ví dụ sau đây:

.demo {
  .lg {
    .triangle,
    .circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

Mặc dù là cách lồng ghép hợp lệ nhưng kết quả sẽ không khớp với các phần tử 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 được kết hợp với nhau, kết quả thực tế sẽ là .lg .triangle, .lg .circle; bộ chọn con cháu.

Chọn tất cả hình dạng, ngoại trừ những hình màu hồng

Nhiệm vụ này yêu cầu một lớp giả chức năng phủ định, trong đó các phần tử không được phép có bộ chọn đã chỉ định.

Nếu không lồng ghép, CSS hiện nay:

.demo :not(.pink) {
  opacity: .25;
  filter: blur(25px);
}

Khi lồng ghép, 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:

Lưới nhiều màu sắc hiện là đơn sắc, chỉ hiển thị các hình màu hồng.
Thử bản minh họa
Độ chính xác và linh hoạt nhờ &

Giả sử bạn muốn nhắm mục tiêu .demo bằng bộ chọn :not(). & là bắt buộc cho rằng:

.demo {
  &:not() {
    ...
  }
}

Điều này kết hợp .demo:not() thành .demo:not(), trái ngược với phương thức trước ví dụ cần .demo :not(). Lời nhắc này rất quan trọng khi muốn lồng một tương tác :hover.

.demo {
  &:hover {
    /* .demo:hover */
  }

  :hover {
    /* .demo :hover */
  }
}

Ví dụ khác về cách lồng ghép

Thông số kỹ thuật của CSS cho lồng ghép là và nhiều ví dụ hơn. Nếu bạn muốn tìm hiểu thêm về cú pháp qua ví dụ, nó bao gồm nhiều ví dụ hợp lệ và không hợp lệ.

Một vài ví dụ tiếp theo sẽ giới thiệu ngắn gọn về tính năng lồng ghép của CSS để giúp bạn nắm được vô vàn khả năng mà tính năng này giới thiệu.

Lồng @media

Có thể rất mất tập trung khi di chuyển đến một khu vực khác của biểu định 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 đó. Sự phân tâm đó không còn khả năng 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 đa phương tiện lồng nhau chỉ sửa đổi 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 &, trong khi cũng nhắm mục tiêu .large để minh hoạ các tính năng lồng 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ả ví dụ cho đến thời điểm này đều tiếp tục hoặc đượ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 */
  }
}

Biểu tượng & đại diện cho tham chiếu đến đối tượng bộ chọn (không phải là chuỗi) và có thể được đặt ở bất cứ đâu trong bộ chọn lồng nhau. Quảng cáo này thậm chí có thể được đặt ở nhiều vị trí lần:

.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

Mặc dù ví dụ này có vẻ hơi vô ích, nhưng chắc chắn sẽ có những tình huống trong đó việc có thể lặp lại ngữ cảnh của bộ chọn sẽ rất hữu ích.

Ví dụ về cách lồng ghép không hợp lệ

Có một số trường hợp lồng nhau cú pháp không hợp lệ và có thể khiến bạn ngạc nhiên nếu bạn đã lồng trong bộ tiền xử lý.

Cách lồng và nối

Nhiều quy ước đặt tên lớp CSS tính đến việc lồng ghép có thể nối hoặc thêm bộ chọn như thể chúng là chuỗi. Điều này không hoạt động trong CSS lồng nhau bộ chọn không phải là chuỗi mà là các tham chiếu đối tượng.

.card {
  &--header {
    /* is not equal to ".card--header" */
  }
}

Bạn có thể xem nội dung giải thích chi tiết hơn trong thông số kỹ thuật.

Ví dụ về cách lồng ghép tinh vi

Lồng ghép trong danh sách bộ chọn và :is()

Hãy xem xét khối CSS lồng nhau sau đây:

.one, #two {
  .three {
    /* some styles */
  }
}

Đây là ví dụ đầu tiên bắt đầu với một danh sách bộ chọn và sau đó tiếp tục lồng nhau. Các ví dụ trước chỉ kết thúc với 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ể phức tạp về việc lồng bên trong danh sách bộ chọn, đặc biệt là những danh sách chứa bộ chọn mã nhận dạng.

Để ý định lồng nhau hoạt động, mọi danh sách bộ chọn không phải là danh sách lồng trong nhất, sẽ được trình duyệt gói bằng :is(). Cách gói này duy trì việc nhóm danh sách bộ chọn trong mọi ngữ cảnh đã tạo. Tác dụng phụ của nhóm này, :is(.one, #two), là áp dụng tính cụ thể của điểm số cao nhất trong các bộ chọn trong ngoặc đơn. Đây là cách :is() luôn hoạt động, nhưng có thể gây bất ngờ khi sử dụng cú pháp lồng nhau vì đây không phải là nội dung được tạo ra. Thủ thuật được tóm tắt; việc lồng ghép bằng mã nhận dạng và danh sách bộ chọn có thể dẫn đến các bộ chọn có độ cụ thể rất cao.

Để tóm tắt rõ ràng ví dụ phức tạp, khối lồng nhau trước đó sẽ được áp dụng cho tài liệu như sau:

:is(.one, #two) .three {
  /* some styles */
}

Hãy để ý hoặc hướng dẫn công cụ tìm lỗi mã nguồn của bạn cảnh báo khi lồng vào danh sách bộ chọn đang sử dụng bộ chọn mã nhận dạng, thì độ cụ thể của tất cả các lần lồng trong danh sách bộ chọn đó sẽ cao.

Kết hợp lồng ghép và khai báo

Hãy xem xét khối CSS lồng nhau sau đây:

.card {
  color: green;
  & { color: blue; }
  color: red;
}

Màu của các phần tử .card sẽ là blue.

Mọi thông tin khai báo kiểu xen kẽ đều được chuyển lên trên cùng, như thể chúng được tạo trước khi bất kỳ lồng nhau nào diễn ra. Bạn có thể xem thêm thông tin chi tiết trong thông số kỹ thuật.

Có nhiều cách để giải quyết vấn đề này. Sau đây là 3 kiểu màu trong &, sẽ duy trì thứ tự phân tầng như tác giả có thể đã dự định. Màu của Các phần tử .card sẽ có 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 sau khi lồng 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 hiệu quả để phát hiện việc lồng CSS: sử dụng tính năng lồng nhau @supports để kiểm tra khả năng phân tích cú pháp bộ chọn lồng.

Ảnh chụp màn hình bản minh hoạ Codepen của Bramus, hỏi xem trình duyệt của bạn có hỗ trợ hay không
  Lồng ghép CSS. Bên dưới câu hỏi đó là một ô màu xanh lục, thể hiện sự ủng hộ.

Sử dụng cách lồng ghép:

html {
  .has-nesting {
    display: block;
  }

  .no-nesting {
    display: none;
  }
}

Đang dùng @supports:

@supports (selector(&)) {
  /* nesting parsing available */
}

Đồng nghiệp của tôi là 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, chúng tôi chỉ hỗ trợ việc lồng ghép trong Công cụ cho nhà phát triển ở mức tối thiểu. Hiện tại, bạn sẽ thấy kiểu được biểu thị trong ngăn Kiểu như dự kiến, nhưng lại theo dõi tình trạng lồng nhau và ngữ cảnh bộ chọn đầy đủ chưa được hỗ trợ. Chúng tôi có thiết kế và kế hoạch để hãy làm cho vấn đề này rõ ràng và minh bạch.

Ảnh chụp màn hình cú pháp lồng trong Công cụ của Chrome cho nhà phát triển.

Chrome 113 dự định bổ sung tính năng hỗ trợ cho việc lồng ghép CSS. Hãy chú ý theo dõi nhé.

Tương lai

Tính năng Lồng ghép CSS chỉ có ở phiên bản 1. Phiên bản 2 sẽ có nhiều cú pháp dễ hiểu hơn và có thể áp dụng ít quy tắc hơn ghi nhớ. Nhu cầu phân tích cú pháp việc lồng nhau rất nhiều để không bị giới hạn hoặc có những khoảnh khắc phức tạp.

Tính năng lồng ghép là một điểm cải tiến lớn cho ngôn ngữ CSS. Có ý nghĩa về mặt tác giả vào hầu hết mọi khía cạnh kiến trúc của CSS. Tác động lớn này cần được khám phá và hiểu rõ trước khi chỉ định phiên bản 2 một cách hiệu quả.

Lưu ý cuối cùng, sau đây là bản minh hoạ sử dụng @scope, lồng nhau và @layer cùng nhau. Tất cả đều rất thú vị!

Một thẻ sáng trên nền xám. Thẻ này có tiêu đề và văn bản,
  một vài nút hành động và hình ảnh phong cách Cyber punk.