Tính kế thừa

Podcast CSS – 005: Tính kế thừa

Giả sử bạn vừa viết một số CSS để làm cho 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 bài viết nội dung, có giá trị class.my-button. Tuy nhiên có một vấn đề, văn bản không phải là màu bạn mong đợi. Việc 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 đã 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 tính 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>

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

html {
  color: lightslategray;
}

Thuộc tính color được các phần tử khác kế thừa theo mặc định. Phần tử htmlcolor: lightslategray, do đó, tất cả cá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ử được lồng sâu nhất. Tính kế thừa chỉ di chuyển xuống dưới, không sao lưu sang 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 vẫn có nhiều thuộc tính như vậy. Để tham khảo, dưới đây là toàn bộ danh sách các thuộc tính được kế thừa theo mặc định, được lấy từ tệp tham chiếu W3 của tất cả các thuộc tính CSS:

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

Mỗi phần tử HTML có mọi thuộc tính CSS được xác định theo mặc định với 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 mặc định nếu tầng không tính toán được giá trị cho phần tử đó.

Các thuộc tính có thể kế thừa xếp tầng xuống dưới, còn các phần tử con sẽ nhận được giá trị đã 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 phần tử mẹ đã đặt font-weight thành bold, thì tất cả các phần tử con sẽ được in đậm, trừ khi 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ó giá trị font-weight cho phần tử đó.

Cách kế thừa và kiểm soát tính 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ụ để trợ giúp việc đó.

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 thành phần 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 ngoại lệ.

strong {
  font-weight: 900;
}

Đoạn mã CSS này đặt tất cả các phần tử <strong> để có 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. Để làm cho các phần tử <strong> bên trong .my-component cũng font-weight: 500, hãy thêm:

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

Bây giờ, 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 giá trị đó.

Từ khoá initial

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

Bạn đã tìm hiểu trước đó rằng mỗi thuộc tính đều có một giá trị mặc định trong CSS. Từ khoá initial sẽ đặt một thuộc tính về giá trị mặc định ban đầu đó.

aside strong {
  font-weight: initial;
}

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

Từ khoá unset

Thuộc tính unset sẽ hoạt động theo cách khác 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.

Việc ghi nhớ những thuộc tính CSS nào được kế thừa theo mặc định có thể không dễ dàng, nhưng unset có thể hữu ích trong bối 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 mã này:

/* 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 bị xoá và color chuyển về giá trị kế thừa tính toán.

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 kiểu p chung có thêm một vài thuộc tính? Chỉ quy tắc bạn đã đặ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ì bất kể kiểu chung nào được áp dụng cho p trong tương lai, chúng sẽ luôn bị huỷ đặt.

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

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

Thuộc tính nào sau đây có thể kế thừa?

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

Giá trị nào sẽ hoạt động như inherit trừ phi không có gì để kế thừa và sau đó sẽ 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