Descender là phần của chữ in thường kéo dài xuống dưới đường cơ sở (baseline) của phông chữ. Trong bảng chữ Latin, các chữ điển hình có descender là “g”, “j”, “p”, “q”, “y”. Chiều dài của descender xác định phần kéo xuống dưới của phông và cực kỳ quan trọng để tính khoảng cách dòng: nếu không có đủ không gian dưới baseline, các chữ có descender sẽ va chạm với dòng tiếp theo. Theo Material Design Type Scale Guidelines (2025), việc không xem xét đầy đủ descender là một trong những nguyên nhân chính gây va chạm dòng trong văn bản nhiều dòng trên thiết bị di động.
Điểm chính
Descender là phần của glyph nằm dưới đường cơ sở. Trong khi phần thân chính của chữ nằm trên baseline, descender kéo dài vượt ra ngoài, tạo nên hình dáng đặc trưng của phông. Trong bảng chữ Latin, các chữ có descender bao gồm “g”, “j”, “p”, “q”, “y” — phần dưới của chúng rơi xuống dưới dòng.
Độ sâu của descender mô tả khoảng cách từ baseline đến cạnh dưới của glyph (descender-line). Trong các phông chất lượng cao, khoảng cách này được cân bằng: descender quá ngắn làm cho các chữ có descender khó nhận biết, trong khi descender quá dài tạo ra khoảng trống quá mức giữa các dòng và làm giảm mật độ văn bản. Các kiểu chữ khác nhau thể hiện sự khác biệt đáng kể về chiều dài descender.
| Kiểu chữ | Descender / em-size | Ví dụ chữ có descender |
|---|---|---|
| SF Pro | ~0.22 | g, j, p, q, y — kéo dài cân bằng |
| Roboto | ~0.24 | g, j, p — descender vừa phải |
| Playfair Display | ~0.30 | g, j, p, q — yếu tố trang trí dài |
| Inter | ~0.26 | g, j, p — rõ rệt dưới baseline |
| Noto Sans | ~0.20 | g, j — descender ngắn, gọn nhẹ |
Theo Google Fonts Metrics Guide (2025), descender được coi là tối ưu khi độ sâu của nó là 20–25% kích thước em đầy đủ (1000 FUnits). Giá trị dưới 15% làm cho các chữ có descender khó phân biệt, trong khi giá trị trên 30% yêu cầu tăng line-height bắt buộc để ngăn chặn va chạm dòng.
Trong phông kỹ thuật số, descender được lưu trữ dưới dạng giá trị âm trong các bảng chỉ số. Trong định dạng OpenType, đây là trường hhea.descent (bảng hhea) và sTypoDescender (bảng OS/2). Cả hai giá trị đều âm vì chúng được đo từ baseline xuống dưới. Đối với TrueType, bảng OS/2 được sử dụng với trường usWinDescent — giá trị của nó dương nhưng biểu thị cùng một chỉ số.
# Đọc descender từ phông qua 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)
# Chuyển đổi sang pixel cho cỡ chữ 16pt
px_per_em = 16
descent_px = abs(descent_hhea) * px_per_em / 1000 # 8 px
Sự khác biệt quan trọng giữa các nền tảng: iOS sử dụng hhea.descent để hiển thị, trong khi Android sử dụng sTypoDescender từ OS/2. Nếu các giá trị này khác nhau (điều xảy ra trong các phông được cấu hình kém), cùng một văn bản sẽ hiển thị với khoảng cách dòng khác nhau trên iOS và Android. Sự khác biệt 100 FUnits (khoảng 1.6 px ở cỡ chữ 16 pt) đã có thể nhận thấy bằng mắt thường.
Theo Microsoft OpenType Specification v1.9 (2025), để hiển thị đa nền tảng chính xác, các giá trị hhea.descent và sTypoDescender phải bằng nhau trong phạm vi 50 FUnits. Khi chọn phông cho ứng dụng di động, điều này cần được kiểm tra qua fontTools hoặc công cụ tương tự.
Trên iOS, giá trị descender có sẵn qua thuộc tính UIFont.descender. Thuộc tính này trả về một số âm cho biết khoảng cách từ baseline đến cạnh dưới của phông (bao gồm cả descender). Ví dụ, đối với SF Pro ở cỡ 17 pt, giá trị descender là khoảng -4.2 pt. Giá trị tuyệt đối càng lớn, phần kéo xuống dưới của phông càng dài.
// Lấy descender trên iOS qua UIFont
let font = UIFont.systemFont(ofSize: 17)
let descender = font.descender // ~ -4.2 pt cho SF Pro 17pt
let ascender = font.ascender // ~ 16.2 pt
let lineHeight = font.lineHeight // ~ 20.4 pt
// Hiển thị tùy chỉnh với độ lệch descender
let attrString = NSAttributedString(
string: "Sample text with letter p and y",
attributes: [.font: font]
)
// Core Text: lấy bounding box với descender
let ctFont = CTFontCreateWithName(
"SF Pro Text" as CFString, 17, nil
)
let descent = CTFontGetDescent(ctFont) // ~4.2 pt
Khi sử dụng TextKit (NSTextStorage, NSLayoutManager), descender được tự động tính đến trong lineFragmentPadding và lineFragmentRect. Tuy nhiên, khi hiển thị tùy chỉnh qua Core Graphics (draw(in:)), bạn phải điều chỉnh tọa độ thủ công bằng cách thêm giá trị tuyệt đối của descender vào lề dưới của container. Nếu không làm điều này, các chữ có descender sẽ vượt quá giới hạn hiển thị và bị cắt.
Trên Android, chỉ số descender có sẵn qua Paint.FontMetrics.descent. Khác với iOS, giá trị descent là dương — nó biểu thị khoảng cách từ baseline đến cạnh dưới của văn bản. Thuộc tính FontMetrics.bottom bao gồm không chỉ descender mà còn cả không gian bổ sung do nhà thiết kế phông khuyến nghị (leading). Để tính chính xác chỉ descender, hãy sử dụng descent thay vì bottom.
// Lấy descender trên Android qua Paint
val paint = Paint().apply {
textSize = 17 * density
}
val metrics = paint.fontMetrics
val descent = metrics.descent // ~4.5 px cho 17sp
val bottom = metrics.bottom // ~5.0 px với leading
// Hiển thị tùy chỉnh với độ lệch descender
val baseline = y
canvas.drawText("Mẫu: gpq", x, baseline, paint)
// Giới hạn dưới với descender
val bottomBound = baseline + descent // giới hạn dưới chính xác
Trong Jetpack Compose, descender có thể được lấy qua TextLayoutResult. Phương thức getLineBottom trả về tọa độ Y của cạnh dưới dòng, đã bao gồm descender. Khi bố trí tùy chỉnh các chuỗi có kích thước phông khác nhau (ví dụ, giá đã giảm và giá đầy đủ), căn chỉnh theo baseline có tính đến descender cho kết quả chính xác hơn so với căn chỉnh theo cạnh dưới.
// Compose: kiểm tra giới hạn dưới của văn bản
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)
// Kiểm tra descender không vượt quá giới hạn container
}
}
)
Theo Google Material Design — Typography Implementation (2025), để ngăn chặn việc cắt descender trong các container có chiều cao cố định, bạn phải thêm padding dọc ít nhất bằng descent của phông, bất kể văn bản hiện tại có chứa chữ có descender hay không. Điều này đảm bảo giao diện sẽ không bị hỏng khi văn bản được thay thế động.
Va chạm dòng là tình huống mà descender của một chữ ở dòng trên giao cắt vật lý với ascender của một chữ ở dòng dưới. Trong giao diện di động, điều này đặc biệt rõ ràng trong các tiêu đề nhiều dòng, thẻ sản phẩm và khối văn bản có khoảng cách dòng nhỏ. Vấn đề trở nên trầm trọng hơn khi sử dụng các phông có descender dài và line-height nhỏ.
Line-height tối thiểu ngăn chặn va chạm có thể được tính bằng công thức: line-height = ascender + descender + 2 px lề. Đối với SF Pro ở cỡ 17 pt, điều này cho line-height khoảng 16.2 + 4.2 + 2 = 22.4 pt (hệ số ~1.32). Đối với Roboto ở 16 sp, khoảng 1.35. Nếu line-height nhỏ hơn giá trị này, va chạm chắc chắn xảy ra trong các văn bản có chứa chữ có descender.
// iOS: tính line-height tối thiểu để ngăn va chạm
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
]
)
Cần đặc biệt thận trọng khi làm việc với các phông trang trí và phông viết tay — descender của chúng có thể đạt 35–40% kích thước em. Những phông này hiếm khi được sử dụng cho văn bản chính nhưng có thể được áp dụng trong tiêu đề. Chỉ một lần xuất hiện của một chữ có descender dài trong tiêu đề cũng có thể gây ra va chạm với phần tử giao diện lân cận.
Lỗi phổ biến nhất là cắt descender trong các nút và trường văn bản. Khi chúng ta đặt chiều cao của nút hoặc trường văn bản bằng line-height mà không tính đến descender, các chữ có descender bị cắt ở cạnh dưới. Điều này đặc biệt rõ ràng trên các nút hệ thống có góc bo tròn, nơi descender có thể vượt quá giới hạn bán kính góc.
Theo Nielsen Norman Group — Mobile Typography Research (2025), 41% ứng dụng di động có ít nhất một màn hình mà văn bản có descender vượt quá giới hạn thành phần. Điều này dẫn đến giảm 15% khả năng đọc và tăng thời gian hoàn thành tác vụ của người dùng. Kiểm tra thường xuyên với văn bản có chứa chữ có descender giúp phát hiện những vấn đề này ở giai đoạn đầu của quá trình phát triển.
Câu hỏi thường gặp
Baseline là đường nằm ngang mà các chữ nằm trên, trong khi descender là phần chữ nằm dưới đường này. Baseline là hằng số cho dòng, descender là thuộc tính của một chữ cụ thể. Đừng nhầm lẫn các khái niệm này: baseline được sử dụng để căn chỉnh, trong khi descender ảnh hưởng đến khoảng cách dòng và cần được xem xét khi đặt chiều cao container.
Sử dụng Paint.getFontMetrics().descent cho hệ thống View hoặc TextLayoutResult trong Jetpack Compose. Khác với iOS, giá trị descent trên Android là dương và cho biết khoảng cách từ baseline đến cạnh dưới của glyph. Để tính toán giới hạn dưới đầy đủ của dòng, thêm descent vào tọa độ Y của baseline.
Các nền tảng sử dụng bảng chỉ số khác nhau từ tệp phông: iOS sử dụng hhea.descent, Android sử dụng os/2.sTypoDescender. Nếu các giá trị này khác nhau trong phông, kết quả hiển thị sẽ khác nhau. Luôn kiểm tra cả hai giá trị qua fontTools. Các phông hệ thống chất lượng cao (SF Pro, Roboto, Noto) có chỉ số nhất quán cho cả hai nền tảng.
Tối thiểu line-height = ascender + descender + 2 px lề. Đối với phông hệ thống 17 pt trên iOS, đây là khoảng 22.4 pt. Trên Android cho Roboto 16 sp — khoảng 22 sp. Nên làm tròn đến số nguyên gần nhất và kiểm tra với chuỗi kiểm tra các chữ có descender — nếu không có va chạm, line-height là đủ.
Có, nhưng có hạn chế. Các phông có descender dài (Playfair Display, các kiểu chữ trang trí) được chấp nhận cho tiêu đề và văn bản nhấn mạnh nơi có thể tăng line-height mà không ảnh hưởng đến thiết kế. Đối với văn bản chính, các phông có descender từ 20–25% kích thước em (SF Pro, Roboto, Inter) được ưu tiên để không lãng phí không gian dọc.
Tóm tắt
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm