Nowoczesne funkcje CSS zastępujące preprocesory SASS i LESS

  • Arkadiusz Meszka
  • 20 stycznia 2026
  • Ostatnia modyfikacja: 19 stycznia 2026
  • Czas czytania: 9 min

Pamiętasz czasy, gdy bez SASS-a lub LESS-a nie wyobrażaliśmy sobie poważnego projektu webowego? Zmienne, zagnieżdżanie, mixiny – to wszystko sprawiało, że czuliśmy się jak bogowie stylowania. Ale świat się zmienia, a CSS dorósł. I to jak dorósł.

Kiedy w 2006 roku Hampton Catlin stworzył SASS, był to prawdziwy game changer. CSS był wtedy stosunkowo prymitywny – brak zmiennych, powtarzalność kodu, problemy z organizacją większych projektów. Preprocesory przyszły jak zbawienie i przez prawie dwie dekady królowały niepodzielnie w naszych workflow’ach. Ale jeśli spojrzymy na aktualny stan CSS, możemy śmiało powiedzieć: era preprocesorów powoli dobiega końca.

Zmienne CSS – dynamika w czasie rzeczywistym

Pierwsze, co przyciągnęło nas do SASS-a, to zmienne. W końcu mogliśmy zdefiniować $primary-color i używać go w całym projekcie. Brzmi znajomo? Problem w tym, że zmienne SASS-a działają tylko w czasie kompilacji. Native CSS variables – oficjalnie zwane Custom Properties – to zupełnie inna liga.

:root {
  --primary-color: #3498db;
  --spacing-unit: 1rem;
  --font-scale: 1.2;
}

.button {
  background: var(--primary-color);
  padding: calc(var(--spacing-unit) * 1.5);
  font-size: calc(1rem * var(--font-scale));
}

/* A teraz magia - zmiana w czasie rzeczywistym */
.dark-theme {
  --primary-color: #2c3e50;
  --spacing-unit: 1.2rem;
}

Co więcej, CSS variables można modyfikować przez JavaScript bez rekompilacji całego projektu. To tak, jakby porównywać samochód spalinowy z elektrycznym – oba dowożą, ale technologia stoi na zupełnie innym poziomie.

Zagnieżdżanie – w końcu native

Jeśli myślałeś, że nigdy nie doczekamy natywnego nestingu w CSS, mam dla Ciebie dobrą wiadomość. Od 2023 roku większość nowoczesnych przeglądarek wspiera CSS Nesting bez potrzeby używania preprocesorów.

.card {
  padding: 2rem;
  background: white;
  
  & .card-title {
    font-size: 1.5rem;
    color: var(--primary-color);
    
    & span {
      font-weight: bold;
    }
  }
  
  &:hover {
    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
  }
  
  &.featured {
    border: 2px solid gold;
  }
}

Zwróć uwagę na znak & – działa dokładnie tak, jak w SASS-ie. Ale tym razem to natywna funkcjonalność przeglądarki, nie wynik transpilacji.

@layer – panowanie nad kaskadą

Chris Coyier, twórca CSS-Tricks, powiedział kiedyś: „Cascade is CSS’s superpower and its Achilles’ heel.” I miał absolutną rację. @layer to odpowiedź CSS na wieczny problem ze specificity i kolejnością reguł.

@layer reset, base, components, utilities;

@layer reset {
  * {
    margin: 0;
    padding: 0;
  }
}

@layer components {
  .button {
    padding: 1rem 2rem;
    background: blue;
  }
}

@layer utilities {
  .bg-red {
    background: red; 
  }
}

Warstwy pozwalają nam dokładnie kontrolować, która reguła ma pierwszeństwo, niezależnie od kolejności w kodzie czy specificity selektorów. To tak, jakby nadać porządek w chaosie – coś, o co prosiliśmy latami.

