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 ที่ไม่เพียงพอเป็นหนึ่งในสาเหตุหลักของการชนกันของบรรทัดในข้อความหลายบรรทัดบนอุปกรณ์เคลื่อนที่

ประเด็นสำคัญ

  • Descender — องค์ประกอบส่วนห้อยลงด้านล่างของตัวอักษร อยู่ต่ำกว่า baseline
  • เมตริก — descender สามารถเข้าถึงได้ผ่าน UIFont.descender (iOS) และ Paint.FontMetrics.descent (Android)
  • Line-height — descender ถูกรวมในการคำนวณความสูงเต็มของบรรทัดและต้องพิจารณาในการจัดวาง
  • การชนกันของบรรทัด — หากไม่พิจารณา descender ตัวอักษรที่มี descender จะชนกับบรรทัดด้านล่าง
  • แบบอักษรที่แตกต่างกัน — ความยาวของ descender แตกต่างกันระหว่างรูปแบบตัวอักษร ส่งผลต่อจังหวะการมองเห็น

Descender ในวิชาการพิมพ์คืออะไร

Descender คือส่วนของกลิฟที่อยู่ต่ำกว่าเส้นฐาน ขณะที่ตัวหลักของตัวอักษรอยู่บน baseline descender ยื่นออกไปเกิน สร้างรูปทรงลักษณะเฉพาะของแบบอักษร ในอักษรละติน ตัวอักษรที่มี descender ได้แก่ “g”, “j”, “p”, “q”, “y” — องค์ประกอบด้านล่างของพวกมันตกลงไปใต้บรรทัด

ความลึกของ descender อธิบายระยะทางจาก baseline ถึงขอบล่างของกลิฟ (descender-line) ในแบบอักษรที่มีคุณภาพ ระยะนี้สมดุล: descender ที่สั้นเกินไปทำให้ตัวอักษรที่มี descender แยกแยะได้ยาก ในขณะที่ descender ที่ยาวเกินไปสร้างพื้นที่ว่างมากเกินไประหว่างบรรทัดและลดความหนาแน่นของข้อความ รูปแบบตัวอักษรที่แตกต่างกันแสดง ความแตกต่างอย่างมีนัยสำคัญ ในความยาวของ descender

รูปแบบตัวอักษรDescender / em-sizeตัวอย่างตัวอักษรที่มี descender
SF Pro~0.22g, j, p, q, y — การยื่นที่สมดุล
Roboto~0.24g, j, p — descender ปานกลาง
Playfair Display~0.30g, j, p, q — องค์ประกอบตกแต่งยาว
Inter~0.26g, j, p — อยู่ใต้ baseline อย่างเห็นได้ชัด
Noto Sans~0.20g, j — descender สั้น กะทัดรัด

ตาม Google Fonts Metrics Guide (2025) ถือว่า descender เหมาะสมที่สุดเมื่อความลึกของมันคือ 20–25% ของขนาด em เต็ม (1000 FUnits) ค่าที่ต่ำกว่า 15% ทำให้ตัวอักษรที่มี descender แยกแยะได้ยาก ในขณะที่ค่าที่สูงกว่า 30% ต้องเพิ่ม 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 ความแตกต่าง 100 FUnits (ประมาณ 1.6 px ที่ขนาดแบบอักษร 16 pt) สังเกตเห็นได้ทางสายตาแล้ว

ตาม Microsoft OpenType Specification v1.9 (2025) เพื่อการเรนเดอร์ข้ามแพลตฟอร์มที่ถูกต้อง ค่า hhea.descent และ sTypoDescender ควรเท่ากันด้วยความแม่นยำ 50 FUnits เมื่อเลือกแบบอักษรสำหรับแอปพลิเคชันมือถือ ควรตรวจสอบผ่าน fontTools หรือยูทิลิตี้ที่คล้ายกัน

Descender ใน iOS: UIFont และ Core Graphics

ใน iOS ค่า descender สามารถเข้าถึงได้ผ่านคุณสมบัติ UIFont.descender คุณสมบัตินี้ส่งคืนตัวเลขติดลบที่ระบุระยะทางจาก baseline ถึงขอบล่างของแบบอักษร (รวมถึง descender) ตัวอย่างเช่น สำหรับ SF Pro ที่ 17 pt ค่า descender ≈ -4.2 pt ยิ่งค่าสัมบูรณ์มากเท่าใด ส่วนยื่นด้านล่างของแบบอักษรก็ยิ่งยาวมากขึ้นเท่านั้น

swift
// การรับ 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: การรับ bounding box พร้อม 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 จะเกินขอบเขตการเรนเดอร์และถูกตัด

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     // ~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 ให้ผลลัพธ์ที่แม่นยำกว่าการจัดตำแหน่งตามขอบล่าง

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 และการชนกันของบรรทัดในอินเทอร์เฟซมือถือ

การชนกันของบรรทัดคือสถานการณ์ที่ descender ของตัวอักษรในบรรทัดบนตัดกับ ascender ของตัวอักษรในบรรทัดล่างทางกายภาพ ในอินเทอร์เฟซมือถือ เห็นได้ชัดเจนเป็นพิเศษในหัวข้อหลายบรรทัด การ์ดสินค้า และบล็อกข้อความที่มีระยะห่างระหว่างบรรทัดน้อย ปัญหารุนแรงขึ้นเมื่อใช้แบบอักษรที่มี descender ยาวและ line-height เล็ก

line-height ขั้นต่ำที่ป้องกันการชนกันสามารถคำนวณได้ด้วยสูตร: line-height = ascender + descender + 2 px ระยะเผื่อ สำหรับ SF Pro ที่ 17 pt ให้ line-height ≈ 16.2 + 4.2 + 2 = 22.4 pt (ค่าสัมประสิทธิ์ ~1.32) สำหรับ Roboto ที่ 16 sp ≈ 1.35 หาก line-height น้อยกว่าค่านี้ การชนกันจะเกิดขึ้นแน่นอนในข้อความที่มีตัวอักษรที่มี descender

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 ของพวกมันสามารถสูงถึง 35–40% ของขนาด em แบบอักษรดังกล่าวไม่ค่อยใช้สำหรับข้อความเนื้อหา แต่อาจใช้ในหัวข้อ แม้การปรากฏเพียงครั้งเดียวของตัวอักษรที่มี descender ยาวในหัวข้อก็สามารถทำให้เกิดการชนกับองค์ประกอบอินเทอร์เฟซที่อยู่ใกล้เคียง

ข้อผิดพลาดทั่วไปเมื่อทำงานกับ Descender

ข้อผิดพลาดที่พบบ่อยที่สุดคือ การตัด descender ในปุ่มและฟิลด์ข้อความ เมื่อเรากำหนดความสูงของปุ่มหรือฟิลด์ข้อความเท่ากับ line-height โดยไม่พิจารณา descender ตัวอักษรที่มี descender จะถูกตัดที่ขอบล่าง โดยเฉพาะอย่างยิ่งเห็นได้ชัดในปุ่มระบบที่มีมุมโค้งมน ซึ่ง descender อาจเกินขอบเขตรัศมีมุม

  • ปุ่มความสูงคงที่ — หากความสูงของปุ่มเท่ากับ ceil(line-height) ตัวอักษรที่มี descender จะถูกตัด วิธีแก้ไข: เพิ่มความสูงของปุ่มด้วยค่าสัมบูรณ์ของ descender (4–5 pt สำหรับแบบอักษรระบบ 17 pt) สำหรับ padding บนและล่าง
  • TextField โดยไม่พิจารณา descender — UITextField และ EditText มาตรฐานมี padding ที่พิจารณา descender แต่การนำไปใช้แบบกำหนดเองมักลืมมัน ตรวจสอบว่าเคอร์เซอร์และบล็อกข้อความไม่ตัดตัวอักษรที่มี descender
  • การผสมขนาดแบบอักษรในบรรทัดเดียว — หาก NSAttributedString หรือ SpannableString มีเซ็กเมนต์ที่มีขนาดแบบอักษรต่างกัน descender ของแบบอักษรที่ใหญ่กว่าอาจทับซ้อนกับ ascender ของแบบอักษรที่เล็กกว่า ใช้ baselineOffset เพื่อชดเชยและตรวจสอบผลลัพธ์
  • การเรนเดอร์ข้อความ SVG — เมื่อเรนเดอร์ข้อความใน SVG หรือบน Canvas (โดยเฉพาะใน web views) descender อาจไม่ถูกรวมโดยอัตโนมัติ ให้ระบุ viewBox ที่ชัดเจนพร้อมระยะเผื่อ 10–15% ของขนาดแบบอักษรเสมอ

ตาม Nielsen Norman Group — Mobile Typography Research (2025) 41% ของแอปพลิเคชันมือถือมีหน้าจออย่างน้อยหนึ่งหน้าที่ข้อความที่มี descender เกินขอบเขตของคอมโพเนนต์ ส่งผลให้ความสามารถในการอ่านลดลง 15% และเวลาในการทำงานของผู้ใช้เพิ่มขึ้น การทดสอบเป็นประจำกับข้อความที่มีตัวอักษรที่มี descender ช่วยระบุปัญหาดังกล่าวในระยะเริ่มต้นของการพัฒนา

คำถามที่พบบ่อย

Descender แตกต่างจาก baseline อย่างไร?

Baseline คือเส้นแนวนอนที่ตัวอักษรตั้งอยู่ ในขณะที่ descender คือส่วนของตัวอักษรที่อยู่ใต้เส้นนี้ Baseline เป็นค่าคงที่สำหรับบรรทัด descender เป็นคุณสมบัติของตัวอักษรเฉพาะ อย่าสับสนแนวคิดเหล่านี้: baseline ใช้สำหรับการจัดตำแหน่ง ในขณะที่ descender ส่งผลต่อระยะห่างระหว่างบรรทัดและต้องพิจารณาเมื่อกำหนดความสูงของคอนเทนเนอร์

วิธีหา descender ของแบบอักษรบน Android

ใช้ Paint.getFontMetrics().descent สำหรับระบบ View หรือ 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 + 2 px ระยะเผื่อ สำหรับแบบอักษรระบบ 17 pt บน iOS ประมาณ 22.4 pt บน Android สำหรับ Roboto 16 sp ประมาณ 22 sp แนะนำให้ปัดเศษเป็นจำนวนเต็มที่ใกล้ที่สุดและทดสอบด้วยสตริงทดสอบของตัวอักษรที่มี descender — หากไม่มีการชนกัน line-height ก็เพียงพอ

สามารถใช้แบบอักษรที่มี descender ยาวมากในแอปพลิเคชันมือถือได้หรือไม่?

ได้ แต่มี ข้อจำกัด แบบอักษรที่มี descender ยาว (Playfair Display, รูปแบบตัวอักษรตกแต่ง) ยอมรับได้สำหรับหัวข้อและข้อความเน้นที่สามารถเพิ่ม line-height ได้โดยไม่กระทบต่อการออกแบบ สำหรับข้อความเนื้อหา แบบอักษรที่มี descender 20–25% ของขนาด em (SF Pro, Roboto, Inter) เป็นที่นิยมเพื่อไม่ให้เสียพื้นที่แนวตั้ง

สรุป

  • Descender — องค์ประกอบส่วนห้อยลงด้านล่างของตัวอักษร อยู่ใต้ baseline มีในตัวอักษรละติน “g”, “j”, “p”, “q”, “y”
  • เมตริกดิจิทัล — hhea.descent (iOS) และ os/2.sTypoDescender (Android) ในรูปแบบ OpenType/TrueType
  • iOS API — UIFont.descender (ค่าลบ) สำหรับ UIKit และ CTFontGetDescent สำหรับ Core Text
  • Android API — Paint.FontMetrics.descent (ค่าบวก) และ TextLayoutResult ใน Compose
  • การชนกันของบรรทัด — เกิดขึ้นเมื่อ line-height < ascender + descender + 2 px ระยะเผื่อ; ตรวจสอบด้วยสตริงทดสอบของตัวอักษรที่มี descender
  • การตัดในคอมโพเนนต์ — ปุ่ม ฟิลด์ข้อความ และคอนเทนเนอร์แบบกำหนดเองควรมี padding เท่ากับค่าสัมบูรณ์ของ descender
  • ความแตกต่างของแพลตฟอร์ม — iOS และ Android ใช้ตารางเมตริกที่แตกต่างกัน ซึ่งต้องตรวจสอบแบบอักษรบนทั้งสองแพลตฟอร์ม

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม