Dziedziczenie w SASS
Ten artykuł wyjaśnia dziedziczenie w SASS.
Wyjaśnimy dziedziczenie w SASS na praktycznych przykładach.
YouTube Video
Dziedziczenie w SASS
Dziedziczenie w SASS (@extend) to mechanizm pozwalający zastosować style jednego selektora do innego bez duplikacji. Ponieważ te same style są ‘łączone’ i generowane dla wielu elementów w kodzie, wynikowy CSS jest mniej podatny na zbędne powtórzenia; jednakże, przy niewłaściwym użyciu, może prowadzić do niezamierzonych połączeń selektorów.
Podstawy: jak używać @extend
Poniżej znajduje się podstawowy przykład, gdzie .btn--primary dziedziczy style po .btn. @extend to dyrektywa, która rozszerza wskazany selektor.
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}- Dzięki zastosowaniu
@extend,.btn--primarydziedziczy bazowe style z.btn, nadpisując tylko te części, które są potrzebne.
Wygenerowany CSS
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}Najlepsza praktyka: używanie placeholderów (%placeholder)
Selektory zastępcze (%name) to selektory, które nie są generowane w CSS. Są szeroko stosowane szczególnie wtedy, gdy chcesz bezpiecznie dzielić wspólne style wyłącznie do dziedziczenia pomiędzy wieloma komponentami.
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}.cardi.paneldziedziczą po%card-base, co pozwala im dzielić wspólne style oraz dodawać różnice w razie potrzeby.
Wygenerowany CSS
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}Wielokrotne dziedziczenie (wiele @extend)
Możesz dziedziczyć po wielu selektorach placeholder lub klasach jednocześnie. Choć ponowne użycie stylów zostaje zwiększone, ważne jest, aby śledzić, które reguły są łączone z którymi selektorami.
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}- To przykład, gdzie przycisk dziedziczy dwa placeholdery – jeden dla 'bazowych' stylów i drugi dla 'rozmiaru'.
.btn--lgdziedziczy zarówno%btn-base, jak i%btn-large, łącząc bazowy układ z większym rozmiarem.
Wygenerowany CSS
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}Zachowanie @extend (mechanizm łączenia) i ostrzeżenie przed 'eksplozją selektorów'
@extend łączy wszystkie pasujące selektory razem, co czasem może prowadzić do niezamierzonych kombinacji selektorów.
Poniższy przykład pokazuje, jak wynikowy kod może się powiększyć, gdy ta sama klasa bazowa jest rozszerzana w wielu miejscach.
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}- Kiedy wiele komponentów dziedziczy po
.utility, selektory są łączone w jeden, a przy dużych projektach może to spowodować rozrost CSS.
Wygenerowany CSS
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 i .class vs selektory elementów (tagi) — priorytet i skutki uboczne
@extend można stosować nie tylko do klas, ale również do selektorów elementów. Jednak rozszerzanie elementów zwiększa zakres działania, co podnosi ryzyko niezamierzonego stosowania reguł w nieprzewidzianych miejscach.
Poniżej znajduje się przykład rozszerzania selektora elementu i konsekwencji tego działania.
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*/- W tym przykładzie, dziedzicząc selektor elementu
h1,.titlezostaje połączone z tymi samymi stylami coh1. - Chociaż może się to wydawać wygodne w niewielkich projektach, w miarę rozrastania się projektu reguły dla
h1mogą się niespodziewanie łączyć z.title, czyniąc style bardziej złożonymi i trudniejszymi do utrzymania. Dlatego projektowanie stylów głównie w oparciu o klasy i selektory zastępcze ułatwia ich utrzymanie.
Wygenerowany CSS
1h1,
2.title {
3 font-size: 2rem;
4 margin-bottom: 0.5rem;
5}
6
7.title {
8 color: #333;
9}Przypadki użycia @extend i !optional
Jeśli określisz !optional wraz z @extend, możesz wyeliminować błędy w przypadku braku celu dziedziczenia. Jest to szczególnie przydatne w kodzie przypominającym bibliotekę lub w przypadkach, gdy selektory zastępcze są definiowane warunkowo.
Poniżej przykład bezpiecznej próby dziedziczenia po klasie, która może nie istnieć, z użyciem !optional.
1/* Try to extend a class that might not exist */
2.component {
3 @extend .maybe-existing !optional;
4 padding: 1rem;
5}- Jeśli
.maybe-existingnie istnieje, nic się nie dzieje i zostaje to pominięte. Możesz tego użyć, gdy chcesz bezpiecznie spróbować rozszerzenia.
Wygenerowany CSS
1.component {
2 padding: 1rem;
3}Porównanie @extend i mixinów (@mixin / @include)
@extend i @mixin mają czasami nakładające się funkcje, ale ich wynikowy kod i zastosowania się różnią.
-
@extend- Wygenerowany CSS ogranicza powielanie poprzez łączenie selektorów.
- Ponieważ selektory są łączone podczas generowania, mogą pojawić się niezamierzone kombinacje.
- Nie można przekazywać parametrów (choć można to obejść, łącząc różne placeholdery).
-
@mixin/@include- Każde wywołanie duplikuje style, powodując powstanie zbędnego kodu.
- Możesz przekazywać parametry i stosować logikę typu instrukcje warunkowe czy pętle.
- Wynik jest bardziej przewidywalny, ale rozmiar pliku rośnie.
Poniżej znajduje się porównanie użycia zarówno @mixin, jak i @extend do realizacji tych samych stylów przycisku.
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}@mixinpozwala elastycznie dołączać style, a@extendefektywnie konsoliduje wynik; możesz więc stosować oba podejścia w zależności od potrzeby.
Wygenerowany CSS
Wynik z @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}Wynik z @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}Praktyczne wytyczne
Dziedziczenie w SASS jest potężną funkcją zwiększającą ponowne użycie stylów. Jednak błędne użycie może skomplikować łączenie stylów i upośledzić możliwość łatwego utrzymania kodu. Poniżej przedstawiono kluczowe wskazówki dotyczące bezpiecznego i efektywnego korzystania z dziedziczenia.
- Używaj selektorów zastępczych dla czysto wspólnych stylów komponentów, takich jak struktura i układ. Dodatkowo, jeśli wymagana jest dynamiczna parametryzacja, możesz użyć
@mixin. - Należy unikać bezpośredniego dziedziczenia elementów HTML, takich jak
h1. Mogą wystąpić niezamierzone połączenia selektorów, co może skutkować wygenerowaniem nieoczekiwanego CSS. - Używanie konwencji nazewniczych, takich jak BEM lub jasne prefiksy wskazujące przeznaczenie placeholderów, pomaga zachować bezpieczeństwo.
- Bezpieczniej jest używać
@extendw ramach tego samego pliku. Szczególnie w dużych projektach zaleca się projektowanie dziedziczenia w obrębie każdego komponentu, aby łatwiej śledzić relacje dziedziczenia.
Podsumowanie
Funkcja @extend w SASS to wygodny sposób na efektywne ponowne wykorzystanie wspólnych stylów i zapewnienie spójności projektu. Jednak kombinacje selektorów mogą łatwo stać się złożone, dlatego należy korzystać z tej funkcji ostrożnie i w ograniczonym zakresie. Grupując wspólne style za pomocą selektorów zastępczych (%placeholder) oraz stosując @mixin do części wymagających dynamicznych parametrów, możesz zachować prosty i łatwy w utrzymaniu projekt.
Możesz śledzić ten artykuł, korzystając z Visual Studio Code na naszym kanale YouTube. Proszę również sprawdzić nasz kanał YouTube.