Descender е част от малката буква, която се спуска под базовата линия (baseline) на шрифта. В латинската азбука типични букви с descender са „g", „j", „p", „q", „y". Дължината на descender определя долния изпъкнал елемент на шрифта и е критична за изчисляване на междуредието: без достатъчно пространство под baseline, буквите с descender ще засягат следващия ред. Според Material Design Type Scale Guidelines (2025), недостатъчното отчитане на descender е една от основните причини за сблъсък (collision) на редове в многоредов текст на мобилни устройства.
Основни точки
Descender е част от глифа, разположена под линията baseline. Докато основното тяло на буквата стои на baseline, descender се простира отвъд нея, създавайки характерен силует на шрифта. В латинските шрифтове буквите „g", „j", „p", „q", „y" имат долни изпъкнали елементи.
Дълбочината на descender описва разстоянието от baseline до долната граница на глифа (descender-line). В качествените шрифтове това разстояние е балансирано: твърде късият descender прави буквите с descender трудни за разпознаване, а твърде дългият създава прекомерно празно пространство между редовете и намалява плътността на текста. Различните шрифтови гарнитури показват значителни разлики в дължината на descender.
| Шрифт | Descender / em-size | Примерни букви с descender |
|---|---|---|
| SF Pro | ~0.22 | g, p — балансирано издаване |
| Roboto | ~0.24 | g, p — умерен descender |
| Playfair Display | ~0.30 | g, q — дълги декоративни елементи |
| Inter | ~0.26 | g, p — забележимо под baseline |
| Noto Sans | ~0.20 | g — къс descender, компактен |
Според Google Fonts Metrics Guide (2025), descender се счита за оптимален, когато дълбочината му е 20–25% от пълния размер em (1000 FUnits). Стойности под 15% затрудняват различаването на букви с descender, а над 30% изискват задължително увеличаване на line-height за предотвратяване на сблъсъци на редове.
В цифровите шрифтове descender се съхранява като отрицателна стойност в таблиците с метрики. В OpenType формат това са полетата hhea.descent (таблица hhea) и sTypoDescender (таблица OS/2). И двете стойности са отрицателни, тъй като се измерват от baseline надолу. За TrueType се използва таблица OS/2 с поле usWinDescent — стойността му е положителна, но обозначава същата метрика.
# Четене на descender от шрифт чрез 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)
# Преобразуване в пиксели за размер на шрифта 16pt
px_per_em = 16
descent_px = abs(descent_hhea) * px_per_em / 1000 # 8 px
Критичната разлика между платформите: iOS използва hhea.descent за рендериране, а Android — sTypoDescender от OS/2. Ако тези стойности се различават (което се случва в некачествено настроени шрифтове), един и същи текст ще се показва с различно междуредие на iOS и Android. Разлика от 100 FUnits (приблизително 1.6 px при размер 16 pt) вече е визуално забележима.
Според Microsoft OpenType Specification v1.9 (2025), за коректно междуплатформено рендериране, стойностите на hhea.descent и sTypoDescender трябва да са равни с точност до 50 FUnits. При избор на шрифт за мобилно приложение, това трябва да се провери чрез fontTools или подобен инструмент.
В iOS стойността на descender е достъпна чрез свойството UIFont.descender. Това свойство връща отрицателно число, показващо разстоянието от baseline до долния край на шрифта (включително descender). Например за SF Pro при размер 17 pt стойността на descender е приблизително -4.2 pt. Колкото по-голяма е абсолютната стойност, толкова по-дълги са долните изпъкнали елементи на шрифта.
// Получаване на descender на iOS чрез UIFont
let font = UIFont.systemFont(ofSize: 17)
let descender = font.descender // ~ -4.2 pt за SF Pro 17pt
let ascender = font.ascender // ~ 16.2 pt
let lineHeight = font.lineHeight // ~ 20.4 pt
// Персонализирано рендериране с отместване на descender
let attrString = NSAttributedString(
string: "Sample text with letter p and y",
attributes: [.font: font]
)
// Core Text: получаване на ограничителна кутия с descender
let ctFont = CTFontCreateWithName(
"SF Pro Text" as CFString, 17, nil
)
let descent = CTFontGetDescent(ctFont) // ~4.2 pt
При използване на TextKit (NSTextStorage, NSLayoutManager), descender автоматично се отчита в lineFragmentPadding и lineFragmentRect. Въпреки това, при персонализирано рендериране чрез Core Graphics (draw(in:)), трябва самостоятелно да коригирате координатите, като добавите абсолютната стойност на descender към долния марж на контейнера. Ако това не се направи, буквите с descender ще излязат извън границата на рендериране и ще бъдат отрязани.
В Android метриките на descender са достъпни чрез Paint.FontMetrics.descent. За разлика от iOS, стойността на descent е положителна — това е разстоянието от baseline до долната граница на текста. Свойството FontMetrics.bottom включва не само descender, но и допълнителното пространство, препоръчано от дизайнера на шрифта (leading). За точно отчитане само на descender, използвайте descent, а не bottom.
// Получаване на descender на Android чрез Paint
val paint = Paint().apply {
textSize = 17 * density
}
val metrics = paint.fontMetrics
val descent = metrics.descent // ~4.5 px за 17sp
val bottom = metrics.bottom // ~5.0 px с leading
// Персонализирано рендериране с отместване на descender
val baseline = y
canvas.drawText("Пример: gpq", x, baseline, paint)
// Долна граница с descender
val bottomBound = baseline + descent // правилна долна граница
В Jetpack Compose descender може да бъде получен чрез TextLayoutResult. Методът getLineBottom връща Y-координатата на долната граница на реда, която вече включва descender. При персонализирано оформление на редове с различни размери (напр. цена с отстъпка и пълна цена), подравняването по baseline с отчитане на descender дава по-точен резултат от подравняването по долния ръб.
// Compose: проверка на долната граница на текст
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)
// Проверка дали descender не надвишава границите на контейнера
}
}
)
Според Google Material Design — Typography Implementation (2025), за предотвратяване на отрязване на descender в контейнери с фиксирана височина, трябва да се добави вертикален padding, равен най-малко на descent на шрифта, независимо от наличието на букви с descender в текущия текст. Това гарантира, че при динамична смяна на текста, интерфейсът няма да се счупи.
Сблъсък на редове (line collision) — ситуация, при която descender на буква от горния ред физически пресича ascender на буква от долния ред. В мобилните интерфейси това е особено забележимо в многоредови заглавия, продуктови карти и текстови блокове с малко междуредие. Проблемът се задълбочава при използване на шрифтове с дълъг descender и малък line-height.
Минималният line-height, предотвратяващ сблъсъци, може да се изчисли по формулата: line-height = ascender + descender + 2 px марж. За SF Pro при размер 17 pt това дава line-height от приблизително 22.4 pt (коефициент ~1.32). За Roboto при 16 sp — приблизително 1.35. Ако line-height е по-малко от тази стойност, сблъсъците са гарантирани в текстове, съдържащи букви от групата „g", „j", „p", „q", „y".
// iOS: изчисляване на минимален line-height за предотвратяване на сблъсъци
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
]
)
Особено внимателни трябва да бъдете при работа с декоративни и ръкописни шрифтове — техният descender може да достигне 35–40% от em-размера. Такива шрифтове рядко се използват за основен текст, но могат да се прилагат в заглавия. Дори единично появяване на буква с дълъг descender в заглавие може да причини сблъсък със съседен елемент на интерфейса.
Най-честата грешка е отрязване на descender в бутони и текстови полета. Когато зададем височината на бутон или текстово поле равна на line-height, без да отчетем descender, буквите с descender се отрязват по долния ръб. Това е особено забележимо на системни бутони със заоблени ъгли, където descender може да излезе извън границата на заоблянето.
Според Nielsen Norman Group — Mobile Typography Research (2025), 41% от мобилните приложения имат поне един екран, където текст с descender излиза извън границите на компонента. Това води до намаляване на четливостта с 15% и увеличаване на времето за изпълнение на задачата от потребителя. Редовното тестване с текст, съдържащ буквите „g", „j", „p", „q", „y" помага за откриване на такива проблеми в ранните етапи на разработката.
Често задавани въпроси
Baseline е хоризонталната линия, на която стоят буквите, а descender е част от буквата, намираща се под тази линия. Baseline е константа за реда, descender е свойство на конкретна буква. Не бъркайте тези понятия: baseline се използва за подравняване, докато descender влияе на междуредието и изисква внимание при задаване на височината на контейнера.
Използвайте Paint.getFontMetrics().descent за View-системата или TextLayoutResult в Jetpack Compose. За разлика от iOS, стойността на descent в Android е положителна и показва разстоянието от baseline до долната граница на глифа. За изчисляване на пълната долна граница на реда, добавете descent към Y-координатата на baseline.
Платформите използват различни таблици с метрики от файла на шрифта: iOS — hhea.descent, Android — os/2.sTypoDescender. Ако тези стойности в шрифта се различават, рендерирането ще бъде различно. Винаги проверявайте и двете стойности чрез fontTools. Качествените системни шрифтове (SF Pro, Roboto, Noto) имат съгласувани метрики и за двете платформи.
Минималният line-height = ascender + descender + 2 px марж. За системен шрифт 17 pt на iOS това е приблизително 22.4 pt. На Android за 16 sp Roboto — приблизително 22 sp. Препоръчва се закръгляване до най-близкото цяло число и проверка с тестов низ „gpq" — ако няма сблъсъци, line-height е достатъчен.
Да, но с условия. Шрифтовете с дълъг descender (Playfair Display, декоративни гарнитури) са приемливи за заглавия и акцидентен текст, където line-height може да се увеличи без вреда за дизайна. За основен текст се предпочитат шрифтове с descender 20–25% от em-размера (SF Pro, Roboto, Inter), за да не се губи излишно вертикално пространство.
Заключения
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също