Tìm hiểu sâu hơn về các truy vấn kiểu vùng chứa

Nút nguồn: 1765194

Tôi đã viết lên một số suy nghĩ ban đầu về truy vấn kiểu vùng chứa một lát sau. Vẫn còn sớm. Chúng đã được xác định trong Thông số kỹ thuật của Mô-đun chứa CSS cấp 1 (hiện ở trạng thái Bản nháp của Biên tập viên) nhưng vẫn còn một số cuộc thảo luận còn tồn đọng đang diễn ra.

Ý tưởng cơ bản là chúng ta có thể xác định một vùng chứa và sau đó áp dụng các kiểu có điều kiện cho các phần tử con của nó dựa trên kiểu dáng được tính toán của nó.

@container ?  {
  /* conditional styles */
}

Ví dụ tốt nhất tôi từng thấy cho đến nay là xóa chữ nghiêng khỏi nội dung như , khi chúng được sử dụng trong ngữ cảnh mà nội dung đã được in nghiêng:

em, i, q {
  font-style: italic; /* default UA behavior */
}

/* When the container's font-style is italic, remove italics from these elements. */
@container style(font-style: italic) {
  em, i, q {
    font-style: normal;
  }
}

Đó là ý tưởng chung. Nhưng nếu bạn chưa biết thì Miriam Suzanne, người biên tập thông số kỹ thuật, luôn cập nhật một bộ thông tin kỹ lưỡng và liên tục. ghi chú cá nhân về truy vấn kiểu vùng chứa đó là có sẵn công khai. Nó đã được cập nhật vào ngày hôm trước và tôi đã dành một chút thời gian ở đó để cố gắng tìm hiểu các khía cạnh sắc thái hơn của các truy vấn kiểu. Đó là nội dung không chính thức, nhưng tôi nghĩ tôi nên ghi lại một số điều nổi bật đối với tôi. Ai biết? Có lẽ đó là thứ mà cuối cùng chúng ta có thể mong đợi!

Mỗi phần tử là một thùng chứa kiểu

Chúng tôi thậm chí không cần phải chỉ định rõ ràng một container-name or container-type để xác định vùng chứa kiểu vì mọi thứ đều là vùng chứa kiểu theo mặc định.

Vì vậy, bạn thấy ví dụ trên loại bỏ chữ nghiêng? Lưu ý rằng nó không xác định được vùng chứa. Nó chuyển ngay đến truy vấn bằng cách sử dụng style() chức năng. Vậy vùng chứa nào đang được truy vấn? Nó sẽ là cha mẹ trực tiếp của các phần tử tiếp nhận các phong cách được áp dụng. Và nếu không phải thế thì đó là thùng chứa tương đối gần nhất tiếp theo điều đó được ưu tiên.

Tôi thích điều đó. Việc truy vấn tìm kiếm kết quả khớp rất giống CSS-y, sau đó tiếp tục hiển thị cho đến khi tìm thấy điều kiện phù hợp.

Bộ não bé nhỏ của tôi thật khó hiểu tại sao chúng ta có thể loại bỏ một vùng chứa ngầm dựa trên các kiểu nhưng không quá nhiều khi chúng ta xử lý các truy vấn thứ nguyên, như sizeinline-size. Miriam giải thích nó một cách độc đáo:

Truy vấn thứ nguyên yêu cầu css ngăn chặn về kích thước, bố cục và kiểu dáng của vùng chứa để tránh lặp lại bố cục. Ngăn chặn là một điều xâm phạm để áp dụng rộng rãi, vì vậy điều quan trọng là tác giả phải kiểm soát cẩn thận những phần tử nào là (hoặc không) là vùng chứa có kích thước.

Truy vấn dựa trên kiểu không có cùng giới hạn. CSS hiện không có cách nào để các kiểu con cháu có tác động đến các kiểu được tính toán của tổ tiên. Vì vậy, không cần phải có biện pháp ngăn chặn và không có tác dụng phụ xâm lấn hoặc bất ngờ nào trong việc thiết lập một phần tử làm cơ sở vùng chứa truy vấn kiểu.

(Tôi nhấn mạnh)

Tất cả đều dẫn đến hậu quả - trong số đó không có gì ngoại trừ mọi thứ đều là một thùng chứa truy vấn kiểu ngay lập tức.

  • Nếu tìm thấy vùng chứa: các điều kiện được giải quyết đối với vùng chứa đó.
  • Nếu nhiều vùng chứa khớp nhau: vùng chứa tương đối gần nhất sẽ được ưu tiên.
  • Nếu không tìm thấy kết quả phù hợp: unknown trả lại.

Điều đó giống nhau Tinh thần “tha thứ” như phần còn lại của CSS.

Một thùng chứa có thể hỗ trợ cả truy vấn chiều và kiểu

Giả sử chúng ta muốn xác định một truy vấn kiểu mà không có một định nghĩa rõ ràng container-name:

@container style(font-style: italic) {
  em {
    font-style: normal;
  }
}

Điều này hoạt động bởi vì tất cả các phần tử đều là vùng chứa kiểu, không có vấn đề container-type. Đó là những gì cho phép chúng tôi truy vấn ngầm các kiểu và dựa vào kết quả khớp gần nhất. Và điều này hoàn toàn ổn vì một lần nữa, không có tác dụng phụ bất lợi nào khi thiết lập các thùng chứa kiểu dáng.

Chúng ta phải sử dụng một cách rõ ràng container-type đối với truy vấn thứ nguyên, nhưng không nhiều đối với truy vấn kiểu vì mọi phần tử đều là truy vấn kiểu. Điều đó cũng có nghĩa thùng chứa này vừa là một phong cách truy vấn chiều:

.card-container {
  container: card / inline-size; /* implictly a style query container as well */
}

Loại trừ một container khỏi bị truy vấn

Có lẽ chúng ta không muốn vùng chứa tham gia vào quá trình so khớp. Đó là nơi có thể thiết lập container-type: none trên một phần tử.

.some-element {
  container-type: none;
}

Vùng chứa truy vấn kiểu rõ ràng cung cấp nhiều quyền kiểm soát hơn đối với những gì được truy vấn

Ví dụ: nếu chúng ta viết một truy vấn kiểu cho padding , không có cách nào đáng tin cậy để xác định vùng chứa phù hợp nhất, bất kể chúng ta đang làm việc với vùng chứa có tên rõ ràng hay vùng chứa cấp độ gốc gần nhất. Đó là bởi vì padding không phải là tài sản thừa kế.

Vì vậy, trong những trường hợp đó, chúng ta nên sử dụng container-name để thông báo rõ ràng cho trình duyệt những vùng chứa mà họ có thể lấy từ đó. Chúng ta thậm chí có thể đặt cho một container nhiều tên rõ ràng để làm cho nó phù hợp với nhiều điều kiện hơn:

.card {
  container-name: card layout theme;
}

Oh, và container-name chấp nhận bất kỳ số lượng tùy chọn và có thể tái sử dụng tên cho một container! Điều đó thậm chí còn linh hoạt hơn khi giúp trình duyệt đưa ra lựa chọn khi tìm kiếm kết quả phù hợp.

.theme {
  container-name: theme;
}
.grid {
  container-name: layout;
}
.card {
  container-name: card layout theme;
}

Tôi tự hỏi liệu điều đó có được coi là "dự phòng" trong trường hợp một container được chuyển qua hay không.

Truy vấn kiểu có thể được kết hợp

Sản phẩm orand các toán tử cho phép chúng ta kết hợp các weries để giữ mọi thứ KHÔ:

@container bubble style(--arrow-position: start start) or style(--arrow-position: end start) {
  .bubble::after {
    border-block-end-color: inherit;
    inset-block-end: 100%;
  }
}

/* is the same as... */
@container bubble style(--arrow-position: start start) {
  /* etc. */
}
@container bubble style(--arrow-position: end start) {
  /* etc. */
}

Chuyển đổi kiểu

Có một chút trùng lặp giữa các truy vấn kiểu vùng chứa và công việc đang được thực hiện để xác định một toggle() chức năng. Ví dụ: chúng ta có thể duyệt qua hai font-style giá trị, nói italicnormal:

em, i, q {
  font-style: italic;
}

@container style(font-style: italic) {
  em, i, q {
    font-style: normal;
  }
}

Mát mẻ. Nhưng đề xuất về CSS Toggles gợi ý rằng toggle() chức năng sẽ là một cách tiếp cận đơn giản hơn:

em, i, q {
  font-style: toggle(italic, normal);
}

