Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Sass (SCSS) - Kosmiczna syntaktyczna supersiła

W kosmosie stylowania React, Sass (Syntactically Awesome Style Sheets) jest jak statek kosmiczny nowej generacji - oferuje wszystkie możliwości standardowego CSS, ale z dodatkowymi mocami, które czynią stylowanie bardziej wydajnym, modułowym i łatwiejszym w utrzymaniu. Poruszając się w galaktyce React, warto opanować tę technologię, która może znacząco usprawnić tworzenie zaawansowanych stylizacji.

Czym jest Sass/SCSS?

Sass to preprocesor CSS, który rozszerza standardowy CSS o zmienne, zagnieżdżone reguły, mixiny, dziedziczenie selektorów i wiele innych funkcji. Istnieją dwie składnie Sass:

  1. Składnia indentacyjna (.sass) - oparta na wcięciach, bez nawiasów klamrowych i średników
  2. SCSS (.scss) - nowsza składnia, która jest nadzbiorem CSS (każdy poprawny CSS jest poprawnym SCSS)

W tym module skupimy się na SCSS, ponieważ jest bardziej popularna i łatwiejsza do nauki dla osób znających CSS. Wyobraźmy sobie SCSS jako ulepszone paliwo rakietowe, które zachowuje wszystkie właściwości standardowego paliwa, ale dodaje więcej mocy.

Konfiguracja Sass w projekcie React

Aby używać Sass w projekcie React, najpierw musimy zainstalować odpowiednie pakiety:

Create React App

Jeśli korzystasz z Create React App, instalacja jest prosta:

1npm install sass

To wszystko! CRA ma wbudowaną obsługę Sass, więc po instalacji możesz po prostu tworzyć pliki .scss/.sass i importować je do komponentów.

Vite

W projektach Vite, proces jest podobny:

1npm install sass

Vite ma natywne wsparcie dla Sass, więc nie potrzeba dodatkowej konfiguracji.

Inne konfiguracje (np. własny Webpack)

Jeśli tworzysz własną konfigurację, potrzebujesz:

1npm install sass sass-loader

I dodać odpowiednią konfigurację do pliku webpack.config.js:

1// Uproszczona konfiguracja webpack
2module.exports = {
3  //
4  module: {
5    rules: [
6      {
7        test: /.s[ac]ss$/i,
8        use: [
9          'style-loader',
10          'css-loader',
11          'sass-loader',
12        ],
13      },
14    ],
15  },
16};

Używanie SCSS w projekcie React

Po skonfigurowaniu, możesz tworzyć pliki SCSS i importować je do komponentów:

1// SpacePanel.jsx
2import React from 'react';
3import './SpacePanel.scss'; // Importujemy SCSS zamiast CSS
4
5function SpacePanel() {
6  return (
7    <div className="space-panel">
8      <h2 className="panel-title">Panel Sterowania Statkiem</h2>
9      <div className="control-area">
10        <div className="button-group">
11          <button className="control-button primary">Uruchom silniki</button>
12          <button className="control-button secondary">Nawigacja</button>
13        </div>
14        <div className="status-display">Status: Gotowy do startu</div>
15      </div>
16    </div>
17  );
18}
19
20export default SpacePanel;

Kluczowe funkcje SCSS

1. Zmienne

W kosmicznym interfejsie, często używamy tych samych kolorów, marginesów czy fontów. Zmienne SCSS pozwalają nam zdefiniować je raz i używać wielokrotnie:

1// variables.scss
2$primary-color: #8a2be2;      // Kosmiczny fiolet
3$secondary-color: #4a90e2;    // Niebieski kosmosu
4$danger-color: #ff4d4f;       // Czerwony alarm
5$success-color: #52c41a;      // Zielony "go"
6
7$border-radius-small: 4px;
8$border-radius-medium: 8px;
9$border-radius-large: 16px;
10
11$font-main: 'Space Grotesk', sans-serif;
12$font-display: 'Nova Mono', monospace;
13
14// Używanie zmiennych
15.control-button {
16  background-color: $secondary-color;
17  border-radius: $border-radius-medium;
18  font-family: $font-main;
19  
20  &.primary {
21    background-color: $primary-color;
22  }
23  
24  &.danger {
25    background-color: $danger-color;
26  }
27}

2. Zagnieżdżanie selektorów

Zagnieżdżanie selektorów pozwala na tworzenie bardziej czytelnej hierarchii, która odzwierciedla strukturę HTML:

1.space-panel {
2  background-color: #1a1a2e;
3  padding: 20px;
4  border-radius: 10px;
5
6  .panel-title {
7    color: white;
8    font-size: 24px;
9    margin-bottom: 15px;
10  }
11  
12  .control-area {
13    display: flex;
14    justify-content: space-between;
15    
16    .button-group {
17      display: flex;
18      gap: 10px;
19      
20      .control-button {
21        padding: 10px 15px;
22        // Inne style przycisku...
23      }
24    }
25    
26    .status-display {
27      background-color: rgba(0, 0, 0, 0.3);
28      padding: 10px;
29      border-radius: 5px;
30    }
31  }
32}

Taki zapis jest nie tylko bardziej czytelny, ale również pomaga uniknąć duplikacji selektorów i czyni strukturę bardziej oczywistą.

3. Selektor & (ampersand)

Ampersand (&) reprezentuje bieżący selektor i jest szczególnie przydatny do:

Pseudoklas i pseudoelementów

1.control-button {
2  background-color: #4a90e2;
3  transition: all 0.3s;
4  
5  &:hover {
6    background-color: darken(#4a90e2, 10%);
7    transform: translateY(-2px);
8  }
9  
10  &:active {
11    transform: translateY(1px);
12  }
13  
14  &::before {
15    content: "🚀";
16    margin-right: 5px;
17  }
18}

Modyfikatorów klasy

1.control-button {
2  // Bazowe style...
3  
4  &.primary {
5    background-color: #8a2be2;
6  }
7  
8  &.secondary {
9    background-color: #4a90e2;
10  }
11  
12  &.large {
13    padding: 12px 20px;
14    font-size: 18px;
15  }
16}

Łączenia selektorów

1.space-theme {
2  .control-button {
3    // Style dla .space-theme .control-button
4  }
5  
6  // Używając & możemy wybierać różne kombinacje selektorów
7  &__dark .control-button {
8    // Style dla .space-theme__dark .control-button
9  }
10}

4. Mixiny - wielokrotne wykorzystanie kodu

Mixiny to zbiory deklaracji CSS, które można wielokrotnie używać w kodzie. To jak reużywalne moduły statku kosmicznego:

1// mixins.scss
2@mixin flex-center {
3  display: flex;
4  justify-content: center;
5  align-items: center;
6}
7
8@mixin glass-effect {
9  background: rgba(255, 255, 255, 0.1);
10  backdrop-filter: blur(10px);
11  border: 1px solid rgba(255, 255, 255, 0.2);
12  box-shadow: 0 8px 32px rgba(31, 38, 135, 0.2);
13}
14
15@mixin button-variant($bg-color, $text-color) {
16  background-color: $bg-color;
17  color: $text-color;
18  
19  &:hover {
20    background-color: darken($bg-color, 10%);
21  }
22  
23  &:active {
24    background-color: darken($bg-color, 15%);
25  }
26}

Użycie mixinów:

1.control-panel {
2  @include glass-effect;
3  padding: 20px;
4}
5
6.button-container {
7  @include flex-center;
8  gap: 10px;
9}
10
11.launch-button {
12  @include button-variant(#ff4d4f, white);
13  padding: 10px 20px;
14}
15
16.navigation-button {
17  @include button-variant(#4a90e2, white);
18  padding: 8px 15px;
19}

5. Dziedziczenie - @extend

Dziedziczenie pozwala jednej klasie dziedziczyć właściwości innej, redukując duplikację kodu:

1.base-button {
2  padding: 10px 15px;
3  border: none;
4  border-radius: 4px;
5  font-weight: bold;
6  cursor: pointer;
7  transition: all 0.3s;
8}
9
10.primary-button {
11  @extend .base-button;
12  background-color: #8a2be2;
13  color: white;
14}
15
16.secondary-button {
17  @extend .base-button;
18  background-color: #4a90e2;
19  color: white;
20}
21
22.ghost-button {
23  @extend .base-button;
24  background-color: transparent;
25  color: #8a2be2;
26  border: 1px solid currentColor;
27}

6. Funkcje matematyczne i kolorystyczne

SCSS oferuje wiele wbudowanych funkcji do manipulacji kolorami i wartościami:

1.panel {
2  // Matematyczne operacje
3  width: 100% - 40px;
4  padding: 10px * 2;
5  
6  // Funkcje kolorów
7  background-color: lighten(#1a1a2e, 10%);
8  border: 1px solid darken(#1a1a2e, 5%);
9  
10  .warning-label {
11    color: transparentize(#ff4d4f, 0.2); // Dodaje przezroczystość
12  }
13  
14  .accent-element {
15    background-color: mix(#8a2be2, #4a90e2, 30%); // Miesza kolory
16  }
17}

7. Importowanie i organizacja plików

SCSS umożliwia dzielenie kodu na modułowe pliki, co jest kluczowe dla dużych projektów:

1// styles/variables.scss
2$primary-color: #8a2be2;
3// Inne zmienne...
4
5// styles/mixins.scss
6@mixin flex-center { /* ... */ }
7// Inne mixiny...
8
9// styles/buttons.scss
10@import 'variables';
11@import 'mixins';
12
13.button { /* ... */ }
14// Style przycisków...
15
16// styles/panels.scss
17@import 'variables';
18@import 'mixins';
19
20.panel { /* ... */ }
21// Style paneli...
22
23// styles/main.scss
24@import 'variables';
25@import 'mixins';
26@import 'buttons';
27@import 'panels';
28// Możemy importować wszystko razem lub wybiórczo w komponentach

8. Operatory warunkowe i pętle

SCSS oferuje także konstrukcje kontrolne znane z języków programowania:

1// Warunki
2$theme: 'dark';
3
4.space-control {
5  @if $theme == 'dark' {
6    background-color: #121212;
7    color: white;
8  } @else {
9    background-color: #f5f5f5;
10    color: #333;
11  }
12}
13
14// Pętle
15$sizes: (
16  'small': 8px,
17  'medium': 16px,
18  'large': 24px,
19  'xlarge': 32px
20);
21
22@each $name, $size in $sizes {
23  .margin-#{$name} {
24    margin: $size;
25  }
26  
27  .padding-#{$name} {
28    padding: $size;
29  }
30}
31
32// Generuje:
33// .margin-small { margin: 8px; }
34// .padding-small { padding: 8px; }
35// ...itd. dla wszystkich rozmiarów

Integracja SCSS z CSS Modules w React

SCSS można doskonale połączyć z CSS Modules, tworząc potężne rozwiązanie stylowania:

1// SpacePanel.module.scss
2@import 'src/styles/variables';
3@import 'src/styles/mixins';
4
5.panel {
6  @include glass-effect;
7  background-color: $panel-bg-color;
8  
9  .title {
10    color: $text-primary;
11    font-family: $font-display;
12  }
13  
14  .controls {
15    display: flex;
16    gap: $spacing-md;
17    
18    .button {
19      @include button-base;
20      
21      &.primary {
22        @include button-variant($primary-color, white);
23      }
24      
25      &.secondary {
26        @include button-variant($secondary-color, white);
27      }
28    }
29  }
30}

Użycie w komponencie:

1import React from 'react';
2import styles from './SpacePanel.module.scss';
3
4function SpacePanel() {
5  return (
6    <div className={styles.panel}>
7      <h2 className={styles.title}>Panel kontrolny</h2>
8      <div className={styles.controls}>
9        <button className={`${styles.button} ${styles.primary}`}>
10          Uruchom
11        </button>
12        <button className={`${styles.button} ${styles.secondary}`}>
13          Anuluj
14        </button>
15      </div>
16    </div>
17  );
18}

Najlepsze praktyki używania SCSS w React

1. Struktura plików

Organizuj swoje pliki SCSS w sposób, który odzwierciedla strukturę komponentów:

1src/
2├── styles/                    # Globalne style i zasoby
3│   ├── _variables.scss        # Konwencja: pliki z podkreśleniem są tylko do importowania
4│   ├── _mixins.scss
5│   ├── _functions.scss
6│   ├── _reset.scss
7│   └── global.scss            # Główny plik globalnych stylów
8├── components/
9│   ├── Button/
10│   │   ├── Button.jsx
11│   │   └── Button.module.scss
12│   ├── Panel/
13│   │   ├── Panel.jsx
14│   │   └── Panel.module.scss
15│   └──
16└──

2. Konwencje nazewnicze

Używaj konsekwentnych konwencji nazewniczych:

  • BEM (Block, Element, Modifier) - dla klas CSS
  • camelCase - dla zmiennych SCSS i mixinów
  • PascalCase - dla komponentów React
  • kebab-case - dla plików SCSS
1// _variables.scss
2$primaryColor: #8a2be2;
3$secondaryColor: #4a90e2;
4
5// Button.module.scss (wykorzystuje BEM)
6.button {
7  // Block
8  background-color: $primaryColor;
9  
10  &__icon {
11    // Element
12    margin-right: 8px;
13  }
14  
15  &--large {
16    // Modifier
17    padding: 12px 24px;
18  }
19}

3. Unikaj nadmiernego zagnieżdżania

Zbyt głębokie zagnieżdżenie może prowadzić do nadspecyficznych selektorów, co utrudnia ich nadpisywanie:

1// Unikaj:
2.panel {
3  .content {
4    .section {
5      .title {
6        .icon {
7          // 5 poziomów zagnieżdżenia!
8          color: red;
9        }
10      }
11    }
12  }
13}
14
15// Lepiej:
16.panel {
17  // Ogólne style panelu
18}
19
20.panel-content {
21  // Style dla zawartości
22}
23
24.section-title-icon {
25  color: red;
26}

4. Używaj zmiennych dla powtarzających się wartości

1// _spacing.scss
2$spacing-xs: 4px;
3$spacing-sm: 8px;
4$spacing-md: 16px;
5$spacing-lg: 24px;
6$spacing-xl: 32px;
7
8// _colors.scss
9$blue-100: #e3f2fd;
10$blue-200: #bbdefb;
11//
12$blue-900: #0d47a1;
13
14$color-primary: $blue-500;
15$color-secondary: $purple-500;

5. Twórz systemowe mixiny

1@mixin media-breakpoint-up($breakpoint) {
2  @if $breakpoint == sm {
3    @media (min-width: 576px) { @content; }
4  } @else if $breakpoint == md {
5    @media (min-width: 768px) { @content; }
6  } @else if $breakpoint == lg {
7    @media (min-width: 992px) { @content; }
8  } @else if $breakpoint == xl {
9    @media (min-width: 1200px) { @content; }
10  }
11}
12
13// Użycie:
14.responsive-element {
15  font-size: 14px;
16  
17  @include media-breakpoint-up(md) {
18    font-size: 16px;
19  }
20  
21  @include media-breakpoint-up(lg) {
22    font-size: 18px;
23  }
24}

Praktyczny przykład: Panel sterowania statkiem kosmicznym

Zobaczmy, jak zastosować SCSS do stworzenia interaktywnego panelu sterowania:

1// _variables.scss
2$primary-color: #7b2cbf;
3$secondary-color: #3a86ff;
4$success-color: #06d6a0;
5$warning-color: #ffd166;
6$danger-color: #ef476f;
7$dark-bg: #1a1a2e;
8$panel-bg: #252941;
9$text-light: #e6e6ff;
10
11$border-radius-sm: 4px;
12$border-radius-md: 8px;
13$border-radius-lg: 12px;
14
15$transition-fast: 0.2s ease;
16$transition-normal: 0.3s ease;
17
18// _mixins.scss
19@mixin glass-morphism {
20  background: rgba(37, 41, 65, 0.8);
21  backdrop-filter: blur(10px);
22  border: 1px solid rgba(255, 255, 255, 0.1);
23  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
24}
25
26@mixin button-glow($color) {
27  box-shadow: 0 0 15px rgba($color, 0.5);
28  &:hover {
29    box-shadow: 0 0 25px rgba($color, 0.7);
30  }
31}
32
33// SpaceControlPanel.module.scss
34@import 'src/styles/variables';
35@import 'src/styles/mixins';
36
37.controlPanel {
38  @include glass-morphism;
39  padding: 24px;
40  border-radius: $border-radius-lg;
41  color: $text-light;
42  
43  .panelHeader {
44    display: flex;
45    justify-content: space-between;
46    align-items: center;
47    margin-bottom: 24px;
48    padding-bottom: 16px;
49    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
50    
51    .title {
52      font-size: 28px;
53      font-weight: 600;
54      
55      &::before {
56        content: "🚀";
57        margin-right: 10px;
58      }
59    }
60    
61    .status {
62      padding: 6px 12px;
63      border-radius: $border-radius-sm;
64      font-size: 14px;
65      font-weight: 500;
66      
67      &.ready {
68        background-color: rgba($success-color, 0.2);
69        color: $success-color;
70      }
71      
72      &.standby {
73        background-color: rgba($warning-color, 0.2);
74        color: $warning-color;
75      }
76      
77      &.error {
78        background-color: rgba($danger-color, 0.2);
79        color: $danger-color;
80      }
81    }
82  }
83  
84  .controlGrid {
85    display: grid;
86    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
87    gap: 20px;
88    
89    .controlSection {
90      background-color: rgba(0, 0, 0, 0.2);
91      border-radius: $border-radius-md;
92      padding: 16px;
93      
94      .sectionTitle {
95        font-size: 18px;
96        margin-bottom: 16px;
97        color: rgba($text-light, 0.8);
98      }
99      
100      .buttonGroup {
101        display: flex;
102        flex-direction: column;
103        gap: 12px;
104      }
105    }
106  }
107  
108  .button {
109    padding: 12px 16px;
110    border: none;
111    border-radius: $border-radius-sm;
112    font-weight: 500;
113    letter-spacing: 0.5px;
114    cursor: pointer;
115    transition: all $transition-normal;
116    position: relative;
117    overflow: hidden;
118    
119    &::before {
120      content: "";
121      position: absolute;
122      top: 0;
123      left: -100%;
124      width: 100%;
125      height: 100%;
126      background: linear-gradient(
127        90deg,
128        transparent,
129        rgba(255, 255, 255, 0.2),
130        transparent
131      );
132      transition: all 0.6s;
133    }
134    
135    &:hover::before {
136      left: 100%;
137    }
138    
139    &.primary {
140      background-color: $primary-color;
141      color: white;
142      @include button-glow($primary-color);
143    }
144    
145    &.secondary {
146      background-color: $secondary-color;
147      color: white;
148      @include button-glow($secondary-color);
149    }
150    
151    &.success {
152      background-color: $success-color;
153      color: black;
154      @include button-glow($success-color);
155    }
156    
157    &.warning {
158      background-color: $warning-color;
159      color: black;
160      @include button-glow($warning-color);
161    }
162    
163    &.danger {
164      background-color: $danger-color;
165      color: white;
166      @include button-glow($danger-color);
167    }
168    
169    &.disabled {
170      opacity: 0.5;
171      cursor: not-allowed;
172      pointer-events: none;
173    }
174  }
175  
176  .monitorDisplay {
177    margin-top: 24px;
178    padding: 16px;
179    background-color: rgba(0, 0, 0, 0.4);
180    border-radius: $border-radius-md;
181    font-family: monospace;
182    height: 120px;
183    overflow-y: auto;
184    
185    .logLine {
186      margin: 4px 0;
187      font-size: 14px;
188      
189      &.info {
190        color: $secondary-color;
191      }
192      
193      &.success {
194        color: $success-color;
195      }
196      
197      &.warning {
198        color: $warning-color;
199      }
200      
201      &.error {
202        color: $danger-color;
203      }
204      
205      &::before {
206        content: "> ";
207      }
208    }
209  }
210}
211
212// Użycie w komponencie React
213import React, { useState } from 'react';
214import styles from './SpaceControlPanel.module.scss';
215
216function SpaceControlPanel() {
217  const [status, setStatus] = useState('standby');
218  const [logs, setLogs] = useState([
219    { type: 'info', text: 'System initialized' },
220    { type: 'info', text: 'Waiting for commands' }
221  ]);
222  
223  const addLog = (text, type = 'info') => {
224    setLogs(prev => [...prev, { type, text }]);
225  };
226  
227  const initiateSequence = () => {
228    setStatus('ready');
229    addLog('Launch sequence initiated', 'success');
230  };
231  
232  const abortSequence = () => {
233    setStatus('standby');
234    addLog('Launch sequence aborted', 'warning');
235  };
236  
237  const triggerAlert = () => {
238    setStatus('error');
239    addLog('ALERT: Critical system failure detected', 'error');
240  };
241  
242  return (
243    <div className={styles.controlPanel}>
244      <div className={styles.panelHeader}>
245        <h2 className={styles.title}>Kosmiczny Panel Sterowania</h2>
246        <div className={`${styles.status} ${styles[status]}`}>
247          Status: {status === 'standby' ? 'Oczekiwanie' : 
248                  status === 'ready' ? 'Gotowy' : 'Błąd'}
249        </div>
250      </div>
251      
252      <div className={styles.controlGrid}>
253        <div className={styles.controlSection}>
254          <h3 className={styles.sectionTitle}>Kontrola Startu</h3>
255          <div className={styles.buttonGroup}>
256            <button 
257              className={`${styles.button} ${styles.success}`}
258              onClick={initiateSequence}
259            >
260              Inicjuj Start
261            </button>
262            <button 
263              className={`${styles.button} ${styles.warning}`}
264              onClick={abortSequence}
265            >
266              Przerwij Sekwencję
267            </button>
268          </div>
269        </div>
270        
271        <div className={styles.controlSection}>
272          <h3 className={styles.sectionTitle}>Systemy Pokładowe</h3>
273          <div className={styles.buttonGroup}>
274            <button 
275              className={`${styles.button} ${styles.primary}`}
276              onClick={() => addLog('Navigation systems online', 'info')}
277            >
278              System Nawigacji
279            </button>
280            <button 
281              className={`${styles.button} ${styles.secondary}`}
282              onClick={() => addLog('Life support activated', 'info')}
283            >
284              Podtrzymanie Życia
285            </button>
286          </div>
287        </div>
288        
289        <div className={styles.controlSection}>
290          <h3 className={styles.sectionTitle}>Bezpieczeństwo</h3>
291          <div className={styles.buttonGroup}>
292            <button 
293              className={`${styles.button} ${styles.danger}`}
294              onClick={triggerAlert}
295            >
296              Alarm Awaryjny
297            </button>
298            <button 
299              className={`${styles.button} ${styles.disabled}`}
300            >
301              Protokół Ewakuacji
302            </button>
303          </div>
304        </div>
305      </div>
306      
307      <div className={styles.monitorDisplay}>
308        {logs.map((log, index) => (
309          <div key={index} className={`${styles.logLine} ${styles[log.type]}`}>
310            {log.text}
311          </div>
312        ))}
313      </div>
314    </div>
315  );
316}
317
318export default SpaceControlPanel;

Sass vs CSS-in-JS: Kiedy używać?

Zalety SCSS

  1. Wydajność - CSS jest generowany podczas budowania, nie w czasie rzeczywistym
  2. Znajoma składnia - bardzo podobna do standardowego CSS
  3. Wsparcie narzędzi - pełne wsparcie dla narzędzi deweloperskich (DevTools)
  4. Możliwość ekstrakcji CSS - można wyodrębnić style do osobnych plików CSS
  5. Mniejszy bundle size - nie wymaga dodatkowych bibliotek JS

Kiedy wybierać SCSS?

  • W większych projektach z kompleksowymi stylami
  • Gdy preferujesz separację logiki od stylu
  • Gdy wydajność jest kluczowa
  • Gdy pracujesz z designerami używającymi tradycyjnego CSS/SCSS
  • Gdy zespół ma doświadczenie z SCSS

Podsumowanie

Sass (SCSS) to potężne narzędzie, które znacząco rozszerza możliwości CSS, pozostając przy tym bliskie jego oryginalnej składni. W ekosystemie React, SCSS doskonale integruje się zarówno z podejściem modułowym (CSS Modules), jak i z innymi technikami stylowania.

Dzięki zmiennym, mixinom, zagnieżdżaniu i innym funkcjom, SCSS pozwala na tworzenie bardziej modułowego, łatwiejszego w utrzymaniu kodu CSS, co jest szczególnie ważne w większych aplikacjach React.

Jak każdy zaawansowany statek kosmiczny, SCSS wymaga pewnego czasu na opanowanie, ale inwestycja w naukę szybko zwraca się w postaci bardziej wydajnej pracy i lepiej zorganizowanego kodu. W przypadku aplikacji React, gdzie zarządzanie komponentami i ich stylami jest kluczowe, SCSS stanowi jedną z najlepszych opcji stylowania, oferując doskonałą równowagę między mocą a prostotą.

Przejdź do CodeWorlds