Tính kế thừa

The 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. Điều này đã xảy ra như thế nào?

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 của nút này, nút này 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 điều đó xảy ra 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 sau:

<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 kỳ phần tử nào 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 đổ 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, vì vậy, tất cả các phần tử có thể kế thừa màu sắc hiện 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. Tính kế thừa chỉ diễn ra theo chiều đi xuống, chứ không quay lại các phần tử mẹ.

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, sau đâ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 hiệu ứng lũy thừa không tính được giá trị cho phần tử đó.

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

Cách kế thừa và kiểm soát việc kế thừa một cách rõ ràng

Tính kế thừa có thể ảnh hưởng đến các phần tử theo cách không mong muốn, vì vậy, CSS có các công cụ để giúp giải quyết vấn đề đó.

Từ khoá inherit

Bạn có thể khiến 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 ngoại lệ.

strong {
  font-weight: 900;
}

Đoạn mã CSS này đặt tất 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;
}

Thay vào đó, 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.

Từ khoá initial

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

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

aside strong {
  font-weight: initial;
}

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

Từ khoá unset

Thuộc tính unset sẽ hoạt động theo cách 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 thuộc tính không được kế thừa theo mặc định, thì từ khoá unset sẽ bằng initial.

Bạn có thể khó nhớ được thuộc tính CSS nào được kế thừa theo mặc định, unset có thể hữu ích trong ngữ cảnh đó. 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;
}

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

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

/* 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ì kiểu toàn cục nào được áp dụng cho p trong tương lai cũng không quan trọng, vì chúng sẽ luôn bị huỷ thiết lập.

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

Kiểm tra mức độ hiểu biết

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

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

animation
Ảnh động không truyền xuống phần tử 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