Cú pháp CSS khá đơn giản. Tuy nhiên, nhiều nguyên tắc cơ bản trong cách hoạt động của nó thường khiến người dùng bất ngờ. Điều này có thể dẫn đến sự bối rối và thất vọng lớn. Cũng có những lúc có nhiều cách để thực hiện cùng một việc. Điều đó cũng gây thêm sự thất vọng vì bạn không biết cách nào tốt hơn trong tình huống cụ thể. CSS thực sự là một trong những thứ mà khi mới bắt đầu, nó có vẻ là điều dễ dàng nhất trên đời. Nhưng nó có thể nhanh chóng dẫn đến những lúc bạn chỉ muốn ném máy tính ra ngoài cửa sổ. Vì vậy, hãy xem xét tám khái niệm CSS cực kỳ quan trọng. Khi bạn hiểu chúng, mọi thứ có thể trở nên đơn giản hơn và cuộc sống của bạn sẽ dễ dàng hơn nhiều khi viết CSS.
1. Mô hình hộp (Box Model) và lý do bạn cần box-sizing: border-box
Đây là một trong những điều thực sự quan trọng cần làm trong mọi tệp bạn từng làm việc. Hãy bắt đầu CSS của bạn với đoạn mã sau:
* {
box-sizing: border-box;
}Bộ chọn dấu sao (*) có nghĩa là “chọn mọi thứ”. Theo thời gian, bạn cũng sẽ bắt đầu sử dụng các phần tử giả (pseudo-elements). Đừng lo lắng nếu bạn chưa biết chúng là gì; chúng ta sẽ nói về chúng sau. Khi đó, bạn sẽ muốn cập nhật đoạn mã trên thành:
*, *::before, *::after {
box-sizing: border-box;
}Hãy tạo thói quen đưa các phần tử giả vào ngay bây giờ, ngay cả khi bạn chưa sử dụng chúng. Bạn sẽ cần chúng cuối cùng.
Đây là lý do tại sao điều này quan trọng. Giả sử bạn có một phần tử và bạn đặt chiều rộng của nó là 400 pixel và lề đệm (padding) là 20 pixel. Hành vi mặc định (gọi là content-box) có nghĩa là chiều rộng chỉ là nội dung đó. Vì vậy, bạn đang thêm 20 pixel ở bên trái và 20 pixel ở bên phải vào trên 400 pixel đó. Phần tử của bạn thực sự rộng 440 pixel bây giờ.
Với box-sizing: border-box, 400 pixel đó bao gồm cả lề đệm. Lề đệm đẩy vào bên trong, và phần tử vẫn rộng 400 pixel. Điều này giúp việc tính toán dễ dàng hơn nhiều. Nó cũng giúp bạn thực sự có thể ước tính kích thước của một cái gì đó. Điều này không còn quan trọng như trước đây khi chúng ta có bố cục dựa trên float và chiều rộng, chiều cao phổ biến hơn.
Tuy nhiên, vẫn có những trường hợp chúng ta đặt chiều rộng rõ ràng. Điều này sẽ giúp bạn tiết kiệm rất nhiều rắc rối về lâu dài. Hãy tạo thói quen đặt đoạn mã này ở đầu mỗi tệp CSS bạn tạo.
2. Độ đặc hiệu (Specificity) – Lý do các kiểu của bạn không hoạt động
Độ đặc hiệu là mức độ cụ thể của các bộ chọn trong CSS của chúng ta. Đây có lẽ là lý do số một khiến người mới bắt đầu thất vọng khi các kiểu của họ không được áp dụng.
Thường có ba cấp độ bộ chọn:
- Bộ chọn phần tử (độ đặc hiệu thấp nhất):
h2 { color: red; } - Bộ chọn lớp (độ đặc hiệu trung bình):
.color-accent { color: purple; } - Bộ chọn ID (độ đặc hiệu cao nhất):
#example { color: lime; }
Vấn đề là: ngay cả khi bạn có một bộ chọn h2 ở phía dưới tệp CSS của bạn nói rằng màu sắc phải là đỏ.
Nếu h2 đó có một lớp với màu khác, lớp đó sẽ thắng. Vị trí của nó trong cascade không quan trọng. Một bộ chọn lớp có tầm quan trọng cao hơn một bộ chọn phần tử. Điều tương tự cũng áp dụng cho ID.
Một bộ chọn ID sẽ luôn thắng một bộ chọn lớp.
Một bộ chọn lớp sẽ luôn thắng một bộ chọn phần tử.
Bạn cũng có thể tăng độ đặc hiệu bằng các bộ chọn con cháu (descendant selectors).
Ví dụ:
.dark-background h3 {
color: red;
}Điều này cụ thể hơn chỉ h3.
Lý do là vì nó là sự kết hợp của bộ chọn lớp và bộ chọn phần tử.
Khi có điều gì đó không hoạt động, các công cụ phát triển (dev tools) của bạn có thể thực sự giúp ích.
Nhấp chuột phải vào phần tử, kiểm tra nó.
Bạn sẽ thấy tất cả các kiểu đang được áp dụng.
Những kiểu bị gạch bỏ đang bị ghi đè.
Bạn có thể thấy chính xác lý do tại sao, bộ chọn nào đang thắng và nó đến từ đâu trong tệp CSS của bạn.
Nói chung, hãy cố gắng tránh lồng ghép quá nhiều và các bộ chọn quá cụ thể.
Nhiều hệ thống thiết kế sử dụng các bộ chọn lớp đơn vì lý do chính đáng.
Chúng giữ cho độ đặc hiệu dễ quản lý và dễ dự đoán.
3. Kế thừa (Inheritance) – Viết ít CSS hơn bằng cách để mọi thứ chảy xuống
Kế thừa là khi các thuộc tính được truyền từ một phần tử cha xuống các phần tử con và cháu của nó.
Đây là một trong những điều bạn nghe nói đến sớm nhưng sau đó lại quên mất hoặc không thực sự hiểu ý nghĩa của nó.
Điểm mấu chốt là: bất cứ thứ gì liên quan đến kiểu chữ đều kế thừa theo mặc định.
Điều này bao gồm color, font-family, font-size, text-align, line-height, v.v.
Bất cứ thứ gì không liên quan đến kiểu chữ nói chung không kế thừa.
Điều này có nghĩa là bạn có thể đặt kiểu một lần trên phần tử body (hoặc html).
Chúng sẽ chảy xuống mọi thứ bên trong:
body {
color: #333;
font-size: 1.25rem;
font-family: Arial, sans-serif;
}Bây giờ tất cả các đoạn văn, tiêu đề và các phần tử văn bản khác của bạn sẽ kế thừa các kiểu này.
Bạn không cần phải chọn từng cái một.
Ưu điểm lớn ở đây là bạn viết ít mã hơn rất nhiều.
Bạn đặt nó một lần và sau đó bạn không phải lo lắng về nó nữa.
Tất nhiên, bạn luôn có thể ghi đè mọi thứ bằng các bộ chọn cụ thể hơn khi cần.
Một lưu ý nhanh: các phần tử biểu mẫu thực sự không kế thừa các thuộc tính phông chữ như bạn mong đợi.
Bạn thường thấy điều này trong các thiết lập lại CSS (CSS resets):
button, input, textarea, select {
font: inherit;
}Điều này buộc các phần tử này bắt đầu kế thừa tất cả các thuộc tính phông chữ như bạn mong đợi ngay từ đầu.
font: inherit; là một cách viết tắt.
Nó kế thừa font-family, font-size, font-weight, line-height và tất cả các thuộc tính liên quan đến phông chữ khác cùng một lúc.
Càng nhiều càng tốt, hãy dựa vào tính kế thừa.
Nó có nghĩa là bạn viết ít mã hơn rất nhiều.
Bạn có thể chọn những nơi bạn muốn phá vỡ quy tắc đó.
Một trong những sai lầm mà mọi người mắc phải là họ bắt đầu chọn mọi thứ và cố gắng tạo kiểu cho từng cái một.
Điều đó chỉ tạo ra nhiều công việc hơn cho bạn.
4. Đơn vị CSS (CSS Units) – Chọn kích thước phù hợp cho công việc
Hiểu các đơn vị khác nhau là nền tảng để tạo ra các bố cục hoạt động trên các kích thước màn hình và tình huống khác nhau.
Có rất nhiều đơn vị khác nhau trong CSS.
Biết cách sử dụng đơn vị nào có thể gây nhầm lẫn.
- Đơn vị tuyệt đối:
px– Pixel là đơn vị cố định. Tốt cho viền và các phép đo nhỏ, chính xác. Không tốt cho thiết kế đáp ứng khi dùng cho bố cục.
- Đơn vị tương đối:
%– Phần trăm kích thước của phần tử cha. Rất tốt cho chiều rộng.em– Tương đối vớifont-sizecủa chính phần tử đó. Cộng dồn khi lồng nhau (có thể phức tạp).rem– Tương đối vớifont-sizegốc (html). Không cộng dồn, giúp dễ dự đoán hơn. Rất tốt cho khoảng cách và kích thước phông chữ.vw/vh– Chiều rộng và chiều cao của khung nhìn (viewport).1vwlà 1% chiều rộng khung nhìn. Rất tốt cho các phần toàn màn hình.
Đối với người mới bắt đầu, đây là một điểm khởi đầu đơn giản:
- Sử dụng
remcho kích thước phông chữ và khoảng cách (padding, margin). - Sử dụng
%hoặcfr(trong grid) cho chiều rộng. - Sử dụng
pxcho những thứ nhỏ như viền. - Sử dụng
vw/vhkhi bạn cần thứ gì đó tương đối với khung nhìn.
Lý do rem rất phổ biến là vì nếu người dùng thay đổi kích thước phông chữ mặc định của trình duyệt (để dễ tiếp cận), mọi thứ sẽ tự động điều chỉnh theo tỷ lệ.
Nếu bạn sử dụng px ở khắp mọi nơi, không có gì sẽ điều chỉnh.
Bạn không cần phải ghi nhớ tất cả điều này ngay lập tức.
Hãy bắt đầu với rem cho hầu hết mọi thứ và px cho viền, và bạn sẽ ổn.
Khi bạn cảm thấy thoải mái hơn, bạn có thể thử nghiệm với các đơn vị khác.
5. Thuộc tính Display (Display Property) – Cách các phần tử thực sự hoạt động
Thuộc tính display là nền tảng để hiểu cách các phần tử hoạt động trên trang.
Mỗi phần tử HTML có một giá trị display mặc định.
Hiểu điều này là rất quan trọng.
display: block- Các phần tử khối chiếm toàn bộ chiều rộng có sẵn.
- Chúng bắt đầu trên một dòng mới.
- Hãy nghĩ đến các thẻ
div, đoạn văn, tiêu đề; chúng xếp chồng theo chiều dọc. - Bạn có thể đặt
widthvàheightcho các phần tử khối.
display: inline- Các phần tử nội tuyến chỉ chiếm nhiều chiều rộng khi cần.
- Chúng không bắt đầu trên một dòng mới.
- Hãy nghĩ đến các thẻ
span, liên kết, thẻstrong; chúng chảy trong văn bản. - Bạn không thể đặt
widthvàheightcho các phần tử nội tuyến.
display: inline-block- Đây là một dạng lai.
- Nó chảy nội tuyến như một phần tử nội tuyến.
- Tuy nhiên, bạn có thể đặt
widthvàheightcho nó như một phần tử khối. - Rất hữu ích cho những thứ như các mục điều hướng hoặc nút cần nằm cạnh nhau nhưng có kích thước cụ thể.
display: none- Điều này loại bỏ phần tử khỏi trang hoàn toàn.
- Nó không chiếm bất kỳ không gian nào.
- Khác với
visibility: hidden, cái này ẩn đi nhưng để lại một khoảng trống nơi nó sẽ ở.
display: flexvàdisplay: grid- Đây là những công cụ bố cục mạnh mẽ của bạn.
- Chúng ta sẽ nói thêm về chúng trong phần tiếp theo.
Hiểu display rất quan trọng vì đôi khi bạn cần thay đổi hành vi mặc định của một phần tử.
Có thể bạn muốn một liên kết hoạt động như một khối để bạn có thể cho nó padding và làm cho nó dễ nhấp hơn.
Hoặc bạn muốn các mục danh sách nằm cạnh nhau thay vì xếp chồng lên nhau.
6. Bố cục với Flexbox và Grid (Không phải Định vị!)
Khi bạn xây dựng bố cục, bạn sẽ muốn chọn giữa Flexbox hoặc Grid.
Nếu bạn chưa học cái nào trong số chúng, bạn sẽ muốn học cả hai.
Đây là khuyến nghị của tôi: hãy bắt đầu với Grid.
Nó dễ hiểu hơn khi bạn mới bắt đầu.
Nó mang lại cho bạn nhiều quyền kiểm soát hơn để xây dựng bố cục trang.
Lý do nên dùng Grid cho bố cục:
.columns {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
}Chỉ vậy thôi.
Bạn có ba cột bằng nhau với khoảng cách giữa chúng.
Đơn vị fr là một phần của không gian có sẵn – một phần cho mỗi cột.
Nó linh hoạt và đáp ứng theo mặc định.
Lý do Flexbox cũng quan trọng: Flexbox tuyệt vời cho bố cục cấp độ thành phần.
Ví dụ như thanh điều hướng, thẻ, căn giữa nội dung, phân bổ khoảng cách đều.
Khi bạn đã quen với các nguyên tắc cơ bản của Grid, hãy thêm Flexbox vào bộ công cụ của bạn.
.nav {
display: flex;
justify-content: space-between;
align-items: center;
}Điều cần tránh: Không sử dụng định vị (position: absolute, position: fixed) cho bố cục.
Định vị dùng cho các điều chỉnh nhỏ và các mẫu UI cụ thể, không phải để xây dựng cấu trúc trang chính của bạn.
Bạn học position absolute, đặt chiều rộng và chiều cao, đặt nó ở nơi bạn muốn.
Đó là cách tồi tệ nhất có thể để xây dựng một bố cục.
Bạn cũng có thể thấy các hướng dẫn cũ với float.
Nếu bạn thấy những điều liên quan đến việc xây dựng bố cục bằng float, hãy hoàn toàn tránh nó.
Float là một thủ thuật chúng ta đã sử dụng trước khi flexbox và grid tồn tại.
Tất cả các bố cục hiện đại đều được xây dựng bằng flexbox hoặc grid.
Ngày nay chúng ta không cần đặt chiều rộng nhiều.
Lý do là vì vùng chứa cha (parent container) làm tất cả công việc cho chúng ta.
Bạn thiết lập grid hoặc flex container.
Các phần tử con chỉ vừa vặn vào không gian được cấp cho chúng.
7. Pseudo-classes và Pseudo-elements – Tạo sự tương tác
Pseudo-classes và pseudo-elements là những công cụ cực kỳ mạnh mẽ.
Chúng cho phép bạn tạo kiểu cho các phần tử dựa trên trạng thái của chúng.
Hoặc chúng cho phép bạn thêm nội dung mà không cần chạm vào HTML của bạn.
Chúng trông tương tự nhau nhưng thực hiện những việc khác nhau.
Cách bạn viết chúng cũng hơi khác một chút.
- Pseudo-classes sử dụng một dấu hai chấm đơn (
:) và tất cả là về trạng thái. Chúng cho phép bạn tạo kiểu cho các phần tử khi có điều gì đó xảy ra với chúng:a:hover { color: blue; text-decoration: underline; }button:focus { outline: 2px solid blue; }input:invalid { border-color: red; }li:first-child { font-weight: bold; }
Đây là những điều cần thiết để tạo ra trải nghiệm tương tác.
Các liên kết của bạn cần trạng thái di chuột (hover states).
Các trường nhập biểu mẫu của bạn cần kiểu tập trung (focus styles) để dễ tiếp cận.
Bạn thường muốn tạo kiểu cho mục đầu tiên hoặc cuối cùng trong danh sách khác nhau.
- Pseudo-elements sử dụng dấu hai chấm kép (
::) và cho phép bạn thêm nội dung trang trí hoặc tạo kiểu cho các phần cụ thể của một phần tử:.quote::before { content: '"'; font-size: 2em; color: gray; }p::first-line { font-weight: bold; }.card::after { content: ''; display: block; width: 100%; height: 3px; background: blue; margin-top: 1rem; }
Các pseudo-elements
::beforevà::afterđặc biệt hữu ích.Chúng giúp thêm các yếu tố trang trí mà không làm lộn xộn HTML của bạn.
Bạn có thể tạo biểu tượng, đường phân cách hoặc hiệu ứng hình ảnh hoàn toàn bằng CSS.
Một điều cần nhớ: pseudo-elements cần thuộc tính
contentđể hiển thị, ngay cả khi đó chỉ làcontent: ''.Nếu không có nó, chúng sẽ không hiển thị chút nào.
Và đây là lý do tại sao trong phần mô hình hộp, tôi đã bao gồm
*::beforevà*::aftertrong quy tắcbox-sizing.Pseudo-elements tạo ra các hộp thực tế trên trang.
Chúng cần hành vi
box-sizingtương tự như mọi thứ khác.Nếu bạn không bao gồm chúng, bạn có thể gặp phải các vấn đề về kích thước kỳ lạ sau này.
8. Thiết kế đáp ứng với Media Queries (Làm cho nó hoạt động ở mọi nơi)
Trang web của bạn cần hoạt động trên điện thoại, máy tính bảng, máy tính xách tay và màn hình máy tính để bàn lớn.
Đó là thực tế ngày nay.
Và cách chúng ta thực hiện điều đó là với các media queries.
Media queries cho phép bạn áp dụng các kiểu khác nhau dựa trên kích thước màn hình:
/* Phương pháp ưu tiên thiết bị di động - kiểu cho màn hình nhỏ trước */.container {
padding: 1rem;
}
/* Máy tính bảng trở lên */@media (min-width: 768px) {
.container {
padding: 2rem;
}
}
/* Máy tính để bàn trở lên */@media (min-width: 1024px) {
.container {
padding: 3rem;
max-width: 1200px;
margin: 0 auto;
}
}Tôi khuyến nghị phương pháp ưu tiên thiết bị di động (mobile-first).
Viết các kiểu cơ bản của bạn cho thiết bị di động.
Sau đó sử dụng media queries min-width để thêm độ phức tạp khi màn hình lớn hơn.
Điều này có ý nghĩa hơn vì:
- Di động là môi trường bị hạn chế nhất – nếu nó hoạt động trên di động, bạn có thể xây dựng từ đó.
- Dễ dàng thêm độ phức tạp hơn là loại bỏ nó.
- Hầu hết lưu lượng truy cập ngày nay là từ di động.
Bạn cũng có thể sử dụng media queries cho những việc khác:
- Chế độ tối (Dark mode)
@media (prefers-color-scheme: dark) { body { background: #222; color: #fff; } } - Kiểu in (Print styles)
@media print { nav, footer { display: none; } }
Các điểm ngắt (breakpoints) phổ biến bạn sẽ thấy là:
640pxhoặc768pxcho máy tính bảng.1024pxhoặc1280pxcho máy tính để bàn.
Thành thật mà nói, các điểm ngắt của bạn nên dựa trên nội dung của bạn, không phải các thiết bị cụ thể.
Đừng quá căng thẳng về việc có được các điểm ngắt hoàn hảo ngay từ đầu.
Khi bạn xây dựng, bạn sẽ thấy nơi thiết kế của bạn bị hỏng.
Đó là nơi bạn thêm một media query.
Các công cụ phát triển trình duyệt của bạn cho phép bạn kiểm tra điều này dễ dàng.
Chỉ cần bật chế độ thiết kế đáp ứng và thay đổi kích thước khung nhìn để xem mọi thứ bắt đầu trông kỳ lạ ở đâu.
Bạn không cần phải thành thạo thiết kế đáp ứng ngay lập tức.
Hãy bắt đầu bằng cách làm cho mọi thứ hoạt động trên di động.
Sau đó thêm một hoặc hai điểm ngắt khi bạn cần.
Theo thời gian, bạn sẽ cảm nhận được nơi bạn thường cần điều chỉnh mọi thứ.
Bonus: Tách biệt bố cục khỏi nội dung
Điều cuối cùng này hơi dựa trên những gì tôi vừa chỉ cho bạn về bố cục.
Càng nhiều càng tốt, hãy cố gắng tạo sự tách biệt giữa cách bạn tạo kiểu cho bố cục và chính nội dung.
Ý tôi là có các lớp thực hiện các công việc cụ thể:
- Lớp này xử lý bố cục:
/* Lớp này xử lý bố cục */.columns { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1rem; } - Lớp này xử lý kiểu nội dung:
/* Lớp này xử lý kiểu nội dung */.card { background: #333; color: white; padding: 2rem; }
Sau đó trong HTML của bạn:
<div class="columns">
<div class="card">Nội dung ở đây</div>
<div class="card">Nội dung ở đây</div>
<div class="card">Nội dung ở đây</div>
</div>Lớp columns đang thiết lập cấu trúc bố cục.
Lớp card đang tạo kiểu cho nội dung bên trong bố cục đó.
Chúng có các công việc riêng biệt.
Điều này làm cho cuộc sống của bạn dễ dàng hơn rất nhiều vì:
- Dễ dàng tìm bộ chọn hơn khi bạn cần sửa đổi điều gì đó.
- Bạn ít gặp xung đột hơn với cascade và độ đặc hiệu.
- Bạn có thể tái sử dụng các lớp này trong các kết hợp khác nhau.
- Mã của bạn dễ bảo trì hơn.
Bạn thậm chí có thể áp dụng cả hai lớp cho cùng một phần tử nếu cần:
<div class="columns card">Điểm mấu chốt là mỗi lớp có một công việc cụ thể. Điều đó làm cho mọi thứ dễ dự đoán hơn và dễ làm việc hơn. Tám khái niệm này – mô hình hộp, độ đặc hiệu, kế thừa, đơn vị CSS, thuộc tính display, bố cục hiện đại, pseudo-classes và pseudo-elements, và thiết kế đáp ứng – tạo thành nền tảng của việc viết CSS tốt.
Khi bạn hiểu cách chúng hoạt động cùng nhau, CSS sẽ không còn cảm thấy như phép thuật (hoặc một nguồn gây thất vọng) nữa. Nó bắt đầu có ý nghĩa logic. Bạn không cần phải thành thạo tất cả những điều này cùng một lúc. Hãy bắt đầu với một cái, làm quen với nó, và chuyển sang cái tiếp theo. Nhưng việc hiểu những nguyên tắc cơ bản này sẽ giúp bạn tiết kiệm vô số giờ gỡ lỗi. Nó cũng sẽ giúp bạn tự tin hơn rất nhiều khi viết CSS.
Tham khảo: medium.com
Mẹo và thủ thuật CSS
Những gì từng đòi hỏi các thư viện JavaScript phức tạp hay trình soạn thảo đồ họa giờ đây có thể được thực hiện chỉ với vài dòng mã. Các hàm và phần tử giả mới đang mở ra cánh cửa cho hiệu suất, khả năng truy cập và tính năng động tốt hơn. Hãy cùng khám phá thế giới CSS hiện đại và khám phá những công cụ mạnh mẽ mà bạn nên bổ sung vào kho vũ khí của mình.
Kiểm soát phần tử động
Trước đây, để định dạng một phần tử dựa trên số lượng phần tử cùng cấp hoặc thứ tự của nó, chúng ta phải dùng đến:nth-childlogic rườm rà, hoặc thường xuyên hơn là JavaScript. Giờ đây, CSS có thể tự xử lý việc này, cho phép tạo ra các bố cục thực sự năng động.
số lượng anh chị em
Hàm này trả về tổng số phần tử ở cùng một cấp độ lồng nhau (bao gồm cả phần tử đó). Hàm này hoàn hảo để tạo lưới hoặc menu động, trong đó kích thước của phần tử phụ thuộc vào ngữ cảnh.
Trường hợp sử dụng:Tự động chia đều chiều rộng có sẵn giữa các mục danh sách, bất kể có bao nhiêu mục.
/* Chiều rộng động dựa trên số lượng anh chị em */
ul li {
width : calc ( 100% / sibling-count ());
transition : width 0.3s ease;
}
/* Khoảng cách phản hồi */
.grid-item {
flex : 1 1 calc ( 100% / sibling-count ());
margin : calc ( 10px / sibling-count ());
}
chỉ số anh chị em()
Hàm này trả về vị trí của một phần tử trong số các phần tử cùng loại (bắt đầu từ 1). Nó tương tự như:nth-child()lớp giả, nhưngsibling-index()có thể được sử dụng bên trong các hàm khác nhưcalc(), cho phép thực hiện logic toán học phức tạp.
Trường hợp sử dụng:Tạo hiệu ứng tầng hoặc hiệu ứng “quạt” hoặc tạo độ trễ hoạt ảnh theo trình tự.
ul li {
position : relative;
/* Dịch chuyển mỗi li tiếp theo sang phải theo lượng tăng dần */
transform : translateX ( calc (( sibling-index () - 1 ) * 15px ));
/* Tạo độ trễ hoạt ảnh tuyệt vời mà không cần viết JS */
animation-delay : calc ( sibling-index () * 100ms );
}Nhấn enter hoặc nhấp để xem hình ảnh ở kích thước đầy đủ

Hình ảnh và bố cục đáp ứng thế hệ tiếp theo
Việc quản lý đồ họa và kích thước trong CSS ngày càng trở nên linh hoạt và mạnh mẽ hơn, giải quyết đồng thời các vấn đề như độ phân giải màn hình và kích thước phần tử.
bộ hình ảnh()
Hàm này tương đương trực tiếp với<img srcset>thuộc tính HTML trong CSS. Nó cho phép trình duyệt chọn ảnh nền đẹp nhất từ một tập hợp dựa trên độ phân giải (1x,2x) hoặc định dạng (type) của màn hình.
Tại sao cần thiết:Đây là cách lý tưởng để xử lý hình ảnh nền cho màn hình Retina hoặc sử dụng các định dạng nén cao hiện đại như AVIF hoặc WebP với định dạng JPEG đơn giản cho các trình duyệt cũ hơn.
.hero-banner {
/* Trình duyệt sẽ chọn tùy chọn tối ưu nhất */
background-image : image-set (
/* Định dạng hiện đại với khả năng nén tốt nhất */
url ( "banner.avif" ) type ( "image/avif" ),
/* Định dạng hiện đại dự phòng tốt */
url ( "banner.webp" ) type ( "image/webp" ),
/* JPEG độ phân giải cao cho màn hình 2x */
url ( "banner-high-res.jpg" ) 2 x,
/* JPEG tiêu chuẩn cho màn hình 1x (dự phòng cuối cùng) */
url ( "banner-low-res.jpg" ) 1 x
);
}Nhấn enter hoặc nhấp để xem hình ảnh ở kích thước đầy đủ

conic-gradient()
Không giống như các gradient tuyến tính và xuyên tâm, gradient nàyconic-gradient()tạo ra sự chuyển màu xung quanh một điểm trung tâm, như thể bạn đang nhìn một hình nón từ trên cao.
Trường hợp sử dụng:Điều này mở ra những khả năng đơn giản để tạo đồ họa phức tạp như biểu đồ hình tròn, bánh xe màu và nền xuyên tâm độc đáo mà không cần sử dụng bất kỳ hình ảnh hoặc SVG nào.
.pie-chart {
width : 200px ;
height : 200px ;
border-radius : 50% ;
/* Định nghĩa các điểm dừng màu theo phần trăm xung quanh hình tròn */
background : conic-gradient (
gold 0% 40% , /* 40% của biểu đồ là màu vàng */
deepskyblue 40% 75% , /* 35% tiếp theo là màu xanh lam nhạt */
lightcoral 75% 100% /* 25% còn lại là màu san hô */
);
}
nội dung phù hợp()
Hàm nàyfit-content()kết hợp logic về kích thước thành một công thức duy nhất cực kỳ hữu ích:min(max-content, max(min-content, <length-percentage>)).
Nói một cách đơn giản:“Hãy làm cho cột này đủ rộng để vừa với nội dung của nó (max-content), nhưng không rộng hơn giá trị đã chỉ định (ví dụ:200px). Đồng thời, không để nó co lại nhỏ hơn kích thước tối thiểu có thể (min-content).”
Chức năng này là một bước đột phá trong việc xác định kích thước đường dẫn linh hoạt trong CSS Grid, đặc biệt là đối với thanh bên hoặc phần chứa.
.container {
display : grid;
grid-template-columns :
1 fr /* Nội dung chính linh hoạt */
fit-content ( 200px ) /* Thanh bên: vừa với nội dung, nhưng tối đa là 200px */
1 fr; /* Nội dung chính linh hoạt */
gap : 1rem ;
}
/* Trường hợp sử dụng: Thanh bên đáp ứng chỉ chiếm những gì cần thiết */
.layout {
grid-template-columns :
fit-content ( 300px ) /* Thanh bên vừa với nội dung, nhưng dừng ở chiều rộng tối đa 300px */
1 fr; /* Nội dung chính chiếm phần không gian còn lại */
}Nhấn enter hoặc nhấp để xem hình ảnh ở kích thước đầy đủ

gradient xuyên tâm
Hàm nàyradial-gradient()tạo ra một hiệu ứng chuyển màu tỏa ra từ một điểm gốc, với hình dạng có thể là hình tròn hoặc hình elip. Nó cho phép xếp chồng nhiều gradient để tạo ra các hiệu ứng phức tạp, hữu cơ như cực quang nền tinh tế.
Trường hợp sử dụng:Tạo nền động hoặc hiệu ứng đổ bóng phức tạp mà không cần sử dụng nội dung hình ảnh bên ngoài.
.aurora {
/* Xếp chồng nhiều gradient xuyên tâm để tạo hiệu ứng phát sáng khuếch tán */
background : radial-gradient (hình tròn ở 20% 20% , #ff00cc , trong suốt 40% ),
radial-gradient (hình tròn ở 80% 30% , #00f0ff , trong suốt 40% ),
radial-gradient (hình tròn ở 50% 80% , #ffea00 , trong suốt 40% );
background-color : #05010f ;
/* Sử dụng hoạt ảnh để dịch chuyển các gradient tạo thành một vòng lặp mê hoặc */
background-size : 200% 200% ;
hoạt ảnh : aurora 12 giây tuyến tính vô hạn;
}
@keyframes aurora {
0% { background-position : 0% 0% ; }
50% { background-position : 100% 100% ; }
100% { vị trí nền : 0% 0% ; }
}
gradient tuyến tính lặp lại
Hàm này tự động lặp lại một mẫu gradient tuyến tính trên nền của một phần tử. Đây là một công cụ tuyệt vời để tạo các mẫu phức tạp, sọc hoặc ô vuông và các bộ tải động.
Trường hợp sử dụng:Xây dựng nền sọc hoạt hình hiệu suất cao cho trình tải, thanh tiến trình hoặc các yếu tố trang trí.
.loader {
width : 200px ;
height : 20px ;
/* Định nghĩa một mẫu sọc nhỏ, hai màu, lặp lại ở góc 45 độ */
background : repetition-linear-gradient (
45deg ,
#23a6d5 ,
#23a6d5 10px ,
#23d5ab 10px ,
#23d5ab 20px
);
/* Hoạt ảnh dịch chuyển vị trí nền, khiến các sọc di chuyển */
background-size : 200% 200% ;
animation : stripes 2s linear infinite;
}
border-image-source
Thuộc tính này cho phép bạn sử dụng hình ảnh, SVG hoặc gradient làm đường viền của một phần tử, vượt xa các đường nét liền đơn giản. Điều này rất cần thiết để tạo các khung phức tạp, cách điệu.
border-image-slicevàborder-image-widthxác định cách hình ảnh được xếp theo ô và tỷ lệ trên đường viền./* Sử dụng gradient tuyến tính làm màu đường viền động */
.fancy-box {
border : 10px solid transparent; /* Bắt buộc để border-image hoạt động */
border-image-source : linear-gradient (sang phải, đỏ, vàng, xanh lá cây);
border-image-slice : 1 ; /* Đảm bảo hình ảnh được cắt để bao phủ toàn bộ đường viền */
}
/* Sử dụng tệp hình ảnh tùy chỉnh cho khung trang trí */
.framed-photo {
border : 20px solid transparent;
border-image-source : url ( "decorative-frame.jpg" );
border-image-slice : 30 ;
border-image-repeat : repeat;
}
Điều hướng và cuộn gốc liền mạch
Trong nhiều năm, các nhà phát triển đã dựa vào JavaScript phức tạp để tạo ra các vòng quay, thanh trượt và các thành phần cuộn tùy chỉnh, thường dẫn đến tình trạng tắc nghẽn hiệu suất và các vấn đề về khả năng truy cập. Cuối cùng, CSS cung cấp các giải pháp gốc và tinh tế.
::nút-cuộn()
Điều nàypseudo-elementcho phép bạn thêm các nút cuộn có thể truy cập trực tiếp vào vùng chứa với tính năng tràn. Không còn cần phải mô phỏng các nút bằng các phần tử div và trình xử lý sự kiện nữa.
Nó hoạt động như thế nào?Bạn chỉ cần chỉ định hướng (up,down,left, hoặcright) và thiết lập nội dung cho nút. Nội dung này có thể là văn bản, biểu tượng hoặc ký hiệu.
/* Ví dụ đơn giản về vùng chứa nằm ngang */
.carousel :: scroll-button (left) {
content : "⬅" ;
/* Bạn có thể thêm bất kỳ kiểu nào ở đây: kích thước, màu sắc, nền */
}
.carousel :: scroll-button (right) {
content : "⮕" ;
}
::scroll-marker và scroll-marker-group
Cặp thuộc tính này đưa khả năng điều khiển cuộn lên một tầm cao mới. Chúng cho phép bạn tạo các điểm đánh dấu (như các điểm chỉ báo chấm cho các slide trong vòng quay) được liên kết với các phần tử con trong một vùng chứa. Nhấp vào một điểm đánh dấu sẽ cuộn nhẹ nhàng vùng chứa đến phần tử tương ứng.
scroll-marker-group: Thuộc tính này “kích hoạt” cơ chế đánh dấu cho vùng chứa. Giá trị trước hoặc sau xác định vị trí nhóm đánh dấu sẽ xuất hiện—trước hoặc sau nội dung.::scroll-marker: Phần tử giả này định dạng chính các điểm đánh dấu. Bạn có thể biến chúng thành chấm, hình vuông hoặc bất kỳ hình dạng nào khác.
/* Tạo chỉ báo cho vòng quay */
.scroll-container {
/* Bật nhóm điểm đánh dấu sau nội dung */
scroll-marker-group: after;
scroll-snap-type : x bắt buộc; /* Để có hiệu ứng tốt hơn */
}
/* Định dạng chính các điểm đánh dấu */
.scroll-container ::scroll-marker {
content : "" ; /* Thuộc tính bắt buộc */
width : 12px ;
height : 12px ;
border-radius : 50% ;
border : 2px solid grey;
background-color : white;
}
/* Bạn thậm chí có thể định dạng điểm đánh dấu đang hoạt động! */
.scroll-container ::scroll-marker:active,
.scroll-container::scroll-marker:current {
background-color : dodgerblue;
border-color : dodgerblue;
}Tại sao cần thiết:Cách tiếp cận này mang tính nguyên bản, giúp nó có hiệu suất cao, mượt mà và dễ sử dụng ngay khi cài đặt cho người dùng điều hướng bằng bàn phím và trình đọc màn hình.

In ấn và thiết kế chuyên nghiệp
CSS từ lâu đã vượt ra ngoài phạm vi màn hình. Các thuộc tính này cho phép bạn kiểm soát chi tiết giao diện trang web trên giấy và cách sử dụng phông chữ hiện đại, nhiều màu sắc.
@font-palette-values
Quy@font-palette-valuestắc at cho phép bạn tùy chỉnh bảng màu được sử dụng trong phông chữ nhiều màu (như phông chữ COLR hoặc SVG). Nó cho phép bạn chọn giữa các bảng màu có sẵn của phông chữ hoặc tự xác định màu sắc tùy chỉnh của riêng bạn.
Cách thức hoạt động:Bạn định nghĩa tên bảng màu tùy chỉnh (có tiền tố là--), chỉ địnhfont-family, sau đó sử dụngoverride-colorsđể ánh xạ chỉ số màu (ví dụ:0,1) thành giá trị màu mới (sử dụnglch,rgb, v.v.). Sau đó, bảng màu được áp dụng bằngfont-palettethuộc tính này.
@font-palette-values --corporate {
font-family : "Bungee Spice" ;
override-colors:
/* Thay thế màu đầu tiên (chỉ số 0) bằng màu LCH tùy chỉnh */
0 lch ( 50% 100 40 ),
/* Thay thế màu thứ hai (chỉ số 1) bằng màu LCH khác */
1 lch ( 80% 90 290 );
}
h1 {
font-family : "Bungee Spice" ;
/* 2. Áp dụng bảng màu tùy chỉnh của chúng ta vào phần tử */
font -palette: --corporate;
}
palette-mix()
Dựa trên bảng màu tùy chỉnh,palette-mix()chức năng này cho phép bạn tạo giá trị bảng màu phông chữ mới bằng cách kết hợp hai bảng màu phông chữ hiện có (có sẵn hoặc tùy chỉnh) với nhau.
Ưu điểm:Cho phép tạo chủ đề màu động, độ trung thực cao cho phông chữ nhiều màu dựa trên sở thích của người dùng, chế độ sáng/tối hoặc sự thay đổi của thương hiệu. Bạn có thể kiểm soát tỷ lệ pha trộn và phương pháp nội suy màu (ví dụ:in lch,in srgb).
/* Trộn các bảng màu được định nghĩa bởi phông chữ */
h2 {
font -palette: palette-mix (trong lch, bình thường, tối);
}
/* Trộn các bảng màu tùy chỉnh được định nghĩa bởi tác giả */
.themed-header {
font -palette: palette-mix (trong lch, --blues 70% , --yellows 30% );
}
trẻ mồ côi và góa phụ
Những thuộc tính này rất quan trọng để tạo nên sự chuyên nghiệp cho trang web của bạn khi in. Chúng ngăn không cho các dòng riêng lẻ của một đoạn văn bị tách biệt trong quá trình ngắt trang.
- Dòng mồ côi:Dòng đầu tiên của đoạn văn được giữ nguyên ở cuối trang.
orphansThuộc tính này thiết lập số dòng tối thiểu phải còn lại ở cuối trang trước khi ngắt trang. - Góa phụ:Dòng cuối cùng của đoạn văn được giữ nguyên ở đầu trang mới.
widowsThuộc tính này thiết lập số dòng tối thiểu phải giữ nguyên ở đầu trang mới.
@media print {
p {
/* Cần ít nhất 3 dòng để giữ nguyên ở cuối trang */
orphans : 3 ;
/* Cần ít nhất 2 dòng để giữ nguyên ở đầu trang mới */
widows : 2 ;
}
}
in-màu-điều chỉnh
Theo mặc định, hầu hết các trình duyệt đều cố gắng tiết kiệm mực bằng cách bỏ qua màu nền và hình ảnh khi in.print-color-adjustThuộc tính này cho phép bạn ghi đè hành vi này.
economy(mặc định): Trình duyệt có thể tối ưu hóa lệnh in (thường bằng cách bỏ qua nền).exact: Yêu cầu trình duyệt in trang chính xác như trên màn hình, bao gồm tất cả hình nền và màu sắc.
@media print {
.important-section {
/* Đảm bảo nền được in */
print- color -adjust: exact;
background-color : #f0f8ff ;
}
}
CSS không còn chỉ là một ngôn ngữ định kiểu nữa; nó đang chuyển mình thành một công cụ mạnh mẽ để tạo ra các giao diện động, đáp ứng và dễ tiếp cận. Các hàm chúng tôi đã xem xét cho phép bạn giải quyết các vấn đề phức tạp một cách khai báo, với ít mã hơn và không cần dựa vào JavaScript. Hãy bắt đầu thử nghiệm chúng ngay hôm nay để giúp dự án của bạn luôn đi trước một bước.
Phong cách thích ứng trong CSS
CSS đã phát triển. Nó đã bổ sung thiết kế đáp ứng. Sau đó là truy vấn vùng chứa (container queries). Hiện tại, là truy vấn kiểu (style queries) với cú pháp phạm vi (range syntax). Hôm nay, tôi sẽ hướng dẫn cách vượt ra ngoài việc khớp kiểu chính xác. Bạn có thể xây dựng các thành phần thích ứng với ngưỡng số. Tôi đã thử điều này để xây dựng các hệ thống thành phần linh hoạt. Nó loại bỏ rất nhiều trở ngại. Chúng ta sẽ xem cách nó hoạt động. Chúng ta cũng sẽ xem các ứng dụng thực tế của nó. Và tại sao điều này thay đổi mọi thứ. Hãy bắt đầu với phần thú vị.
Khớp Kiểu Thích Ứng Trong CSS
Hãy tìm hiểu tính năng này. Nó cho phép bạn tạo kiểu đáp ứng dựa trên phạm vi số. Bạn không cần sử dụng JavaScript.
Trước đây, truy vấn kiểu hoạt động như sau. Thuộc tính tùy chỉnh của bạn hoặc khớp với một giá trị, hoặc không.
Ví dụ, style(--rainy: true) có nghĩa chính xác là true. Không có nghĩa nào khác.
/* Style query must be an exact match (old) */@container style(--rainy: true) {
.weather-card {
background: linear-gradient(140deg, skyblue, lightblue);
}
}Nhưng nếu bạn cần kiểm soát nhiều hơn thì sao?
Ví dụ, token khoảng cách của bạn là --padding: 1.5em. Bạn chỉ muốn kích hoạt thay đổi bố cục khi nó vượt quá 1em.
Hoặc độ mờ của thành phần là --opacity: 0.75. Bạn cần các hình ảnh khác nhau tùy thuộc vào việc nó vượt quá 50 phần trăm hay không.
Bạn sẽ gặp khó khăn. Bạn sẽ phải dùng đến các giải pháp thay thế calc() hoặc sử dụng JavaScript.
Chrome 142 đã thay đổi điều đó. Giờ đây, bạn có thể sử dụng các toán tử so sánh. Đó là >, <, >=, <=. Bạn dùng chúng trực tiếp trong các truy vấn kiểu của mình.
Điều này có nghĩa là bạn đang so sánh các giá trị số. Bạn không tìm kiếm các kết quả khớp chính xác.
/* Old way: exact matching only */@container style(--inner-padding: 1em) {
.card { border: 2px solid; }
}
/* New way: range comparisons */@container style(--inner-padding > 1em) {
.card {
border: 2px solid;
padding: 2rem;
}
}Trong ví dụ trên, quy tắc thứ hai áp dụng khi khoảng đệm vượt quá 1em.
Ngưỡng trở nên động. Nó không còn được mã hóa cứng.
Cách Cú Pháp Phạm Vi Hoạt Động Ngầm
Khi truy vấn kiểu của bạn chạy, trình duyệt kiểm tra cả hai vế của phép so sánh.
Chúng có cùng loại không?
Nếu có, điều kiện sẽ được chấp nhận hoặc không.
Nếu không, truy vấn sẽ trả về false.
Để phép so sánh hợp lệ, cả hai vế phải phân giải thành cùng một loại số.
CSS hỗ trợ các loại số sau cho phép so sánh phạm vi:
- length (px, em, rem, vh, vmin, vmax, vh, vw, vmin, vmax, etc.)
- number (số nguyên hoặc số thập phân không đơn vị)
- percentage (25%, 100%, etc.)
- angle (deg, grad, turn, rad)
- time (ms, s)
- frequency (Hz, kHz)
- resolution (dpi, dpcm)
Bạn có thể so sánh các thuộc tính tùy chỉnh. Bạn cũng có thể so sánh các giá trị cố định. Hoặc bạn có thể so sánh các giá trị được lấy từ thuộc tính HTML bằng attr().
Đây là sức mạnh của nó. Bạn không bị giới hạn bởi các số được mã hóa cứng.
/* Compare custom property to literal */@container style(--font-scale > 1.5) { }
/* Compare attribute to custom property */@container style(attr(data-level type(<integer>)) >= 50) { }
/* Compare two attributes */@container style(attr(data-current) > attr(data-threshold)) { }Cả hai vế được phân giải trước. Sau đó chúng được so sánh.
Nếu chúng khớp loại, truy vấn hoạt động. Nếu không, không có gì xảy ra.
Tại Sao Tính Năng Này Lại Tuyệt Vời
Hãy cùng tìm hiểu lý do tôi thích tính năng này:
- Giảm mã lặp lại (boilerplate): Trước đây, tôi phải viết nhiều truy vấn kiểu. Hoặc tôi phải sử dụng trình lắng nghe sự kiện JavaScript. Giờ đây, một truy vấn phạm vi duy nhất có thể làm được điều mà trước đây cần đến ba truy vấn.
- Không phụ thuộc JavaScript: Các thư viện theo dõi, quản lý trạng thái, trình xử lý sự kiện đều không cần nữa. Trình duyệt xử lý nó một cách tự nhiên.
- Các thành phần vẫn linh hoạt: Một thành phần thẻ (card component) không cần biết mọi giá trị khoảng đệm có thể có. Nó chỉ nói: “Nếu khoảng đệm vượt quá
1em, hãy hiển thị bố cục này.” Điều này hoạt động với bất kỳ giá trị khoảng đệm nào mà hệ thống thiết kế của bạn cung cấp.
Kết Hợp Cú Pháp Phạm Vi Với if()
Hàm if() của CSS kết hợp tuyệt vời với cú pháp phạm vi. Nó tạo ra logic điều kiện nội tuyến.
.component {
background-color: if(
style(--brightness > 60%): white;
style(--brightness > 30%): lightgray;
else: #222
);
border-width: if(
style(--emphasis > 7): 3px;
else: 1px
);
}Điều này giống như một toán tử ba ngôi (ternary operator).
Nhiều điều kiện, một khai báo.
Khi độ sáng vượt quá 60 phần trăm, sử dụng màu trắng.
Giữa 30 và 60 phần trăm, sử dụng màu xám nhạt.
Dưới 30 phần trăm, nền tối.
Toàn bộ giao diện của bạn thích ứng dựa trên một thuộc tính tùy chỉnh duy nhất.
Yêu Cầu Khớp Loại: Nơi Mọi Thứ Có Thể Gặp Lỗi
Đây là một điểm cần lưu ý. Nó sẽ gây ra lỗi nếu bạn không cẩn thận.
Cả hai vế của phép so sánh phải phân giải thành cùng một loại số.
Bạn không thể so sánh 20px với 1.5em mà không có sự chuẩn bị.
/* This works: both are lengths */@container style(--spacing > 1em) { }
/* This fails: length vs. unitless number */@container style(--spacing > 50) { } /* Wrong if --spacing is 1.5em */
/* This works: both are integers */@container style(attr(data-count type(<integer>)) > 5) { }
/* This fails: integer vs. percentage */@container style(attr(data-count type(<integer>)) > 50%) { }Nếu hệ thống thiết kế của bạn đặt --gutter: 2rem, hãy so sánh nó với các giá trị độ dài khác.
Phần trăm, số không đơn vị, góc là các loại khác nhau.
Việc trộn lẫn chúng có nghĩa là truy vấn của bạn sẽ thất bại một cách âm thầm.
Hãy kiểm tra các token thiết kế của bạn trước khi viết các phép so sánh.
Tính nhất quán về loại là rất quan trọng ở đây.
Ví Dụ 1: Cường Độ Màu Thẻ Động
Tôi sẽ hướng dẫn bạn qua một ví dụ đơn giản.
Bạn đang xây dựng một widget thời tiết. API của bạn trả về tỷ lệ phần trăm mưa.
Trước cú pháp phạm vi, bạn sẽ mã hóa cứng nhiều truy vấn khớp chính xác.
Bây giờ, hãy xem điều gì xảy ra:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<style>
.weather-container {
container-name: weather;
--rain-percent: attr(data-rain-percent type(<percentage>));
}
.weather-card {
background: linear-gradient(140deg, #ffd89b, #ffe6b3);
padding: 2rem;
border-radius: 8px;
}
/* Light drizzle: 0-30% */ @container style(--rain-percent <=30%) {
.weather-card {
background: linear-gradient(140deg, #ffd89b, #ffe6b3);
}
}
/* Moderate rain: 30-60% */ @container style(--rain-percent > 30%) and style(--rain-percent <=60%) {
.weather-card {
background: linear-gradient(140deg, #87ceeb, #b0e0e6);
}
}
/* Heavy rain: 60%+ */ @container style(--rain-percent > 60%) {
.weather-card {
background: linear-gradient(140deg, #4682b4, #5f9ea0);
}
}
</style>
</head>
<body>
<div class="weather-container" data-rain-percent="90%">
<div class="weather-card">
<h3>Tomorrow</h3>
<p>Rain expected</p>
</div>
</div>
</body>
</html>Thay đổi thuộc tính data-rain-percent. Nền thẻ của bạn sẽ thích ứng ngay lập tức.
Mưa nhẹ, gradient sáng. Mưa lớn, gradient tối.
Không cần JavaScript. Chỉ là khả năng phản ứng thuần túy của CSS.
Ví Dụ 2: Đưa Dữ Liệu Vào Kiểu Của Bạn Với attr()
Đây là nơi mọi thứ trở nên thực sự thú vị.
Bạn có thể truy vấn các thuộc tính HTML trực tiếp trong CSS. Bạn sử dụng hàm attr().
Hãy tưởng tượng một thẻ sản phẩm. Số lượng hàng tồn kho nằm trong HTML của bạn:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<style>
.container {
container-name: cardcontainer;
--data-stock: attr(data-stock type(<integer>));
}
.product {
border: 1px solid gray;
}
@container cardcontainer style(attr(data-stock type(<integer>)) < 10) {
.product {
border: 2px solid orange;
background-color: if(style(--data-stock < 4): orange;
style(--data-stock < 8): yellow;
else: white);
}
[data-label="stock"] {
color: #ff6b35;
font-weight: bold;
}
}
@container cardcontainer style(attr(data-stock type(<integer>)) < 5) {
[data-label="stock"]::after {
content: " — Hurry!";
}
}
</style>
</head>
<body>
<div class="container" data-stock="9">
<div class="product">
<h3>Awesome Widget</h3>
<p data-label="stock">9 in stock</p>
</div>
</div>
</body>
</html>Khi hàng tồn kho giảm xuống dưới 10, viền chuyển sang màu cam.
Dưới 5, một cảnh báo xuất hiện.
Hỗ Trợ Trình Duyệt: Chrome Đi Đầu, Các Trình Khác Sẽ Theo Sau
Đây là thực tế: tính đến tháng 12 năm 2025, cú pháp phạm vi hoạt động trên Chrome 142 trở lên. Nó chưa hoạt động ở bất kỳ nơi nào khác.
Firefox, Safari và Edge đang theo dõi đặc tả. Nhưng chúng chưa triển khai tính năng này.
Nếu bạn đang triển khai mã sản xuất hôm nay, bạn cần một chiến lược dự phòng.
Sử dụng @supports để phát hiện hỗ trợ tính năng:
.component {
color: darkgray; /* Fallback for unsupported browsers */}
@supports (background: if(style(--theme: dark): black; else: white)) {
.component {
color: if(style(--theme: dark): white; else: black);
}
}Hiện tại, hãy coi đây là một cải tiến lũy tiến (progressive enhancement).
Sử dụng nó trong các bảng điều khiển, hệ thống thiết kế hoặc thư viện thành phần. Nơi người dùng của bạn sử dụng các trình duyệt cập nhật.
Kết Luận Cuối Cùng
Cú pháp phạm vi cho truy vấn kiểu không phải là sự thay thế. Nó không thay thế truy vấn phương tiện (media queries) hoặc truy vấn kích thước vùng chứa (container size queries).
Nó sẽ không giải quyết mọi vấn đề thiết kế đáp ứng.
Nhưng nếu bạn cần các kiểu phản hồi ngưỡng số trong token thiết kế của mình, nó là hoàn hảo.
Điểm mấu chốt là sự đơn giản.
Khi bạn bắt đầu sử dụng nó, bạn sẽ nhận ra JavaScript đã gây ra bao nhiêu trở ngại.
Bạn sẽ muốn sử dụng nó ở mọi nơi. Hãy chống lại sự cám dỗ đó.
Hãy sử dụng nó một cách chiến lược. Sử dụng ở những nơi thích ứng ngữ nghĩa là quan trọng.
Hãy bắt đầu thử nghiệm trong Chrome ngay hôm nay.
Hãy thử lấy các giá trị thuộc tính vào kiểu của bạn. Hãy so sánh các thuộc tính tùy chỉnh. Và xây dựng các thành phần thích ứng mà không cần một dòng JavaScript nào.
Tôi rất muốn xem những gì bạn xây dựng với tính năng này. Hãy để lại ví dụ của bạn trong phần bình luận.
Tham khảo: medium.com

Bài viết liên quan: