Tính kế thừa

CSS Podcast – 005: Kế thừa

Giả sử bạn vừa viết một số CSS để các phần tử trông giống như một nút.

<a href="http://example.com" class="my-button">I am a button link</a> 
.my-button {   display: inline-block;   padding: 1rem 2rem;   text-decoration: none;   background: pink;   font: inherit;   text-align: center; } 

Sau đó, bạn thêm một phần tử đường liên kết vào một bài viết nội dung, với giá trị class.my-button. Tuy nhiên, có một vấn đề là văn bản không có màu như bạn mong đợi. Tại sao điều này lại xảy ra?

Một số thuộc tính CSS sẽ kế thừa nếu bạn không chỉ định giá trị cho các thuộc tính đó. Trong trường hợp nút này, nút đã kế thừa color từ CSS này:

article a {   color: maroon; } 

Trong bài học này, bạn sẽ tìm hiểu lý do xảy ra hiện tượng đó và cách kế thừa là một tính năng mạnh mẽ giúp bạn viết ít CSS hơn.

Luồng kế thừa

Hãy xem cách hoạt động của tính kế thừa bằng cách sử dụng đoạn mã HTML này:

<html>   <body>     <article>       <p>Lorem ipsum dolor sit amet.</p>     </article>   </body> </html> 

Phần tử gốc (<html>) sẽ không kế thừa bất cứ điều gì vì đây là phần tử đầu tiên trong tài liệu. Thêm một số CSS vào phần tử HTML và CSS đó sẽ bắt đầu xếp tầng xuống tài liệu.

html {   color: lightslategray; } 

Theo mặc định, các phần tử khác sẽ kế thừa thuộc tính color. Phần tử htmlcolor: lightslategray, do đó, tất cả phần tử có thể kế thừa màu sẽ có màu lightslategray.

body {   font-size: 1.2em; } 
p {   font-style: italic; } 

Chỉ <p> mới có văn bản in nghiêng vì đây là phần tử lồng sâu nhất. Hoạt động kế thừa chỉ diễn ra theo hướng xuống dưới, chứ không quay ngược lên các phần tử gốc.

Những thuộc tính nào được kế thừa theo mặc định?

Theo mặc định, không phải tất cả các thuộc tính CSS đều được kế thừa, nhưng có rất nhiều thuộc tính được kế thừa. Để tham khảo, đây là toàn bộ danh sách các thuộc tính được kế thừa theo mặc định, lấy từ tài liệu tham khảo W3 về tất cả các thuộc tính CSS:

Cách hoạt động của tính năng kế thừa

Theo mặc định, mọi phần tử HTML đều có mọi thuộc tính CSS được xác định bằng một giá trị ban đầu. Giá trị ban đầu là một thuộc tính không được kế thừa và xuất hiện dưới dạng giá trị mặc định nếu tầng không tính được giá trị cho phần tử đó.

Các thuộc tính có thể được kế thừa sẽ xếp tầng xuống dưới và các phần tử con sẽ nhận được một giá trị được tính toán, thể hiện giá trị của phần tử mẹ. Điều này có nghĩa là nếu một phần tử mẹ có font-weight được đặt thành bold thì tất cả các phần tử con sẽ được in đậm, trừ phi font-weight của các phần tử con được đặt thành một giá trị khác hoặc biểu định kiểu tác nhân người dùng có một giá trị cho font-weight của phần tử đó.

Cách kế thừa rõ ràng và kiểm soát hoạt động kế thừa

Tính kế thừa có thể ảnh hưởng đến các phần tử theo những cách không mong muốn, vì vậy CSS có các công cụ để hỗ trợ việc này.

Từ khoá inherit

Bạn có thể làm cho bất kỳ thuộc tính nào kế thừa giá trị được tính toán của thuộc tính mẹ bằng từ khoá inherit. Một cách hữu ích để sử dụng từ khoá này là tạo các trường hợp ngoại lệ.

strong {   font-weight: 900; } 

Đoạn mã CSS này đặt tất cả các phần tử <strong>font-weight900, thay vì giá trị bold mặc định, tương đương với font-weight: 700.

.my-component {   font-weight: 500; } 

Lớp .my-component đặt font-weight thành 500. Để các phần tử <strong> bên trong .my-component cũng là font-weight: 500, hãy thêm:

.my-component strong {   font-weight: inherit; } 

Giờ đây, các phần tử <strong> bên trong .my-component sẽ có font-weight500.

Bạn có thể đặt giá trị này một cách rõ ràng, nhưng nếu sử dụng inherit và CSS của .my-component thay đổi trong tương lai, bạn có thể đảm bảo rằng <strong> sẽ tự động cập nhật theo giá trị đó.

Từ khoá initial

Tính kế thừa có thể gây ra vấn đề với các phần tử của bạn và initial cung cấp cho bạn một lựa chọn đặt lại mạnh mẽ.

Trước đó, bạn đã biết rằng mọi thuộc tính đều có giá trị mặc định trong CSS. Từ khoá initial đặt một thuộc tính trở lại giá trị mặc định ban đầu đó.

aside strong {   font-weight: initial; } 

Đoạn mã này sẽ xoá độ đậm của tất cả các phần tử <strong> bên trong một phần tử <aside> và thay vào đó, đặt độ đậm của các phần tử này thành bình thường (giá trị ban đầu).

Từ khoá unset

Thuộc tính unset hoạt động khác nhau nếu một thuộc tính được kế thừa theo mặc định hay không. Nếu một thuộc tính được kế thừa theo mặc định, thì từ khoá unset sẽ giống với inherit. Nếu theo mặc định, thuộc tính không được kế thừa, thì từ khoá unset sẽ bằng initial.

Việc nhớ những thuộc tính CSS được kế thừa theo mặc định có thể khó khăn, unset có thể hữu ích trong trường hợp đó. Ví dụ: color được kế thừa theo mặc định, nhưng margin thì không, vì vậy, bạn có thể viết như sau:

/* Global color styles for paragraph in authored CSS */ p {   margin-top: 2em;   color: goldenrod; }  /* The p needs to be reset in asides, so you can use unset */ aside p {   margin: unset;   color: unset; } 

Giờ đây, margin sẽ bị xoá và color sẽ trở lại thành giá trị được tính toán kế thừa.

Bạn cũng có thể dùng giá trị unset với thuộc tính all. Quay lại ví dụ trước, điều gì sẽ xảy ra nếu các kiểu p chung có thêm một vài thuộc tính? Chỉ quy tắc được đặt cho margincolor mới được áp dụng.

/* Global color styles for paragraph in authored CSS */ p {     margin-top: 2em;     color: goldenrod;     padding: 2em;     border: 1px solid; }  /* Not all properties are accounted for anymore */ aside p {     margin: unset;     color: unset; } 

Nếu bạn thay đổi quy tắc aside p thành all: unset, thì không quan trọng kiểu toàn cục nào được áp dụng cho p trong tương lai, chúng sẽ luôn được huỷ đặt.

aside p {     margin: unset;     color: unset;     all: unset; } 

Từ khoá revert

Như bạn đã tìm hiểu trong bài học về thứ tự ưu tiên, các kiểu đến từ nhiều nguồn khác nhau: kiểu cơ sở của tác nhân người dùng, kiểu theo lựa chọn ưu tiên của người dùng và kiểu do bạn tạo. Từ khoá revert sẽ huỷ các kiểu được đặt trong cùng một nguồn mà từ khoá revert được dùng.

Điều này hữu ích khi bạn đã đặt một kiểu nhưng không muốn áp dụng kiểu đó trong một số trường hợp. Trong khi inherit, initialunset chỉ định cách tính giá trị của một kiểu, thì revert chỉ định rằng các kiểu khác mà bạn đã viết không áp dụng.

p {   padding: 2em; }  aside p {   padding: revert; } 

Đoạn mã này cung cấp khoảng đệm cho các phần tử <p>, nhưng khi phần tử <p> nằm trong <aside>, thì đoạn mã này hoàn toàn không chỉ định padding. Thay vào đó, nó sẽ quay về kiểu ưu tiên của người dùng (nếu có) hoặc kiểu cơ bản của tác nhân người dùng.

Từ khoá revert-layer

Các lớp xếp tầng là một cách hữu ích để sắp xếp các kiểu và ưu tiên các kiểu trong nguồn gốc của tác giả trong lớp xếp tầng. Từ khoá revert-layer tương tự như revert, nhưng thay vì chỉ định rằng không có kiểu tác giả nào được áp dụng cho một thuộc tính, từ khoá này chỉ huỷ các kiểu trong lớp hiện tại.

Nếu đang sử dụng một thư viện giao diện người dùng của bên thứ ba, thì một mẫu hữu ích là nhập thư viện đó vào một lớp và thêm mọi chế độ ghi đè vào một lớp có mức độ ưu tiên cao hơn. Sau đó, bạn có thể xoá một chế độ ghi đè bằng cách sử dụng revert-layer và chế độ này sẽ sử dụng các giá trị mặc định của thư viện giao diện người dùng.

Nếu không có lớp nào khác chỉ định giá trị cho thuộc tính này, thì thuộc tính này sẽ hoạt động như revert và sử dụng giá trị từ một nguồn gốc trước đó.

Kiểm tra mức độ hiểu biết của bạn

Kiểm tra kiến thức của bạn về tính kế thừa

Theo mặc định, thuộc tính nào sau đây được kế thừa?

animation
Ảnh động không được truyền xuống cho các thành phần con.
font-size
🎉
color
🎉
text-align
🎉
line-height
🎉

Giá trị nào hoạt động như inherit trừ phi không có gì để kế thừa và sau đó hoạt động như initial?

reset
không phải là giá trị hợp lệ, hãy thử lại!
unset
🎉
superset
không phải là giá trị hợp lệ, hãy thử lại!

Tài nguyên