Wszystko, co w powyższym przykładzie ma layer utilities, będzie miało pierwszeństwo, ponieważ utilities jest zadeklarowane jako ostatnie. W związku z tym przycisk, który miałby klasy .button i .bg-red, będzie mieć tło czerwone, nie niebieskiego, ponieważ utilities było podane później w @layer.

@scope – kontekstowe stylowanie

Czy zastanawiałeś się kiedyś, jak ograniczyć style tylko do konkretnego komponentu bez konieczności używania BEM czy innych konwencji nazewnictwa? @scope właśnie to robi.

@scope (.card) to (.card-footer) {
  /* Style działają tylko wewnątrz .card, ale NIE w .card-footer */
  p {
    color: gray;
    line-height: 1.6;
  }
  
  a {
    color: var(--link-color);
    text-decoration: none;
  }
}

To rozwiązuje problem „bleeding styles” – sytuacji, gdy nasze style niezamierzenie wpływają na zagnieżdżone komponenty. W praktyce to oznacza mniej kodu, więcej kontroli i zero potrzeby wymyślania skomplikowanych nazw klas.

Container Queries – prawdziwy responsive design

Media queries opierają się na szerokości viewportu. Container queries patrzą na szerokość kontenera. Różnica? Fundamentalna. To jak porównywać pogodę w całym kraju z pogodą w Twoim ogródku – to drugie jest dużo bardziej użyteczne dla Twoich pomidorów.

.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

