Kurs HTML i CSS · Moduł 7: SASS

Zmienne w Sass

4 min czytania
W tej lekcji5

Paleta świątyni to kilkanaście wartości: złoto, lapis lazuli, kolor piasku, dwie czcionki i kilka odstępów. Jeśli każdą z nich wpisujesz ręcznie, przy pierwszej zmianie gubisz spójność, bo gdzieś zawsze zostanie stary odcień. Zmienne w Sass nadają każdej wartości imię, jak kartusz z imieniem faraona: zapisujesz je raz, a potem przywołujesz wszędzie tam, gdzie jest potrzebne. To potężne narzędzie, które ułatwia utrzymanie kodu i wprowadzanie zmian.

Definiowanie zmiennych

Zmienne w Sass zaczynają się od znaku dolara ($). Po nazwie stawiasz dwukropek, wartość i średnik. Możesz przypisać do nich różne wartości, takie jak kolory, długości, procenty, nazwy czcionek, wartości logiczne i inne. Oto trzy przykładowe deklaracje:

1$main-color: #c06;
2$font-stack: Helvetica, sans-serif;
3$base-line-height: 1.5;

Mamy tu kolor, listę czcionek i liczbę bez jednostki. Same deklaracje nie wygenerują w CSS ani jednej linii, bo zmienna istnieje tylko w pliku źródłowym. Warto też wiedzieć, że w nazwach zmiennych Sass traktuje myślnik i podkreślenie tak samo, więc $font-stack i $font_stack to ta sama zmienna. Polecam Ci myślniki bo tak samo nazywamy właściwości w CSS.

Używanie zmiennych

Po zdefiniowaniu zmiennej umieszczasz jej nazwę wszędzie tam, gdzie chcesz użyć jej wartości, także obok innych wartości w jednej deklaracji:

1body {
2  color: $main-color;
3  font: 100% $font-stack;
4  line-height: $base-line-height;
5}

Kompilator podmieni każdą zmienną na jej wartość, więc w CSS zobaczysz color: #c06, a skrót font otrzyma wartość 100% Helvetica, sans-serif. Reguła body wygląda po kompilacji dokładnie tak, jakbyś wpisał te wartości ręcznie.

Zasięg zmiennych

Zmienne w Sass mają zasięg, co oznacza, że są dostępne tylko w obrębie bloku, w którym zostały zdefiniowane. Jeśli zdefiniujesz zmienną na najwyższym poziomie, poza jakimikolwiek selektorami czy regułami, jest ona globalna i możesz jej używać w całym arkuszu stylów. Jeżeli jednak zdefiniujesz zmienną wewnątrz reguły lub selektora, będzie ona dostępna tylko w tym bloku, jak skarb zamknięty w jednej komnacie:

1$global-color: blue;
2
3.foo {
4  $local-color: green;
5  color: $local-color;  // zielony
6}
7
8.bar {
9  color: $local-color;  // błąd, $local-color nie jest dostępne tutaj
10}

Reguła .foo dostanie zielony kolor, ale przy .bar kompilacja zakończy się błędem, bo zmienna $local-color nie istnieje poza blokiem .foo. Zmienna $global-color pozostaje dostępna w obu regułach.

Sass pozwala też użyć tej samej nazwy ponownie. Jeśli wewnątrz selektora zadeklarujesz zmienną o nazwie zmiennej globalnej, powstanie zmienna lokalna, która przesłoni globalną tylko w tym bloku, a poza nim globalna wartość się nie zmieni. Flaga !global pozwala celowo nadpisać zmienną globalną z wnętrza bloku, ale używaj jej oszczędnie.

Gdy kompilator zgłasza błąd

Błąd z .bar to świetna okazja, żeby nauczyć się czytać komunikaty kompilatora. Dart Sass mówi dokładnie, co się stało, w którym pliku i w której linii:

1Error: Undefined variable.
2  ╷
39 │   color: $local-color;  // błąd, $local-color nie jest dostępne tutaj
4  │          ^^^^^^^^^^^^
5  ╵
6  styles.scss 9:10  root stylesheet

Pierwsza linia opisuje problem, a ostatnia wskazuje plik, numer linii i kolumnę. Z takim komunikatem naprawisz każdy błąd w pięciu krokach:

  1. Przeczytaj komunikat błędu kompilacji.
  2. Znajdź wskazany plik i numer linii.
  3. Sprawdź składnię: brakujący średnik, nawias klamrowy albo literówkę w nazwie zmiennej.
  4. Popraw kod.
  5. Skompiluj ponownie i sprawdź wynik w przeglądarce.

Dlaczego to ważne

Zmienne w Sass to jedno z najważniejszych narzędzi do utrzymania spójnego i łatwego w zarządzaniu kodu CSS. Dzięki nim tworzysz bardziej dynamiczne, konfigurowalne arkusze stylów. Moja rada: wszystkie zmienne globalne trzymaj na początku pliku albo w osobnym pliku, a w następnej lekcji zobaczysz, jak wydzielić je do partiala i wczytać dyrektywą @use.

W piaskownicy poniżej zmień wartość jednej zmiennej w pliku main.scss i obserwuj, ile miejsc w wynikowym CSS zmieni się naraz.

Pamiętaj: zmienna to kartusz, czyli jedno imię i jedna wartość, którą kompilator wpisze wszędzie tam, gdzie ją przywołasz.

Kod do tej lekcji: index.html
1<!DOCTYPE html>
2<html lang="pl">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>SCSS - Projekt E-commerce</title>
7    <link rel="stylesheet" href="main.css">
8    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
9</head>
10<body>
11    <!-- Header -->
12    <header class="header">
13        <div class="header__top">
14            <div class="container">
15                <div class="header__top-info">
16                    <span>+48 123 456 789</span>
17                    <span>kontakt@shopmaster.pl</span>
18                </div>
19                <div class="header__top-links">
20                    <a href="#">O nas</a>
21                    <a href="#">Dostawa</a>
22                    <a href="#">Pomoc</a>
23                </div>
24            </div>
25        </div>
26
27        <div class="header__main">
28            <div class="container">
29                <a href="#" class="header__logo">ShopMaster</a>
30
31                <div class="header__search">
32                    <input type="text" placeholder="Czego szukasz?">
33                    <button type="submit">Szukaj</button>
34                </div>
35
36                <div class="header__actions">
37                    <a href="#" class="header__actions-item">
38                        <span></span>
39                        <span>Konto</span>
40                    </a>
41                    <a href="#" class="header__actions-item">
42                        <span></span>
43                        <span>Ulubione</span>
44                        <span class="badge">3</span>
45                    </a>
46                    <a href="#" class="header__actions-item">
47                        <span></span>
48                        <span>Koszyk</span>
49                        <span class="badge">5</span>
50                    </a>
51                </div>
52            </div>
53        </div>
54
55        <nav class="navigation">
56            <div class="container">
57                <ul class="navigation__menu">
58                    <li class="navigation__item">
59                        <a href="#" class="navigation__link">Elektronika</a>
60                    </li>
61                    <li class="navigation__item">
62                        <a href="#" class="navigation__link">Moda</a>
63                    </li>
64                    <li class="navigation__item">
65                        <a href="#" class="navigation__link">Dom i ogród</a>
66                    </li>
67                    <li class="navigation__item">
68                        <a href="#" class="navigation__link">Sport</a>
69                    </li>
70                    <li class="navigation__item navigation__item--sale">
71                        <a href="#" class="navigation__link">Wyprzedaż</a>
72                    </li>
73                </ul>
74            </div>
75        </nav>
76    </header>
77
78    <!-- Hero Section -->
79    <section class="hero">
80        <div class="hero__content">
81            <h1>Zimowa wyprzedaż do -70%</h1>
82            <p>Odkryj najlepsze oferty na elektronikę, modę i wiele więcej!</p>
83            <div class="btn-group">
84                <a href="#" class="btn btn--primary btn--large">Zobacz oferty</a>
85                <a href="#" class="btn btn--outline btn--large">Dowiedz się więcej</a>
86            </div>
87        </div>
88    </section>
89
90    <!-- Categories Section -->
91    <section class="categories section">
92        <div class="container">
93            <h2 class="section__title">Popularne kategorie</h2>
94            <div class="categories__grid">
95                <a href="#" class="category-card">
96                    <div class="category-card__icon">◆</div>
97                    <h3 class="category-card__title">Elektronika</h3>
98                    <p class="category-card__count">1234 produktów</p>
99                </a>
100                <a href="#" class="category-card">
101                    <div class="category-card__icon">◆</div>
102                    <h3 class="category-card__title">Moda</h3>
103                    <p class="category-card__count">5678 produktów</p>
104                </a>
105                <a href="#" class="category-card">
106                    <div class="category-card__icon">◆</div>
107                    <h3 class="category-card__title">Dom i ogród</h3>
108                    <p class="category-card__count">910 produktów</p>
109                </a>
110                <a href="#" class="category-card">
111                    <div class="category-card__icon">◆</div>
112                    <h3 class="category-card__title">Sport</h3>
113                    <p class="category-card__count">2345 produktów</p>
114                </a>
115            </div>
116        </div>
117    </section>
118
119    <!-- Featured Products -->
120    <section class="products section">
121        <div class="container">
122            <div class="section__header">
123                <h2 class="section__title">Polecane produkty</h2>
124                <a href="#" class="btn btn--ghost">Zobacz wszystkie →</a>
125            </div>
126
127            <div class="products__grid">
128                <!-- Product Card 1 -->
129                <div class="product-card">
130                    <div class="product-card__badge product-card__badge--sale">-30%</div>
131                    <div class="product-card__image">
132                        <img src="https://picsum.photos/300/300?random=10" alt="Product 1">
133                        <div class="product-card__overlay">
134                            <button class="btn btn--primary btn--small">Szybki podgląd</button>
135                            <button class="btn btn--outline btn--small">Lubię</button>
136                        </div>
137                    </div>
138                    <div class="product-card__content">
139                        <p class="product-card__category">Elektronika</p>
140                        <h3 class="product-card__title">Smartfon XYZ Pro 128GB</h3>
141                        <div class="product-card__rating">
142                            <span class="product-card__rating-stars">5/5</span>
143                            <span class="product-card__rating-count">(125)</span>
144                        </div>
145                        <div class="product-card__price">
146                            <span class="product-card__price-current">1 399 zł</span>
147                            <span class="product-card__price-original">1 999 zł</span>
148                            <span class="product-card__price-discount">-30%</span>
149                        </div>
150                        <div class="product-card__actions">
151                            <button class="btn btn--primary">Do koszyka</button>
152                        </div>
153                    </div>
154                </div>
155
156                <!-- Product Card 2 -->
157                <div class="product-card">
158                    <div class="product-card__badge product-card__badge--new">Nowość</div>
159                    <div class="product-card__image">
160                        <img src="https://picsum.photos/300/300?random=11" alt="Product 2">
161                        <div class="product-card__overlay">
162                            <button class="btn btn--primary btn--small">Szybki podgląd</button>
163                            <button class="btn btn--outline btn--small">Lubię</button>
164                        </div>
165                    </div>
166                    <div class="product-card__content">
167                        <p class="product-card__category">Audio</p>
168                        <h3 class="product-card__title">Słuchawki bezprzewodowe Premium</h3>
169                        <div class="product-card__rating">
170                            <span class="product-card__rating-stars">4/5</span>
171                            <span class="product-card__rating-count">(89)</span>
172                        </div>
173                        <div class="product-card__price">
174                            <span class="product-card__price-current">799 zł</span>
175                        </div>
176                        <div class="product-card__actions">
177                            <button class="btn btn--primary">Do koszyka</button>
178                        </div>
179                    </div>
180                </div>
181
182                <!-- Product Card 3 -->
183                <div class="product-card">
184                    <div class="product-card__image">
185                        <img src="https://picsum.photos/300/300?random=12" alt="Product 3">
186                        <div class="product-card__overlay">
187                            <button class="btn btn--primary btn--small">Szybki podgląd</button>
188                            <button class="btn btn--outline btn--small">Lubię</button>
189                        </div>
190                    </div>
191                    <div class="product-card__content">
192                        <p class="product-card__category">Gaming</p>
193                        <h3 class="product-card__title">Konsola do gier NextGen</h3>
194                        <div class="product-card__rating">
195                            <span class="product-card__rating-stars">5/5</span>
196                            <span class="product-card__rating-count">(234)</span>
197                        </div>
198                        <div class="product-card__price">
199                            <span class="product-card__price-current">2 199 zł</span>
200                        </div>
201                        <div class="product-card__actions">
202                            <button class="btn btn--primary">Do koszyka</button>
203                        </div>
204                    </div>
205                </div>
206            </div>
207        </div>
208    </section>
209
210    <!-- Newsletter -->
211    <section class="newsletter">
212        <div class="container">
213            <div class="newsletter__content">
214                <h2 class="newsletter__title">Zapisz się do newslettera</h2>
215                <p class="newsletter__description">Otrzymuj najlepsze oferty i bądź na bieżąco z nowościami!</p>
216                <form class="newsletter__form">
217                    <input type="email" placeholder="Twój adres e-mail" class="newsletter__input">
218                    <button type="submit" class="btn btn--primary">Zapisz się</button>
219                </form>
220            </div>
221        </div>
222    </section>
223
224    <!-- Footer -->
225    <footer class="footer">
226        <div class="container">
227            <div class="footer__grid">
228                <div class="footer__column">
229                    <h3 class="footer__title">O nas</h3>
230                    <ul class="footer__list">
231                        <li><a href="#">Kim jesteśmy</a></li>
232                        <li><a href="#">Kariera</a></li>
233                        <li><a href="#">Kontakt</a></li>
234                        <li><a href="#">Blog</a></li>
235                    </ul>
236                </div>
237                <div class="footer__column">
238                    <h3 class="footer__title">Pomoc</h3>
239                    <ul class="footer__list">
240                        <li><a href="#">Centrum pomocy</a></li>
241                        <li><a href="#">Dostawa i płatności</a></li>
242                        <li><a href="#">Zwroty i reklamacje</a></li>
243                        <li><a href="#">FAQ</a></li>
244                    </ul>
245                </div>
246            </div>
247            <div class="footer__bottom">
248                <p>&copy; 2024 ShopMaster. Wszystkie prawa zastrzeżone.</p>
249            </div>
250        </div>
251    </footer>
252</body>
253</html>

Widzisz błąd w tej lekcji?

Zadania praktyczne w grze

  • Układanie w pionie

    Ułóż kroki debugowania błędu kompilacji SASS:

Przydatne artykuły