Descender در توسعه موبایل — ماهیت، اهمیت و تأثیر بر چیدمان

نویسنده: IT Sectr منتشر شده: 2026-07-24 زمان مطالعه: 9 دقیقه

Descender — بخشی از حرف کوچک است که زیر خط پایه (baseline) قلم قرار می‌گیرد. در خط لاتین حروف معمول با descender «g», «j», «p», «q», «y» هستند. طول descender عنصر پایینی قلم را تعیین می‌کند و برای محاسبه فاصله خطوط حیاتی است: بدون فضای کافی زیر baseline، حروف دارای descender به خط بعدی برخورد خواهند کرد. طبق Material Design Type Scale Guidelines (2025)، عدم توجه کافی به descender یکی از دلایل اصلی برخورد (collision) خطوط در متن چندخطی در دستگاه‌های موبایل است.

نکات اصلی

  • Descender — عنصر پایینی حرف که در زیر baseline قرار دارد.
  • متریک — descender از طریق UIFont.descender (iOS) و Paint.FontMetrics.descent (Android) قابل دسترسی است.
  • Line-height — descender در محاسبه ارتفاع کامل خط وارد می‌شود و در چیدمان نیاز به توجه دارد.
  • برخورد خطوط — بدون در نظر گرفتن descender، حروف «g», «j», «p», «q», «y» به خط زیرین برخورد می‌کنند.
  • قلم‌های مختلف — طول descender بین فونت‌ها متفاوت است و بر ریتم بصری تأثیر می‌گذارد.

Descender در تایپوگرافی چیست

Descender بخشی از گلیف است که در زیر خط baseline قرار دارد. در حالی که بدنه اصلی حرف روی baseline قرار می‌گیرد، descender فراتر از آن امتداد می‌یابد و سیلوئت مشخصی به قلم می‌بخشد. در قلم‌های لاتین، حروف «g», «j», «p», «q», «y» دارای عناصر پایینی هستند.

عمق descender فاصله از baseline تا مرز پایینی گلیف (descender-line) را توصیف می‌کند. در قلم‌های با کیفیت این فاصله متعادل است: descender خیلی کوتاه باعث می‌شود حروف دارای descender به سختی قابل تشخیص باشند، و descender خیلی بلند فضای خالی اضافی بین خطوط ایجاد می‌کند و تراکم متن را کاهش می‌دهد. فونت‌های مختلف تفاوت‌های قابل توجهی در طول descender نشان می‌دهند.

فونتDescender / em-sizeنمونه حروف با descender
SF Pro~0.22g, p — خروجی متعادل
Roboto~0.24g, p — descender متوسط
Playfair Display~0.30g, q — عناصر تزئینی بلند
Inter~0.26g, p — قابل توجه زیر baseline
Noto Sans~0.20g — descender کوتاه، فشرده

طبق Google Fonts Metrics Guide (2025)، descender زمانی بهینه در نظر گرفته می‌شود که عمق آن ۲۰-۲۵٪ از اندازه کامل em (۱۰۰۰ FUnits) باشد. مقادیر کمتر از ۱۵٪ باعث می‌شود حروف دارای descender به سختی قابل تشخیص باشند و مقادیر بالای ۳۰٪ نیاز به افزایش اجباری line-height برای جلوگیری از برخورد خطوط دارند.

متریک‌های دیجیتال Descender: OpenType و TrueType

در قلم‌های دیجیتال descender به صورت یک مقدار منفی در جداول متریک ذخیره می‌شود. در فرمت OpenType این فیلد hhea.descent (جدول hhea) و sTypoDescender (جدول OS/2) است. هر دو مقدار منفی هستند زیرا از baseline به سمت پایین اندازه‌گیری می‌شوند. برای TrueType از جدول OS/2 با فیلد usWinDescent استفاده می‌شود — مقدار آن مثبت اما نشان‌دهنده همان متریک است.

python
# خواندن 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 نمایش داده می‌شود. تفاوت ۱۰۰ FUnits (حدود ۱.۶ پیکسل در اندازه ۱۶ pt) از نظر بصری قابل توجه است.

طبق Microsoft OpenType Specification v1.9 (2025)، برای رندرینگ صحیح بین پلتفرمی، مقادیر hhea.descent و sTypoDescender باید با دقت ۵۰ FUnits برابر باشند. هنگام انتخاب قلم برای اپلیکیشن موبایل، این موضوع را باید از طریق fontTools یا ابزار مشابه بررسی کرد.

Descender در iOS: UIFont و Core Graphics

در iOS مقدار descender از طریق ویژگی UIFont.descender در دسترس است. این ویژگی یک عدد منفی برمی‌گرداند که فاصله از baseline تا لبه پایینی قلم (شامل descender) را نشان می‌دهد. به عنوان مثال، برای SF Pro در اندازه ۱۷ pt مقدار descender ۴.۲- pt است. هرچه قدر مطلق عدد بیشتر باشد، عناصر پایینی قلم بلندتر هستند.

swift
// دریافت descender در iOS از طریق UIFont
let font = UIFont.systemFont(ofSize: 17)
let descender = font.descender     // فاصله ۴.۲- pt برای SF Pro 17pt
let ascender = font.ascender        // ۱۶.۲ pt
let lineHeight = font.lineHeight    // ۲۰.۴ 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)  // ۴.۲ pt

هنگام استفاده از TextKit (NSTextStorage, NSLayoutManager)، descender به طور خودکار در lineFragmentPadding و lineFragmentRect در نظر گرفته می‌شود. اما در رندرینگ سفارشی از طریق Core Graphics (draw(in:)) باید به طور مستقل مختصات را تنظیم کرد و قدر مطلق descender را به حاشیه پایینی کانتینر اضافه کرد. اگر این کار انجام نشود، حروف دارای descender از مرز رندرینگ خارج شده و بریده می‌شوند.

Descender در Android: Paint و Compose

در Android متریک‌های descender از طریق Paint.FontMetrics.descent در دسترس هستند. برخلاف iOS، مقدار descent مثبت است — این فاصله از baseline تا مرز پایینی متن است. ویژگی FontMetrics.bottom نه تنها descender، بلکه فضای اضافی توصیه شده توسط طراح قلم (leading) را نیز شامل می‌شود. برای در نظر گرفتن دقیق فقط descender از descent استفاده کنید، نه bottom.

kotlin
// دریافت descender در Android از طریق Paint
val paint = Paint().apply {
    textSize = 17 * density
}

val metrics = paint.fontMetrics
val descent = metrics.descent     // ۴.۵ px برای 17sp
val bottom = metrics.bottom       // ۵.۰ 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 نتیجه دقیق‌تری نسبت به تراز بر اساس لبه پایینی می‌دهد.

kotlin
// 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 در متن فعلی. این تضمین می‌کند که در جایگزینی پویای متن، رابط کاربری خراب نشود.

Descender و برخورد خطوط در رابط‌های موبایل

برخورد خطوط (line collision) — وضعیتی است که descender حرف خط بالایی با ascender حرف خط پایینی تلاقی فیزیکی پیدا می‌کند. در رابط‌های موبایل این موضوع به ویژه در عنوان‌های چندخطی، کارت‌های محصولات و بلوک‌های متنی با فاصله خطوط کم قابل توجه است. مشکل با استفاده از قلم‌های دارای descender بلند و line-height کم تشدید می‌شود.

حداقل line-height برای جلوگیری از برخورد را می‌توان با فرمول محاسبه کرد: line-height = ascender + descender + ۲ پیکسل حاشیه. برای SF Pro در اندازه ۱۷ pt این مقدار line-height ۲۲.۴ pt (ضریب ۱.۳۲) می‌دهد. برای Roboto در اندازه ۱۶ sp — حدود ۱.۳۵. اگر line-height کمتر از این مقدار باشد، در متون حاوی حروف گروه «g», «j», «p», «q», «y» برخورد تضمین شده است.

swift
// 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 آنها می‌تواند به ۳۵-۴۰٪ از اندازه برسد. چنین قلم‌هایی به ندرت برای متن اصلی استفاده می‌شوند اما ممکن است در عنوان‌ها به کار روند. حتی یک بار ظاهر شدن حرف با descender بلند در عنوان می‌تواند باعث برخورد با عنصر مجاور رابط کاربری شود.

خطاهای معمول هنگام کار با Descender

رایج‌ترین خطا بریده شدن descender در دکمه‌ها و فیلدهای متنی است. وقتی ارتفاع دکمه یا فیلد متنی را برابر line-height بدون در نظر گرفتن descender تنظیم می‌کنیم، حروف دارای descender در لبه پایینی بریده می‌شوند. این موضوع به ویژه در دکمه‌های سیستمی با گوشه‌های گرد قابل توجه است، جایی که descender ممکن است از مرز گرد شدن خارج شود.

  • دکمه‌های با ارتفاع ثابت — اگر ارتفاع دکمه برابر ceil(line-height) باشد، حروف دارای descender بریده می‌شوند. راه‌حل: ارتفاع دکمه را به اندازه قدر مطلق descender (۴-۵ pt برای قلم سیستمی ۱۷ pt) برای حاشیه بالا و پایین افزایش دهید.
  • TextField بدون در نظر گرفتن descender — UITextField استاندارد و EditText دارای padding هستند که descender را در نظر می‌گیرند، اما پیاده‌سازی‌های سفارشی اغلب آن را فراموش می‌کنند. بررسی کنید که مکان‌نما و بلوک متنی حروف دارای descender را قطع نکنند.
  • ترکیب اندازه‌های مختلف در یک خط — اگر در NSAttributedString یا SpannableString بخش‌هایی با اندازه‌های مختلف وجود داشته باشد، descender قلم بزرگتر ممکن است روی ascender قلم کوچکتر قرار گیرد. از baselineOffset برای جبران استفاده کنید و نتیجه را بررسی کنید.
  • رندرینگ SVG متن — هنگام ترسیم متن در SVG یا روی Canvas (به ویژه در WebView)، descender ممکن است به طور خودکار در نظر گرفته نشود. همیشه viewBox صریح با حاشیه ۱۰-۱۵٪ از اندازه قلم تنظیم کنید.

طبق Nielsen Norman Group — Mobile Typography Research (2025)، ۴۱٪ از اپلیکیشن‌های موبایل حداقل یک صفحه دارند که در آن متن با descender از مرزهای کامپوننت خارج می‌شود. این باعث کاهش ۱۵٪ خوانایی و افزایش زمان انجام وظیفه توسط کاربر می‌شود. آزمایش منظم با متنی حاوی حروف «g», «j», «p», «q», «y» به شناسایی چنین مشکلاتی در مراحل اولیه توسعه کمک می‌کند.

سوالات متداول

تفاوت Descender با baseline چیست؟

Baseline خط افقی است که حروف روی آن قرار می‌گیرند، در حالی که descender بخشی از حرف است که زیر این خط قرار دارد. Baseline برای یک خط ثابت است، descender ویژگی یک حرف خاص است. این مفاهیم را اشتباه نگیرید: baseline برای تراز استفاده می‌شود، در حالی که descender بر فاصله خطوط تأثیر می‌گذارد و هنگام تنظیم ارتفاع کانتینر نیاز به توجه دارد.

چگونه descender قلم را در Android پیدا کنیم؟

از Paint.getFontMetrics().descent برای View-system یا TextLayoutResult در Jetpack Compose استفاده کنید. برخلاف iOS، مقدار descent در Android مثبت است و فاصله از baseline تا مرز پایینی گلیف را نشان می‌دهد. برای محاسبه مرز پایینی کامل خط، descent را به مختصات Y baseline اضافه کنید.

چرا descender یک قلم در iOS و Android متفاوت است؟

پلتفرم‌ها از جداول متریک متفاوت در فایل قلم استفاده می‌کنند: iOS — hhea.descent، Android — os/2.sTypoDescender. اگر این مقادیر در قلم متفاوت باشند، رندرینگ متفاوت خواهد بود. همیشه هر دو مقدار را از طریق fontTools بررسی کنید. قلم‌های سیستمی با کیفیت (SF Pro, Roboto, Noto) متریک‌های هماهنگی برای هر دو پلتفرم دارند.

حداقل line-height برای جلوگیری از برخورد descender چقدر است؟

حداقل line-height = ascender + descender + ۲ پیکسل حاشیه. برای قلم سیستمی ۱۷ pt در iOS این تقریباً ۲۲.۴ pt است. در Android برای ۱۶ sp Roboto — حدود ۲۲ sp. توصیه می‌شود به نزدیکترین عدد صحیح گرد کنید و با رشته تستی «gpq» بررسی کنید — اگر برخوردی وجود نداشته باشد، line-height کافی است.

آیا می‌توان از قلم با descender بسیار بلند در اپلیکیشن موبایل استفاده کرد؟

بله، اما با شرایطی. قلم‌های با descender بلند (Playfair Display، فونت‌های تزئینی) برای عنوان‌ها و متن‌های خاص قابل قبول هستند، جایی که line-height را می‌توان بدون آسیب به طراحی افزایش داد. برای متن اصلی، قلم‌هایی با descender ۲۰-۲۵٪ از اندازه em (SF Pro, Roboto, Inter) ترجیح داده می‌شوند تا فضای عمودی اضافی هدر نرود.

نتیجه‌گیری

  • Descender — عنصر پایینی حرف که در زیر baseline قرار دارد، در حروف «g», «j», «p», «q», «y» (لاتین) وجود دارد.
  • متریک‌های دیجیتال — hhea.descent (iOS) و os/2.sTypoDescender (Android) در فرمت‌های OpenType/TrueType.
  • API iOS — UIFont.descender (مقدار منفی) برای UIKit و CTFontGetDescent برای Core Text.
  • API Android — Paint.FontMetrics.descent (مثبت) و TextLayoutResult در Compose.
  • برخورد خطوط — زمانی رخ می‌دهد که line-height کمتر از ascender + descender + ۲ پیکسل حاشیه باشد؛ با رشته «gpq» بررسی می‌شود.
  • بریده شدن در کامپوننت‌ها — دکمه‌ها، فیلدهای متنی و کانتینرهای سفارشی باید padding برابر قدر مطلق descender داشته باشند.
  • تفاوت پلتفرم‌ها — iOS و Android از جداول متریک متفاوت استفاده می‌کنند که نیاز به بررسی قلم در هر دو پلتفرم دارد.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید