Kế thừa trong SASS

Kế thừa trong SASS

Bài viết này giải thích về tính kế thừa trong SASS.

Chúng tôi sẽ giải thích tính kế thừa trong SASS với các ví dụ thực tế.

YouTube Video

Kế thừa trong SASS

Kế thừa trong SASS (@extend) là một cơ chế cho phép bạn áp dụng các kiểu của một bộ chọn sang bộ chọn khác mà không bị trùng lặp. Vì cùng một kiểu được 'kết hợp' và xuất ra cho nhiều phần tử trong mã nguồn, CSS kết quả sẽ ít bị dư thừa hơn; tuy nhiên, nếu sử dụng không đúng cách, có thể dẫn đến việc kết hợp bộ chọn không mong muốn.

Cơ bản: Cách sử dụng @extend

Dưới đây là một ví dụ cơ bản nơi .btn--primary kế thừa các kiểu từ .btn. @extend là một chỉ thị dùng để mở rộng bộ chọn mục tiêu.

 1// Base button styles
 2.btn {
 3  padding: 0.5rem 1rem;
 4  border-radius: 4px;
 5  border: 1px solid #ccc;
 6  background: white;
 7  color: #333;
 8}
 9
10/* Primary button extends the base .btn */
11.btn--primary {
12  @extend .btn;
13  background: #007bff;
14  color: white;
15}
  • Bằng cách sử dụng @extend, .btn--primary kế thừa các kiểu cơ bản từ .btn và chỉ ghi đè những phần cần thiết.

CSS được tạo ra

 1.btn, .btn--primary {
 2  padding: 0.5rem 1rem;
 3  border-radius: 4px;
 4  border: 1px solid #ccc;
 5  background: white;
 6  color: #333;
 7}
 8
 9.btn--primary {
10  background: #007bff;
11  color: white;
12}

Thực tiễn tốt nhất: Sử dụng Placeholder (%placeholder)

Các bộ chọn placeholder (%name) là các bộ chọn sẽ không được xuất ra CSS. Chúng được sử dụng rộng rãi, đặc biệt khi bạn muốn chia sẻ an toàn các kiểu chung chỉ cho mục đích kế thừa giữa nhiều thành phần.

 1// %placeholder will not be output directly
 2%card-base {
 3  padding: 1rem;
 4  border-radius: 6px;
 5  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
 6  background: #fff;
 7}
 8
 9/* Components extend the placeholder */
10.card {
11  @extend %card-base;
12  border: 1px solid #eee;
13}
14
15.panel {
16  @extend %card-base;
17  border: 1px solid #ddd;
18}
  • .card.panel đều kế thừa từ %card-base, cho phép chúng chia sẻ các kiểu chung đồng thời bổ sung sự khác biệt khi cần thiết.

CSS được tạo ra

 1.card, .panel {
 2  padding: 1rem;
 3  border-radius: 6px;
 4  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
 5  background: #fff;
 6}
 7
 8.card {
 9  border: 1px solid #eee;
10}
11
12.panel {
13  border: 1px solid #ddd;
14}

Kế thừa đa cấp (Nhiều @extend)

Bạn có thể kế thừa nhiều placeholder hoặc class cùng lúc. Mặc dù khả năng tái sử dụng kiểu được cải thiện, nhưng quan trọng là bạn cần theo dõi các quy tắc nào được kết hợp với các bộ chọn nào.

 1%btn-base {
 2  display: inline-block;
 3  padding: 0.5rem 1rem;
 4  border-radius: 3px;
 5}
 6
 7%btn-large {
 8  padding: 0.75rem 1.5rem;
 9  font-size: 1.125rem;
10}
11
12/* Composite button that extends both placeholders */
13.btn--lg {
14  @extend %btn-base;
15  @extend %btn-large;
16  background: #222;
17  color: #fff;
18}
  • Đây là một ví dụ trong đó một nút kế thừa hai placeholder, một cho 'base' và một cho 'size'.
  • .btn--lg kế thừa cả %btn-base%btn-large, kết hợp bố cục cơ bản với kích thước lớn hơn.

CSS được tạo ra

1.btn--lg {
2  display: inline-block;
3  /* %btn-large overrides the padding from %btn-base */
4  padding: 0.75rem 1.5rem;
5  border-radius: 3px;
6  font-size: 1.125rem;
7  background: #222;
8  color: #fff;
9}

Hành vi của @extend (Cơ chế kết hợp) và Lưu ý về 'Bùng nổ bộ chọn'

@extend xuất tất cả các bộ chọn phù hợp đã được kết hợp, điều này đôi khi dẫn đến sự kết hợp các bộ chọn ngoài ý muốn.

Ví dụ dưới đây cho thấy cách đầu ra có thể tăng lên khi cùng một class cơ bản được mở rộng ở nhiều nơi.

 1/* Many components extend .utility */
 2/* A generic utility class */
 3.utility {
 4  margin-bottom: 1rem;
 5}
 6
 7/* Nested selectors that extend .utility */
 8.header {
 9  @extend .utility;
10  .title {
11    font-weight: bold;
12  }
13}
14
15.footer {
16  @extend .utility;
17  .note {
18    color: #888;
19  }
20}
21
22.article {
23  @extend .utility;
24  .content {
25    line-height: 1.6;
26  }
27}
28
29.sidebar {
30  @extend .utility;
31  .section {
32    padding: 1rem;
33  }
34}
  • Khi nhiều thành phần kế thừa .utility, các bộ chọn sẽ được kết hợp thành một, trong những dự án lớn có thể gây ra sự phình to của CSS.

CSS được tạo ra

 1.utility,
 2.header,
 3.footer,
 4.article,
 5.sidebar {
 6  margin-bottom: 1rem;
 7}
 8
 9.header .title {
10  font-weight: bold;
11}
12
13.footer .note {
14  color: #888;
15}
16
17.article .content {
18  line-height: 1.6;
19}
20
21.sidebar .section {
22  padding: 1rem;
23}

@extend với .class so với Bộ chọn phần tử (Tag) — Ưu tiên và Tác động phụ

@extend có thể được áp dụng không chỉ cho class mà còn cho các bộ chọn phần tử. Tuy nhiên, mở rộng phần tử sẽ làm tăng phạm vi bị ảnh hưởng, dẫn đến nguy cơ các quy tắc được áp dụng một cách vô ý tại những nơi không mong muốn.

Dưới đây là ví dụ về việc mở rộng một bộ chọn phần tử và tác động của nó.

 1/* Extending an element selector (not recommended) */
 2h1 {
 3  font-size: 2rem;
 4  margin-bottom: 0.5rem;
 5}
 6
 7/* If you extend h1, the resulting selector will include your class with h1 */
 8.title {
 9  @extend h1;
10  color: #333;
11}
12
13/* Output becomes:
14h1, .title { font-size: 2rem; margin-bottom: 0.5rem; }
15*/
  • Trong ví dụ này, kế thừa bộ chọn phần tử h1 khiến .title được kết hợp với cùng kiểu như h1.
  • Mặc dù điều này có vẻ tiện lợi trong các trường hợp dự án nhỏ, nhưng khi dự án phát triển lớn hơn, các quy tắc cho h1 có thể kết hợp bất ngờ với .title, khiến các kiểu trở nên phức tạp và giảm tính bảo trì. Vì vậy, việc thiết kế kiểu dựa chủ yếu vào các class và placeholder sẽ giúp dễ dàng bảo trì hơn.

CSS được tạo ra

1h1,
2.title {
3  font-size: 2rem;
4  margin-bottom: 0.5rem;
5}
6
7.title {
8  color: #333;
9}

Trường hợp sử dụng của @extend!optional

Nếu bạn chỉ định !optional cùng với @extend, bạn có thể tránh được lỗi khi đối tượng kế thừa không tồn tại. Điều này đặc biệt hữu ích trong những đoạn mã giống thư viện hoặc các trường hợp placeholder được định nghĩa dựa trên điều kiện.

Sau đây là ví dụ về việc thử kế thừa một class có thể không tồn tại một cách an toàn, bằng cách sử dụng !optional.

1/* Try to extend a class that might not exist */
2.component {
3  @extend .maybe-existing !optional;
4  padding: 1rem;
5}
  • Nếu .maybe-existing không tồn tại, sẽ không có gì xảy ra và nó sẽ bị bỏ qua. Bạn có thể sử dụng điều này khi muốn thực hiện mở rộng một cách an toàn.

CSS được tạo ra

1.component {
2  padding: 1rem;
3}

So sánh giữa @extend và Mixins (@mixin / @include)

@extend@mixin đôi khi có mục đích tương tự, nhưng kết quả đầu ra và trường hợp sử dụng lại khác nhau.

  • @extend

    • CSS được tạo ra giúp giảm dư thừa bằng cách kết hợp bộ chọn.
    • Vì các bộ chọn được kết hợp sau khi tạo ra, nên có thể xảy ra sự kết hợp ngoài ý muốn.
    • Không thể truyền tham số (mặc dù có thể bù đắp bằng cách kết hợp placeholder).
  • @mixin / @include

    • Mỗi lần gọi sẽ sao chép các kiểu (gây ra đầu ra dư thừa).
    • Bạn có thể truyền tham số và bao gồm logic như điều kiện hoặc vòng lặp.
    • Đầu ra dễ dự đoán hơn, nhưng kích thước tệp tăng lên.

Dưới đây là sự so sánh khi sử dụng cả @mixin@extend để triển khai cùng một kiểu nút.

 1/* Mixin approach */
 2@mixin btn-styles($bg, $color) {
 3  display: inline-block;
 4  padding: 0.5rem 1rem;
 5  background: $bg;
 6  color: $color;
 7  border-radius: 4px;
 8}
 9
10/* Use mixin */
11.btn {
12  @include btn-styles(white, #333);
13}
14
15.btn--primary {
16  @include btn-styles(#007bff, white);
17}
18
19/* Extend approach (shared placeholder) */
20%btn-base {
21  display: inline-block;
22  padding: 0.5rem 1rem;
23  border-radius: 4px;
24}
25
26.btn2 {
27  @extend %btn-base;
28  background: white;
29  color: #333;
30}
31
32.btn2--primary {
33  @extend %btn-base;
34  background: #007bff;
35  color: white;
36}
  • @mixin cho phép bạn chèn kiểu một cách linh hoạt, trong khi @extend hợp nhất đầu ra hiệu quả, vì vậy bạn có thể sử dụng từng cách phù hợp với trường hợp cụ thể.

CSS được tạo ra

Đầu ra từ @mixin
 1.btn {
 2  display: inline-block;
 3  padding: 0.5rem 1rem;
 4  background: white;
 5  color: #333;
 6  border-radius: 4px;
 7}
 8
 9.btn--primary {
10  display: inline-block;
11  padding: 0.5rem 1rem;
12  background: #007bff;
13  color: white;
14  border-radius: 4px;
15}
Đầu ra từ @extend
 1.btn2,
 2.btn2--primary {
 3  display: inline-block;
 4  padding: 0.5rem 1rem;
 5  border-radius: 4px;
 6}
 7
 8.btn2 {
 9  background: white;
10  color: #333;
11}
12
13.btn2--primary {
14  background: #007bff;
15  color: white;
16}

Hướng dẫn thực tiễn

Kế thừa trong SASS là một tính năng mạnh mẽ giúp tăng khả năng tái sử dụng kiểu. Tuy nhiên, nếu sử dụng sai, việc kết hợp kiểu có thể trở nên phức tạp và giảm khả năng bảo trì. Dưới đây là một số điểm chính để sử dụng tính năng kế thừa một cách an toàn và hiệu quả.

  • Hãy sử dụng placeholder cho các kiểu hoàn toàn chung như cấu trúc và bố cục giữa các thành phần. Ngoài ra, nếu cần tham số hóa động, bạn có thể sử dụng @mixin.
  • Bạn nên tránh kế thừa trực tiếp các phần tử HTML như h1. Có thể xảy ra các tổ hợp bộ chọn ngoài ý muốn, dẫn đến CSS được sinh ra không như mong đợi.
  • Sử dụng quy tắc đặt tên như BEM hoặc tiền tố rõ ràng để phân biệt mục đích của từng placeholder giúp đảm bảo an toàn.
  • Sử dụng @extend trong cùng một tệp sẽ an toàn hơn. Đặc biệt với các dự án lớn, bạn nên thiết kế kế thừa trong phạm vi của từng thành phần để dễ dàng quản lý mối quan hệ kế thừa.

Tóm tắt

Tính năng @extend trong SASS là một cách thuận tiện để tái sử dụng các kiểu chung một cách hiệu quả và đảm bảo tính nhất quán cho thiết kế. Tuy nhiên, vì các kết hợp bộ chọn dễ trở nên phức tạp, bạn cần sử dụng tính năng này một cách cẩn trọng và trong phạm vi giới hạn. Bằng cách nhóm các kiểu chia sẻ bằng các bộ chọn placeholder (%placeholder) và sử dụng @mixin cho những phần cần tham số hóa động, bạn có thể duy trì một thiết kế đơn giản và dễ bảo trì.

Bạn có thể làm theo bài viết trên bằng cách sử dụng Visual Studio Code trên kênh YouTube của chúng tôi. Vui lòng ghé thăm kênh YouTube.

YouTube Video