Nhưng bất cứ điều gì ngoài trường hợp sử dụng nhị phân này đều nằm ở đâu toggle() ít phù hợp hơn. Tuy nhiên, các truy vấn về phong cách vẫn có thể thực hiện được. Miriam xác định ba trường hợp trong đó các truy vấn kiểu phù hợp hơn một toggle():

/* When font-style is italic, apply background color. */
/* Toggles can only handle one property at a time. */
@container style(font-style: italic) {
  em, i, q {
    background: lightpink;
  }
}

/* When font-style is italic and --color-mode equals light */
/* Toggles can only evaluate one condition at a time */
@container style((font-style: italic) and (--color-mode: light)) {
  em, i, q {
    background: lightpink;
  }
}

/* Apply the same query condition to multiple properties */
/* Toggles have to set each one individually as separate toggles */
@container style(font-style: italic) {
  em, i, q {
    /* clipped gradient text */
    background: var(--feature-gradient);
    background-clip: text;
    box-decoration-break: clone;
    color: transparent;
    text-shadow: none;
  }
}

Truy vấn kiểu giải quyết “Hack chuyển đổi thuộc tính tùy chỉnh”

Lưu ý rằng các truy vấn kiểu là một giải pháp chính thức cho “Thủ thuật chuyển đổi thuộc tính tùy chỉnh CSS”. Trong đó, chúng tôi đặt một thuộc tính tùy chỉnh trống (--foo: ;) và sử dụng phương thức dự phòng được phân tách bằng dấu phẩy để “bật và tắt” các thuộc tính khi thuộc tính tùy chỉnh được đặt thành giá trị thực.

button {
  --is-raised: ; /* off by default */
  
  border: 1px solid var(--is-raised, rgb(0 0 0 / 0.1));
  box-shadow: var(
    --is-raised,
    0 1px hsl(0 0% 100% / 0.8) inset,
    0 0.1em 0.1em -0.1em rgb(0 0 0 / 0.2)
  );
  text-shadow: var(--is-raised, 0 -1px 1px rgb(0 0 0 / 0.3));
}

button:active {
  box-shadow: var(--is-raised, 0 1px 0.2em black inset);
}

#foo {
  --is-raised: initial; /* turned on, all fallbacks take effect. */
}

Điều đó thật tuyệt vời, cũng có rất nhiều công việc mà các truy vấn vùng chứa kiểu trở nên tầm thường.

Truy vấn kiểu và nội dung được tạo CSS

Đối với nội dung được tạo ra bởi content tài sản của ::before::after phần tử giả, vùng chứa phù hợp là phần tử mà nội dung được tạo ra trên đó.

.bubble {
  --arrow-position: end end;
  container: bubble;
  border: medium solid green;
  position: relative;
}

.bubble::after {
  content: "";
  border: 1em solid transparent;
  position: absolute;
}

@container bubble style(--arrow-position: end end) {
  .bubble::after {
    border-block-start-color: inherit;
    inset-block-start: 100%;
    inset-inline-end: 1em;
  }
}

Truy vấn kiểu và thành phần web

Chúng ta có thể định nghĩa một thành phần web làm vùng chứa và truy vấn nó theo kiểu. Đầu tiên, chúng ta có của thành phần:


  
… …

Sau đó chúng tôi sử dụng :host phần tử giả làm vùng chứa để đặt container-name, Một container-typevà một số thuộc tính cấp cao trên đó:

:host {
  container: media-host / inline-size;
  --media-location: before;
  --media-style: square;
  --theme: light;
}

Các phần tử bên trong có thể truy vấn các tham số của thành phần:

@container media-host style(--media-style: round) {
  [part='img'] {
    border-radius: 100%;
  }
}

Cái gì tiếp theo?

Một lần nữa, tất cả những thứ tôi ghi lại ở đây đều dựa trên ghi chú của Miriam và những ghi chú đó không thay thế cho thông số kỹ thuật chính thức. Nhưng chúng là dấu hiệu cho thấy những gì đang được thảo luận và nơi mọi thứ có thể xảy ra trong tương lai. Tôi đánh giá cao Miriam đã liên kết một số cuộc thảo luận nổi bật vẫn đang diễn ra mà chúng ta có thể theo dõi để luôn cập nhật mọi thứ:

Dấu thời gian:

Thêm từ Thủ thuật CSS