Lekcja 17

Fluid typography i funkcje min(), max(), clamp()

Po obrazach i mediach responsywnych czas na płynne skalowanie tekstu oraz odstępów. Zamiast skakać między rozmiarami tylko na breakpointach, możesz pozwolić wartościom rosnąć stopniowo w bezpiecznych granicach.

Cele lekcji

Po ukończeniu tej lekcji będziesz umieć:

  • wyjaśnić, czym różni się skokowa responsywność od płynnej skali,
  • użyć min() do wyboru mniejszej z kilku wartości,
  • użyć max() do ustawienia minimalnej granicy,
  • zbudować bezpieczny rozmiar tekstu przez clamp(),
  • tworzyć płynne odstępy bez nadmiaru breakpointów,
  • utrzymać czytelność tekstu na mobile i desktopie.

Kontekst praktyczny

Płynna typografia przydaje się w hero, leadach artykułów, kartach marketingowych, dashboardach i stronach edukacyjnych. Duże nagłówki mogą rosnąć razem z viewportem, ale nie powinny stać się ani zbyt małe na telefonie, ani absurdalnie wielkie na szerokim monitorze.

W praktyce: najlepszy efekt daje połączenie wartości względnych. Dolna i górna granica zwykle są w rem, a środek skali miesza rem z vw.

Problem skokowej skali

Klasyczne breakpointy często zmieniają tekst skokowo: na małym ekranie nagłówek ma 2rem, a od 1024px nagle dostaje 3.5rem. To działa, ale między breakpointami layout może wyglądać przypadkowo.

.hero-title {
  font-size: 2rem;
}

@media (min-width: 1024px) {
  .hero-title {
    font-size: 3.5rem;
  }
}

Fluid typography pozwala zastąpić wiele takich progów jedną wartością, która płynnie reaguje na szerokość viewportu.

min()

min() wybiera mniejszą z podanych wartości. To użyteczne, gdy element ma rosnąć, ale nie przekroczyć rozsądnego limitu.

.content {
  width: min(100%, 42rem);
}

Ten zapis oznacza: kontener może mieć pełną szerokość rodzica, ale maksymalnie 42rem. To czytelniejsza alternatywa dla pary width: 100% i max-width.

max()

max() wybiera większą z wartości. Przydaje się, gdy chcesz zagwarantować minimalny rozmiar albo odstęp, nawet jeśli druga wartość jest zależna od viewportu.

.section {
  padding-block: max(2rem, 6vw);
}

Na małym ekranie odstęp nie spadnie poniżej 2rem, a na większym może rosnąć zależnie od szerokości viewportu.

clamp()

clamp() ma trzy wartości: minimum, wartość preferowaną i maksimum. Przeglądarka wybiera wartość preferowaną, ale pilnuje dolnej i górnej granicy.

.hero-title {
  font-size: clamp(2rem, 1.2rem + 4vw, 4.5rem);
  line-height: 1.05;
}

Odczyt praktyczny: nagłówek nigdy nie będzie mniejszy niż 2rem, będzie rósł według wartości 1.2rem + 4vw, ale zatrzyma się na 4.5rem.

Fluid typography

W większym projekcie warto zbudować kilka tokenów typograficznych. Dzięki temu komponenty nie używają przypadkowych wartości, tylko wspólnej skali.

:root {
  --text-sm: clamp(0.875rem, 0.82rem + 0.2vw, 1rem);
  --text-md: clamp(1rem, 0.95rem + 0.35vw, 1.125rem);
  --text-lg: clamp(1.25rem, 1.05rem + 0.9vw, 1.75rem);
  --text-xl: clamp(2rem, 1.3rem + 3vw, 4rem);
}

.article-title {
  font-size: var(--text-xl);
  line-height: 1.08;
}

Nie każda wartość musi być płynna. Tekst akapitu często może zostać stabilny, a największy zysk daje płynna skala nagłówków i dużych elementów kompozycyjnych.

Płynne odstępy

Te same funkcje możesz stosować do paddingu, gapów i marginesów. Płynny spacing pomaga utrzymać rytm bez dopisywania breakpointu do każdej sekcji.

.section {
  padding-block: clamp(2.5rem, 6vw, 6rem);
}

.card-grid {
  gap: clamp(1rem, 2vw, 2rem);
}

Granice są tu tak samo ważne jak przy tekście. Bez maksimum odstępy na dużych monitorach mogą zacząć marnować przestrzeń.

Granice i dostępność

Płynna typografia ma poprawiać czytelność, nie robić efektu wizualnego za wszelką cenę. W praktyce pilnuj trzech rzeczy:

  • minimum nie może być zbyt małe dla użytkowników na mobile,
  • maksimum nie może rozpychać layoutu na desktopie,
  • akapit nadal potrzebuje sensownej długości linii, np. max-width: 65ch.
Zapamiętaj: płynny rozmiar tekstu nie zastępuje hierarchii. Nadal potrzebujesz dobrego kontrastu, line-height, szerokości tekstu i logicznej skali nagłówków.

Demo płynnej skali

Poniższe demo pokazuje, jak jedna skala może kontrolować nagłówek, lead, odstępy i kartę bez dokładania kolejnych breakpointów.

.fluid-card {
  padding: clamp(1rem, 3vw, 2rem);
}

.fluid-card h3 {
  font-size: clamp(1.5rem, 1rem + 2vw, 3rem);
}

.fluid-card p {
  max-width: 58ch;
}
clamp()

Ten nagłówek skaluje się płynnie

Jego rozmiar ma dolną granicę, wartość reagującą na viewport i górny limit, dzięki czemu pozostaje czytelny na telefonie i desktopie.

min 2rem
mobile
desktop
max 4.5rem

Interpretacja: clamp() daje kontrolę nad całym zakresem. Tekst może reagować na ekran, ale nie wymyka się poza zaplanowane minimum i maksimum.

Najczęstsze błędy początkujących

  • Używanie samego vw dla fontu, przez co tekst robi się zbyt mały lub zbyt duży.
  • Brak dolnej i górnej granicy dla dużych nagłówków.
  • Tworzenie wielu przypadkowych wartości clamp() zamiast małej skali tokenów.
  • Skalowanie akapitów tak mocno, że zmienia się rytm czytania.
  • Ignorowanie line-height po zwiększeniu rozmiaru fontu.
  • Brak testu na wąskim viewportcie i bardzo szerokim desktopie.

Mini zadanie

Zbuduj sekcję hero z płynną typografią i odstępami.

  • Ustaw nagłówek przez font-size: clamp(2rem, 1.2rem + 4vw, 4.5rem).
  • Dodaj lead z max-width: 60ch i spokojnym line-height.
  • Ustaw padding sekcji przez clamp(3rem, 8vw, 7rem).
  • Przetestuj szerokości 390px, 768px, 1440px i sprawdź, czy tekst nie rozpycha layoutu.
  • Wydziel przynajmniej dwa tokeny CSS, np. --text-lg i --space-section.

Checklista

  • Rozumiem, że min() wybiera mniejszą wartość.
  • Rozumiem, że max() wybiera większą wartość.
  • Potrafię czytać zapis clamp(min, preferowane, max).
  • Umiem zbudować płynny nagłówek z granicami w rem.
  • Wiem, że vw powinno być ograniczone przez clamp().
  • Testuję płynną skalę na małym ekranie, tablecie i szerokim desktopie.

Podsumowanie lekcji

min(), max() i clamp() pozwalają budować wartości, które reagują na kontekst, ale nie tracą kontroli. Najważniejszym narzędziem dla fluid typography jest clamp(), bo łączy minimum, skalowanie i maksimum w jednym zapisie.

Kolejny krok roadmapy to komponenty UI: linki, przyciski i stany hover, focus, active oraz disabled.

Przejdź do Lekcji 18