Descender este partea unei litere mici care se extinde sub linia de bază (baseline) a fontului. În alfabetul latin, literele tipice cu descender sunt „g", „j", „p", „q", „y". Lungimea descender-ului determină elementul inferior al fontului și este critică pentru calcularea spațierii liniilor: fără spațiu suficient sub baseline, literele cu descender vor atinge rândul următor. Conform Material Design Type Scale Guidelines (2025), ignorarea descender-ului este una dintre principalele cauze ale coliziunii liniilor în textul multi-rând pe dispozitivele mobile.
Principalele idei
Descender este partea unui glif situată sub linia baseline. În timp ce corpul principal al literei stă pe baseline, descender se extinde dincolo de acesta, creând un siluet caracteristic al fontului. În fonturile latine, literele „g", „j", „p", „q", „y" au elemente inferioare.
Adâncimea descender-ului descrie distanța de la baseline până la marginea inferioară a glifului (descender-line). În fonturile de calitate, această distanță este echilibrată: un descender prea scurt face literele cu descender greu de recunoscut, iar unul prea lung creează spațiu gol excesiv între rânduri și reduce densitatea textului. Diferite familii de fonturi prezintă diferențe semnificative în lungimea descender-ului.
| Font | Descender / em-size | Exemple de litere cu descender |
|---|---|---|
| SF Pro | ~0.22 | g, p — extensie echilibrată |
| Roboto | ~0.24 | g, p — descender moderat |
| Playfair Display | ~0.30 | g, q — elemente decorative lungi |
| Inter | ~0.26 | g, p — vizibil sub baseline |
| Noto Sans | ~0.20 | g — descender scurt, compact |
Conform Google Fonts Metrics Guide (2025), descender-ul este considerat optim atunci când adâncimea sa este de 20–25% din dimensiunea completă em (1000 FUnits). Valorile sub 15% fac literele cu descender greu de distins, iar peste 30% necesită creșterea obligatorie a line-height pentru a preveni coliziunile rândurilor.
În fonturile digitale, descender este stocat ca o valoare negativă în tabelele de metrice. În formatul OpenType, acesta este câmpul hhea.descent (tabela hhea) și sTypoDescender (tabela OS/2). Ambele valori sunt negative, deoarece sunt măsurate de la baseline în jos. Pentru TrueType se utilizează tabela OS/2 cu câmpul usWinDescent — valoarea sa este pozitivă, dar desemnează aceeași metrică.
# Citirea descender-ului din font prin 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)
# Convertirea în pixeli pentru dimensiunea fontului de 16pt
px_per_em = 16
descent_px = abs(descent_hhea) * px_per_em / 1000 # 8 px
Diferența critică între platforme: iOS utilizează hhea.descent pentru randare, iar Android — sTypoDescender din OS/2. Dacă aceste valori diferă (ceea ce se întâmplă în fonturile configurate necorespunzător), același text va fi afișat cu spațieri diferite între rânduri pe iOS și Android. O diferență de 100 FUnits (aproximativ 1.6 px la dimensiunea de 16 pt) este deja vizibilă.
Conform Microsoft OpenType Specification v1.9 (2025), pentru o randare cross-platform corectă, valorile hhea.descent și sTypoDescender ar trebui să fie egale cu o precizie de 50 FUnits. La alegerea unui font pentru o aplicație mobilă, acest lucru merită verificat prin fontTools sau o unealtă similară.
În iOS, valoarea descender-ului este disponibilă prin proprietatea UIFont.descender. Această proprietate returnează un număr negativ, indicând distanța de la baseline până la marginea inferioară a fontului (inclusiv descender). De exemplu, pentru SF Pro la dimensiunea de 17 pt, valoarea descender-ului este de aproximativ -4.2 pt. Cu cât modulul numărului este mai mare, cu atât elementele inferioare ale fontului sunt mai lungi.
// Obținerea descender-ului pe iOS prin UIFont
let font = UIFont.systemFont(ofSize: 17)
let descender = font.descender // ~ -4.2 pt pentru SF Pro 17pt
let ascender = font.ascender // ~ 16.2 pt
let lineHeight = font.lineHeight // ~ 20.4 pt
// Randare personalizată cu offset descender
let attrString = NSAttributedString(
string: "Sample text with letter p and y",
attributes: [.font: font]
)
// Core Text: obținerea căsuței de delimitare cu descender
let ctFont = CTFontCreateWithName(
"SF Pro Text" as CFString, 17, nil
)
let descent = CTFontGetDescent(ctFont) // ~4.2 pt
La utilizarea TextKit (NSTextStorage, NSLayoutManager), descender-ul este luat automat în considerare în lineFragmentPadding și lineFragmentRect. Totuși, la randarea personalizată prin Core Graphics (draw(in:)), este necesar să ajustați manual coordonatele, adăugând modulul descender-ului la marginea inferioară a containerului. Dacă acest lucru nu se face, literele cu descender vor ieși din limita de randare și vor fi tăiate.
În Android, metricele descender-ului sunt disponibile prin Paint.FontMetrics.descent. Spre deosebire de iOS, valoarea descent este pozitivă — reprezintă distanța de la baseline până la marginea inferioară a textului. Proprietatea FontMetrics.bottom include nu doar descender, ci și spațiul suplimentar recomandat de designerul fontului (leading). Pentru a lua în considerare doar descender-ul, utilizați descent, nu bottom.
// Obținerea descender-ului pe Android prin Paint
val paint = Paint().apply {
textSize = 17 * density
}
val metrics = paint.fontMetrics
val descent = metrics.descent // ~4.5 px pentru 17sp
val bottom = metrics.bottom // ~5.0 px cu leading
// Randare personalizată cu offset descender
val baseline = y
canvas.drawText("Exemplu: gpq", x, baseline, paint)
// Marginea inferioară cu descender
val bottomBound = baseline + descent // marginea inferioară corectă
În Jetpack Compose, descender-ul poate fi obținut prin TextLayoutResult. Metoda getLineBottom returnează coordonata Y a marginii inferioare a rândului, care include deja descender-ul. La layout-ul personalizat al rândurilor cu dimensiuni diferite (de exemplu, preț redus și preț întreg), alinierea pe baseline ținând cont de descender oferă un rezultat mai precis decât alinierea pe marginea inferioară.
// Compose: verificarea marginii inferioare a textului
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)
// Verificarea că descender-ul nu depășește limitele containerului
}
}
)
Conform Google Material Design — Typography Implementation (2025), pentru a preveni tăierea descender-ului în containerele cu înălțime fixă, este necesar să adăugați un padding vertical egal cel puțin cu descent-ul fontului, indiferent de prezența literelor cu descender în textul curent. Acest lucru garantează că, la înlocuirea dinamică a textului, interfața nu se va strica.
Coliziunea rândurilor (line collision) este situația în care descender-ul literei de pe rândul superior se intersectează fizic cu ascender-ul literei de pe rândul inferior. În interfețele mobile, acest lucru este vizibil mai ales în titlurile multi-rând, cardurile de produse și blocurile de text cu spațiere redusă între rânduri. Problema se agravează la utilizarea fonturilor cu descender lungi și line-height mic.
Line-height-ul minim care previne coliziunile poate fi calculat după formula: line-height = ascender + descender + 2 px marjă. Pentru SF Pro la dimensiunea de 17 pt, aceasta oferă un line-height de aproximativ 22.4 pt (coeficient ~1.32). Pentru Roboto la 16 sp — aproximativ 1.35. Dacă line-height-ul este mai mic decât această valoare, coliziunile sunt garantate în textele care conțin litere din grupul „g", „j", „p", „q", „y".
// iOS: calculul line-height-ului minim pentru a preveni coliziunile
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
]
)
O atenție deosebită trebuie acordată la lucrul cu fonturi decorative și scrise de mână — descender-ul lor poate atinge 35–40% din dimensiunea em. Astfel de fonturi sunt rareori utilizate pentru textul principal, dar pot fi folosite în titluri. Chiar și o singură apariție a unei litere cu descender lung într-un titlu poate provoca o coliziune cu elementul vecin al interfeței.
Cea mai frecventă greșeală este tăierea descender-ului în butoane și câmpuri text. Când setăm înălțimea unui buton sau câmp text egală cu line-height, fără a ține cont de descender, literele cu descender sunt tăiate la marginea inferioară. Acest lucru este vizibil mai ales pe butoanele sistemului cu colțuri rotunjite, unde descender-ul poate ieși dincolo de limita rotunjirii.
Conform Nielsen Norman Group — Mobile Typography Research (2025), 41% dintre aplicațiile mobile au cel puțin un ecran în care textul cu descender iese din limitele componentei. Aceasta duce la o scădere a lizibilității cu 15% și la o creștere a timpului de executare a sarcinii de către utilizator. Testarea regulată cu text care conține literele „g", „j", „p", „q", „y" ajută la identificarea acestor probleme în fazele incipiente ale dezvoltării.
Întrebări frecvente
Baseline este linia orizontală pe care stau literele, iar descender-ul este partea literei aflată sub această linie. Baseline este o constantă pentru rând, descender-ul este o proprietate a unei litere specifice. Nu confundați aceste concepte: baseline este utilizat pentru aliniere, iar descender-ul influențează spațierea dintre rânduri și necesită atenție la setarea înălțimii containerului.
Utilizați Paint.getFontMetrics().descent pentru sistemul View sau TextLayoutResult în Jetpack Compose. Spre deosebire de iOS, valoarea descent pe Android este pozitivă și arată distanța de la baseline până la marginea inferioară a glifului. Pentru a calcula marginea inferioară completă a rândului, adăugați descent la coordonata Y a baseline-ului.
Platformele utilizează tabele de metrice diferite din fișierul fontului: iOS — hhea.descent, Android — os/2.sTypoDescender. Dacă aceste valori în font diferă, randarea va fi diferită. Verificați întotdeauna ambele valori prin fontTools. Fonturile sistemice de calitate (SF Pro, Roboto, Noto) au metrice consistente pentru ambele platforme.
Line-height-ul minim este line-height = ascender + descender + 2 px marjă. Pentru fontul de sistem de 17 pt pe iOS, aceasta este de aproximativ 22.4 pt. Pe Android, pentru 16 sp Roboto — aproximativ 22 sp. Se recomandă rotunjirea la cel mai apropiat întreg și verificarea cu șirul de testare „gpq" — dacă nu există coliziuni, line-height-ul este suficient.
Da, dar cu condiții. Fonturile cu descender lung (Playfair Display, caractere decorative) sunt acceptabile pentru titluri și text accentual, unde line-height-ul poate fi mărit fără a afecta designul. Pentru textul principal, sunt preferate fonturile cu descender de 20–25% din dimensiunea em (SF Pro, Roboto, Inter) pentru a nu pierde spațiu vertical inutil.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și