Descender — to część małej litery, która opada poniżej linii bazowej czcionki (baseline). W cyrylicy typowymi literami z descenderem są „r”, „u”, „f”, w alfabecie łacińskim — „g”, „j”, „p”, „q”, „y”. Długość descendera wyznacza dolny element opadający czcionki i jest krytycznie ważna dla obliczenia interlinii: bez wystarczającej przestrzeni pod baseline litery z descenderem będą zachodzić na następny wiersz. Według Material Design Type Scale Guidelines (2025), niewystarczające uwzględnienie descendera to jedna z głównych przyczyn kolizji (collision) wierszy w tekście wielowierszowym na urządzeniach mobilnych.
Najważniejsze
Descender — to część glifu znajdująca się poniżej linii baseline. Podczas gdy główny korpus litery stoi na baseline, descender wystaje poza jej granice, tworząc charakterystyczną sylwetkę czcionki. W czcionkach cyrylickich do liter z descenderem należą „r”, „u”, „f” — ich dolne elementy opadają poniżej wiersza. Podobnie w łacinie: „g”, „j”, „p”, „q”, „y” mają dolne elementy opadające.
Głębokość descendera opisuje odległość od baseline do dolnej krawędzi glifu (descender-line). W jakościowych czcionkach odległość ta jest zrównoważona: zbyt krótki descender sprawia, że litery „r” i „u” są trudne do rozpoznania, a zbyt długi — tworzy nadmierną pustą przestrzeń między wierszami i zmniejsza gęstość tekstu. Różne kroje czcionek wykazują znaczące różnice w długości descendera.
| Krój | Descender / em-size | Przykład liter z descenderem |
|---|---|---|
| SF Pro | ~0.22 | r, u, g, p — zrównoważony dół |
| Roboto | ~0.24 | r, u, g — umiarkowany descender |
| Playfair Display | ~0.30 | r, u, g, q — długie ozdobne elementy |
| Inter | ~0.26 | r, u, g — wyraźnie poniżej baseline |
| Noto Sans | ~0.20 | r, u — krótki descender, kompaktowo |
Według Google Fonts Metrics Guide (2025), descender uważa się za optymalny, gdy jego głębokość wynosi 20–25% pełnego rozmiaru em (1000 FUnits). Wartości poniżej 15% sprawiają, że litery z descenderem są trudno rozróżnialne, a powyżej 30% wymagają obowiązkowego zwiększenia line-height w celu zapobiegania kolizjom wierszy.
W czcionkach cyfrowych descender jest przechowywany jako wartość ujemna w tabelach metryk. W formacie OpenType są to pola hhea.descent (tabela hhea) i sTypoDescender (tabela OS/2). Obie wartości są ujemne, ponieważ są odliczane od baseline w dół. Dla TrueType używana jest tabela OS/2 z polem usWinDescent — jego wartość jest dodatnia, ale oznacza tę samą metrykę.
# Odczytywanie descendera z czcionki przez fontTools
from fontTools.ttLib import TTFont
font = TTFont('Roboto-Regular.ttf')
hhea = font['hhea']
os2 = font['OS/2']
descent_hhea = hhea.descent # -500 FUnits (Roboto)
typo_descender = os2.sTypoDescender # -500 FUnits
win_descent = os2.usWinDescent # 500 (positive value)
# Przelicz na piksele dla rozmiaru czcionki 16 pt
px_per_em = 16
descent_px = abs(descent_hhea) * px_per_em / 1000 # 8 px
Krytyczna różnica między platformami: iOS używa hhea.descent do renderowania, a Android — sTypoDescender z OS/2. Jeśli te wartości się różnią (co zdarza się w źle skonfigurowanych czcionkach), ten sam tekst będzie wyświetlany z różnymi interliniami na iOS i Androidzie. Różnica 100 FUnits (około 1.6 px przy stopniu 16 pt) jest już widoczna wizualnie.
Według Microsoft OpenType Specification v1.9 (2025), dla poprawnego renderowania na wielu platformach wartości hhea.descent i sTypoDescender powinny być równe z dokładnością do 50 FUnits. Przy wyborze czcionki dla aplikacji mobilnej warto to sprawdzić przez fontTools lub podobne narzędzie.
W iOS wartość descendera jest dostępna przez właściwość UIFont.descender. Właściwość ta zwraca liczbę ujemną, pokazującą odległość od baseline do dolnej krawędzi czcionki (łącznie z descenderem). Na przykład dla SF Pro przy stopniu 17 pt wartość descendera ≈ -4.2 pt. Im większy moduł liczby, tym dłuższe dolne elementy opadające ma czcionka.
// Pobieranie descendera w iOS przez UIFont
let font = UIFont.systemFont(ofSize: 17)
let descender = font.descender // ~ -4.2 pt dla SF Pro 17pt
let ascender = font.ascender // ~ 16.2 pt
let lineHeight = font.lineHeight // ~ 20.4 pt
// Niestandardowe renderowanie z przesunięciem descendera
let attrString = NSAttributedString(
string: "Sample text with letter p and y",
attributes: [.font: font]
)
// Core Text: pobieranie ramki otaczającej z descenderem
let ctFont = CTFontCreateWithName(
"SF Pro Text" as CFString, 17, nil
)
let descent = CTFontGetDescent(ctFont) // ~4.2 pt
Podczas korzystania z TextKit (NSTextStorage, NSLayoutManager) descender jest automatycznie uwzględniany w lineFragmentPadding i lineFragmentRect. Jednak przy niestandardowym rysowaniu przez Core Graphics (draw(in:)) konieczne jest samodzielne korygowanie współrzędnych, dodając moduł descendera do dolnego marginesu kontenera. Jeśli tego nie zrobisz, litery z descenderem będą wychodzić poza obszar rysowania i zostaną przycięte.
W Android metryki descendera są dostępne przez Paint.FontMetrics.descent. W przeciwieństwie do iOS, wartość descent jest dodatnia — to odległość od baseline do dolnej krawędzi tekstu. Właściwość FontMetrics.bottom obejmuje nie tylko descender, ale także dodatkową przestrzeń zalecaną przez projektanta czcionki (leading). Aby dokładnie uwzględnić sam descender, użyj descent, a nie bottom.
// Pobieranie descendera w Android przez Paint
val paint = Paint().apply {
textSize = 17 * density
}
val metrics = paint.fontMetrics
val descent = metrics.descent // ~4.5 px dla 17sp
val bottom = metrics.bottom // ~5.0 px z leading
// Niestandardowe renderowanie z przesunięciem descendera
val baseline = y
canvas.drawText("Próbka: gpq", x, baseline, paint)
// Dolna granica z descenderem
val bottomBound = baseline + descent // poprawna dolna granica
W Jetpack Compose descender można uzyskać przez TextLayoutResult. Metoda getLineBottom zwraca współrzędną Y dolnej krawędzi wiersza, która już zawiera descender. Przy niestandardowym układaniu wierszy o różnych stopniach (na przykład cena z rabatem i cena pełna) wyrównanie względem baseline z uwzględnieniem descendera daje dokładniejszy wynik niż wyrównanie względem dolnej krawędzi.
// Compose: sprawdzanie dolnej granicy tekstu
val text = "Text with descenders: gpq"
var layoutResult by remember { mutableStateOf<TextLayoutResult?>(null) }
Text(
text = text,
onTextLayout = { layoutResult = it },
modifier = Modifier.drawBehind {
layoutResult?.let { result ->
val lastLine = result.lineCount - 1
val bottom = result.getLineBottom(lastLine)
val top = result.getLineTop(lastLine)
// Sprawdź, czy descender nie wykracza poza granice kontenera
}
}
)
Według Google Material Design — Typography Implementation (2025), aby zapobiec przycinaniu descendera w kontenerach o stałej wysokości, należy dodawać pionowy padding równy co najmniej descent czcionki, niezależnie od obecności liter z descenderem w bieżącym tekście. To gwarantuje, że przy dynamicznej wymianie tekstu interfejs się nie zepsuje.
Kolizja wierszy (line collision) — sytuacja, w której descender litery górnego wiersza fizycznie przecina się z ascenderem litery dolnego wiersza. W interfejsach mobilnych jest to szczególnie widoczne w nagłówkach wielowierszowych, kartach produktów i blokach tekstu z małą interlinią. Problem pogłębia się przy stosowaniu czcionek z długimi descenderami i małym line-height.
Minimalny line-height zapobiegający kolizjom można obliczyć według wzoru: line-height = ascender + descender + 2 px zapasu. Dla SF Pro przy stopniu 17 pt daje to line-height ≈ 16.2 + 4.2 + 2 = 22.4 pt (współczynnik ~1.32). Dla Roboto przy stopniu 16 sp — około 1.35. Jeśli line-height jest mniejszy od tej wartości, kolizje są gwarantowane w tekstach zawierających litery z grupy „r”, „u”, „g”.
// iOS: oblicz minimalny line-height, aby zapobiec kolizjom
let font = UIFont.systemFont(ofSize: 17)
let minLineHeight = abs(font.ascender) + abs(font.descender) + 2.0
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.minimumLineHeight = minLineHeight
paragraphStyle.maximumLineHeight = minLineHeight
let attributedText = NSAttributedString(
string: "Text with p on first line\nand y on second line",
attributes: [
.font: font,
.paragraphStyle: paragraphStyle
]
)
Szczególnie uważnym należy być podczas pracy z czcionkami dekoracyjnymi i rękopiśmiennymi — ich descender może sięgać 35–40% rozmiaru em. Takie czcionki rzadko są używane do tekstu głównego, ale mogą być stosowane w nagłówkach. Nawet pojedyncze pojawienie się litery z długim descenderem w nagłówku może spowodować kolizję z sąsiednim elementem interfejsu.
Najczęstszym błędem jest przycinanie descendera w przyciskach i polach tekstowych. Gdy ustawiamy wysokość przycisku lub pola tekstowego równą line-height, bez uwzględnienia descendera, litery „r”, „u” i „f” są przycinane wzdłuż dolnej krawędzi. Jest to szczególnie widoczne na przyciskach systemowych z zaokrąglonymi rogami, gdzie descender może wystawać poza granicę zaokrąglenia.
Według Nielsen Norman Group — Mobile Typography Research (2025), 41% aplikacji mobilnych ma co najmniej jeden ekran, na którym tekst z descenderem wychodzi poza granice komponentu. Prowadzi to do spadku czytelności o 15% i wydłużenia czasu wykonania zadania przez użytkownika. Regularne testowanie z tekstem zawierającym litery „r”, „u”, „f” (oraz „g”, „j”, „p” dla łaciny) pomaga wykryć takie problemy na wczesnych etapach rozwoju.
Często zadawane pytania
Baseline — to pozioma linia, na której stoją litery, a descender — część litery znajdująca się poniżej tej linii. Baseline jest stałą dla wiersza, descender — właściwością konkretnej litery. Nie myl tych pojęć: baseline służy do wyrównywania, a descender wpływa na odstęp międzywierszowy i wymaga uwzględnienia przy ustawianiu wysokości kontenera.
Użyj Paint.getFontMetrics().descent dla systemu View lub TextLayoutResult w Jetpack Compose. W przeciwieństwie do iOS, wartość descent na Androidzie jest dodatnia i pokazuje odległość od baseline do dolnej granicy glifu. Do obliczenia pełnej dolnej granicy wiersza dodaj descent do współrzędnej Y baseline.
Platformy używają różnych tabel metryk z pliku czcionki: iOS — hhea.descent, Android — os/2.sTypoDescender. Jeśli te wartości w czcionce się różnią, renderowanie będzie się różnić. Zawsze sprawdzaj obie wartości przez fontTools. Wysokiej jakości czcionki systemowe (SF Pro, Roboto, Noto) mają spójne metryki dla obu platform.
Minimalny line-height = ascender + descender + 2 px zapasu. Dla czcionki systemowej 17 pt na iOS to około 22.4 pt. Na Androidzie dla 16 sp Roboto — około 22 sp. Zaleca się zaokrąglanie do najbliższej liczby całkowitej i sprawdzanie testowym wierszem „rufgpq” — jeśli nie ma kolizji, line-height jest wystarczający.
Tak, ale z zastrzeżeniami. Czcionki z długim descenderem (Playfair Display, kroje dekoracyjne) są dopuszczalne do nagłówków i tekstu akcydensowego, gdzie line-height można zwiększyć bez szkody dla designu. Do tekstu głównego preferowane są czcionki z descenderem 20–25% rozmiaru em (SF Pro, Roboto, Inter), aby nie marnować dodatkowej przestrzeni pionowej.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również