@container sidebar (min-width: 400px) {
  .widget {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

@container sidebar (max-width: 399px) {
  .widget {
    display: block;
  }
}

Ethan Marcotte, ojciec responsive web design, na konferencji An Event Apart w 2021 roku stwierdził, że container queries to „brakujący kawałek” tej układanki. I trudno się z nim nie zgodzić – to zmienia sposób, w jaki myślimy o responsywności komponentów.

:has() – selektor rodzica, którego nie było

Przez lata mówiliśmy: „CSS nie może stylować elementów na podstawie ich dzieci”. To była prawda. Była. Pseudo-klasa :has() przewraca tę koncepcję do góry nogami.

/* Styluj formularz, jeśli zawiera błąd */
form:has(.error) {
  border: 2px solid red;
  background: #fee;
}

/* Styluj kartę, która nie ma obrazka */
.card:not(:has(img)) {
  padding-top: 0;
}

/* Styluj listę, która ma więcej niż 5 elementów */
ul:has(li:nth-child(6)) {
  column-count: 2;
}

/* Styluj paragraf poprzedzający obraz */
p:has(+ img) {
  margin-bottom: 0.5rem;
}

To nie jest już CSS, jaki znaliśmy. To CSS ze świadomością kontekstu, z „parent selector” i logiką, której wcześniej mogliśmy zazdrościć JavaScriptowi.

Funkcje kolorów nowej generacji

SASS dawał nam funkcje typu darken(), lighten(), mix(). CSS teraz ma coś lepszego – przestrzeń kolorów OKLCH i funkcję color-mix(), które działają w przestrzeniach kolorów zgodnych z ludzką percepcją.

.element {
  /* OKLCH - lepsze od HSL, bardziej przewidywalne */
  background: oklch(70% 0.15 260);
  
  /* color-mix - mieszanie kolorów */
  border-color: color-mix(in oklch, blue 70%, white);
  
  /* Animacje kolorów bez "brudnych" przejść */
  transition: background 0.3s in oklch;
}

.theme-colors {
  --base: oklch(60% 0.2 200);
  --lighter: oklch(from var(--base) calc(l + 20%) c h);
  --darker: oklch(from var(--base) calc(l - 20%) c h);
}

OKLCH to dość rozbudowana koncepcja, której poświęciłem osobny artykuł. Znajdziesz to tutaj:

OKLCH w CSS – kompletny przewodnik dla webdeveloperów

FunkcjaSASSNative CSSZaleta CSS
Zmienne$color--colorRuntime, JS access
Mieszaniemix()color-mix()Lepsza percepcja
Jasnośćlighten()oklch()Predykcyjność

Matematyka i kompozycja

calc(), min(), max(), clamp() – to funkcje, które SASS miał od zawsze, ale teraz CSS robi to lepiej, bo w czasie rzeczywistym.

.container {
  /* Responsywny padding bez media queries */
  padding: clamp(1rem, 5vw, 3rem);
  
  /* Fluid typography */
  font-size: clamp(1rem, 0.8rem + 0.5vw, 1.5rem);
  
  /* Matematyka z custom properties */
  --base-size: 16;
  --scale: 1.5;
  --level: 3;
  
  font-size: calc(var(--base-size) * pow(var(--scale), var(--level)) * 1px);
}

.grid {
  /* Container-aware grid */
  grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
}

Czy to już koniec SASS-a?

Nie oszukujmy się – SASS nie zniknie z dnia na dzień. Istnieje mnóstwo projektów legacy, w których zamiana preprocesora na native CSS nie ma sensu ekonomicznego. Ale dla nowych projektów? Pytanie brzmi: po co dodawać kolejny build step, kolejną zależność, kolejny punkt potencjalnej awarii, skoro przeglądarka już to wszystko umie?

W 2024 roku State of CSS survey pokazało, że 67% developerów używa CSS variables, 48% korzysta z container queries, a 52% z :has(). Liczby mówią same za siebie – native CSS nie jest już przyszłością, to teraźniejszość.

Oczywiście, SASS wciąż ma pewne przewagi – mixiny, funkcje, pętle. Ale czy naprawdę często ich używasz? A jeśli tak, to czy nie można tego zastąpić małą funkcją w JavaScript, generującą potrzebne style? W większości przypadków odpowiedź brzmi: tak, można.

Tabela porównawcza: SASS vs Native CSS

FunkcjonalnośćSASS/LESSNative CSSZwycięzca
ZmienneCompile-timeRuntimeCSS
Zagnieżdżanie✓ (od 2023)Remis
Warstwy kaskadyBrak@layerCSS
Container queriesBrakCSS
Parent selectorBrak:has()CSS
Build stepWymaganyNiepotrzebnyCSS
Browser support100% po kompilacji90%+ nowoczesneSASS*

*Ale różnica szybko znika

Praktyczne porady na migrację

Jeśli planujesz powoli żegnać się z preprocesorami, oto kilka kroków, które ułatwią przejście:

Zacznij od zmiennych – zamień $variable na --variable. To najprostszy krok, który od razu przynosi korzyści. Następnie przyjrzyj się zagnieżdżeniom – większość można przenieść 1:1 do native CSS. Pamiętaj o znaku &. Wreszcie, zidentyfikuj miejsca, gdzie używasz mixinów czy funkcji SASS-a – często da się je zastąpić calc() czy color-mix().

Nie musisz robić tego wszystkiego od razu. Możesz prowadzić projekt hybrydowy – część w SASS-ie, część w native CSS. Stopniowo przenosząc funkcjonalności, zobaczysz, gdzie native CSS wystarcza, a gdzie może faktycznie jeszcze potrzebujesz preprocesora.

Jedna rzecz jest pewna – za 5 lat rozmowa o SASS-ie będzie brzmiała podobnie jak dzisiaj rozmowa o jQuery. „Pamiętasz, jak kiedyś musieliśmy używać preprocesora do zmiennych?” Młodsze pokolenie developerów będzie patrzeć na nas jak na dinozaury. I może to wcale nie jest złe – ewolucja to przecież postęp.

CSS dorósł. Nauczył się tego wszystkiego, czego uczyliśmy go przez preprocesory. Teraz robi to lepiej, szybciej i bez pośredników. Czas dać mu szansę błysnąć.

Udostępnij wpis
1 Gwiazdka2 Gwiazdki3 Gwiazdki4 Gwiazdki5 Gwiazdek (1 głosów, średnia: 5,00 z 5)
Loading...

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *