Dynamic Type: ключові поняття, текстові стилі та як це працює в iOS

Автор: IT Sectr Опубліковано: 2026-05-16 Час читання: 9 хв

Dynamic Type — вбудована функція iOS, яка автоматично змінює розмір шрифту в додатку відповідно до системних налаштувань користувача. Користувач задає бажаний розмір тексту в Налаштуваннях → Екран та яскравість → Розмір тексту, і всі додатки, що підтримують Dynamic Type, адаптуються без додаткових дій. Згідно з Apple Human Interface Guidelines, 2024, підтримка Dynamic Type — обов’язкова вимога для публікації в App Store, оскільки це базовий елемент accessibility на платформі iOS.

Головне

  • Dynamic Type — механізм iOS для автоматичного масштабування тексту під системні налаштування розміру шрифту
  • Підтримка забезпечується через текстові стилі (UIFont.TextStyle) — body, headline, caption, title та інші
  • Система підтримує 11 рівнів масштабування від XSmall до AccessibilityXXXL
  • Для кастомних шрифтів використовується метод UIFontMetrics, що масштабує будь-який шрифт відносно стилю body
  • Верстка повинна бути адаптивною — UIStackView, Auto Layout та динамічна висота комірок обов’язкові

Що таке Dynamic Type в iOS

Dynamic Type — технологія iOS, яка з’явилася в iOS 7 і дозволяє тексту в додатку автоматично підлаштовуватися під системні налаштування розміру шрифту. Користувач може збільшити або зменшити шрифт у всіх додатках одразу — без необхідності змінювати налаштування всередині кожного додатку окремо.

Згідно з Apple WWDC 2023, «Make Your App Visually Accessible», понад 40% користувачів iOS змінюють розмір шрифту від стандартного. Для вікової групи 65+ цей показник досягає 70%. Dynamic Type — обов’язкова вимога для сертифікації accessibility App Store. Відсутність підтримки — причина відхилення додатку на ревю.

Принцип роботи: додаток використовує UIFont.preferredFont(forTextStyle:) замість UIFont(name:size:). iOS автоматично повертає шрифт, масштабований під поточне системне налаштування. При зміні розміру в налаштуваннях iOS генерує сповіщення UIContentSizeCategory.didChangeNotification — додаток повинен перерахувати верстку.

Історія розвитку Dynamic Type

Dynamic Type з’явився в iOS 7 разом з «плоским» дизайном. iOS 10 додав підтримку кастомних шрифтів через UIFontMetrics. iOS 11 ввів accessibility-рівні (до AccessibilityXXXL). iOS 15 додав Dynamic Type в SwiftUI з автоматичною підтримкою. З кожним релізом Apple посилює вимоги: починаючи з iOS 17, додатки без підтримки Dynamic Type отримують попередження при завантаженні в App Store Connect.

Текстові стилі UIFont.TextStyle

iOS надає 8 текстових стилів, кожен з попередньо визначеним розміром та накресленням для стандартного налаштування:

СтильКонстантаРозмір (L)Призначення
Large Title.largeTitle34pxГоловний заголовок екрану
Title 1.title128pxЗаголовок секції
Title 2.title222pxПідзаголовок
Title 3.title320pxЗаголовок картки
Headline.headline17px (напівжирний)Напівжирний для акцентів
Body.body17pxОсновний текст
Callout.callout16pxДопоміжний текст
Caption 1.caption112pxПідпис під зображенням
Caption 2.caption211pxДрібний підпис
Footnote.footnote13pxВиноска, примітка

Використання правильного стилю — не просто «зовнішній вигляд». UIFont.TextStyle.body в режимі AccessibilityXXXL може досягати 53px. Якщо додаток використовує фіксований шрифт 17px для body, текст стане нечитабним для користувачів, які збільшили шрифт.

Візуальна ієрархія через стилі

Dynamic Type не лише масштабує — він зберігає візуальну ієрархію. Large Title завжди більший за Title 1, який більший за Body, незалежно від рівня масштабування. Коефіцієнти масштабування різні: заголовки масштабуються активніше, ніж основний текст, щоб ієрархія зберігалася навіть на accessibility-рівнях.

Рівні масштабування

iOS підтримує 11 рівнів масштабування тексту, розділених на дві категорії:

  • Стандартні розміри (5 рівнів): XS, S, M, L (за замовчуванням), XL
  • Accessibility-розміри (6 рівнів): accessibilityXL, accessibilityXXL, accessibilityXXXL, accessibilityXXXXL, accessibilityXXXXXL, accessibilityXXXXXXL

Різниця між XS та AccessibilityXXXL для стилю body становить від 14px до 53px — майже 4×. Верстка, розрахована на 17px, повністю ламається на 53px: текст виходить за межі, кнопки перекриваються, комірки наїзжджають одна на одну.

Перевірити поточну категорію в коді:

swift
let category = UIApplication.shared.preferredContentSizeCategory
// .extraSmall, .small, .medium, .large, .extraLarge ...
if category.isAccessibilityCategory {
    // Увімкнути альтернативну верстку
}

traitCollection та розмір тексту

Категорія розміру тексту доступна через traitCollection.uiContentSizeCategory. При зміні системного налаштування iOS викликає traitCollectionDidChange на всіх UIView. У цьому методі потрібно оновити шрифти та перерахувати верстку. SwiftUI робить це автоматично — UIKit потребує ручної підписки.

Для UICollectionView використовуйте UICollectionViewCompositionalLayout — він автоматично підбудовує кількість колонок під ширину екрану та розмір тексту. На accessibility-рівнях перемикайтеся з двоколонної на одноколонну верстку, щоб текст не обрізався та елементи не наїзджали один на одного. Використовуйте умовну верстку: для regular width — дві колонки, для compact або accessibility — одна колонка.

Реалізація в UIKit

Базова реалізація в UIKit — UIFont.preferredFont(forTextStyle:). Цей метод повертає шрифт, масштабований під поточне системне налаштування:

swift
titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
bodyLabel.font = UIFont.preferredFont(forTextStyle: .body)

Для кастомних шрифтів використовуйте UIFontMetrics:

swift
let customFont = UIFont(name: "Montserrat-Regular", size: 16)!
titleLabel.font = UIFontMetrics(forTextStyle: .body)
    .scaledFont(for: customFont)

// Відстеження змін розміру
NotificationCenter.default.addObserver(
    self,
    selector: #selector(preferredContentSizeChanged),
    name: UIContentSizeCategory.didChangeNotification,
    object: nil
)

Для UILabel в Interface Builder достатьо встановити шрифт як текстовий стиль (Text Style) і увімкнути «Automatically Adjusts Font». Для кастомних шрифтів IB не підтримує UIFontMetrics — тільки через код.

UIFontMetrics та scaling curve

UIFontMetrics використовує ту же scaling curve, що й preferredFont. Ви можете задати як fromTextStyle: .body, .headline тощо. Кожен стиль має свій коефіцієнт масштабування. Body масштабується помірно, Large Title — активно. Якщо ваш кастомний шрифт використовується для основного тексту, використовуйте .body.

Dynamic Type в SwiftUI

В SwiftUI підтримка Dynamic Type вбудована за замовчуванням. Усі системні модифікатори (.font(.body), .font(.title)) автоматично масштабуються. Розробнику не потрібно викликати UIFont.preferredFont.

Приклад:

swift
Text("Основний текст")
    .font(.body)
    .lineLimit(nil)
    .minimumScaleFactor(0.5)

Для кастомних масштабів використовуйте DynamicTypeSize:

swift
@Environment(\.dynamicTypeSize) var dynamicTypeSize

var body: some View {
    Text("Адаптивний текст")
        .font(.body)
        .padding(dynamicTypeSize <= .large ? 8 : 16)
}

SwiftUI автоматично оновлює подання при зміні системного розміру тексту — ніяких додаткових підписок на сповіщення.

Обмеження Dynamic Type в SwiftUI

Модифікатор .font(.body) працює лише для системного шрифту. Для кастомних шрифтів в SwiftUI використовуйте Font.custom з UIFontMetrics під капотом. Починаючи з iOS 16, SwiftUI підтримує DynamicTypeSize в @Environment, що дозволяє адаптувати відступи та компонування.

Адаптація верстки під великі шрифти

Auto Layout — обов’язкова умова підтримки Dynamic Type. Фіксовані ширини та висоти (>=, <=) ламаються при accessibility-розмірах. Використовуйте intrinsicContentSize для UILabel — він автоматично обчислює висоту під поточний розмір шрифту.

Правила адаптивної верстки:

  • UIStackView з distribution = fill та spacing >= 8 — елементи будуть переноситися на наступний рядок
  • UITableViewCell з automaticDimension — висота комірки підбудовується під контент
  • numberOfLines = 0 на UILabel — текст не обрізається, а переноситься
  • Кнопки з edgeInsets — додайте відступи на accessibility-рівнях через traitCollection.preferredContentSizeCategory

Для довгих текстів (наприклад, статті, умови використання) встановіть minimumScaleFactor на UILabel — це зменшує текст в останню чергу, коли Auto Layout не може вмістити контент. Значення 0.5 означає, що шрифт може зменшитися до 50% від прийнятого розміру.

Приклад підбудови відступів під категорію розміру:

swift
let isAccessibility = traitCollection
    .preferredContentSizeCategory.isAccessibilityCategory
stackView.spacing = isAccessibility ? 16 : 8
button.contentEdgeInsets = isAccessibility
    ? UIEdgeInsets(top: 16, left: 24, bottom: 16, right: 24)
    : UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)

Типові проблеми верстки на accessibility-рівнях

Обрізання тексту — UILabel з numberOfLines = 1 та фіксованою шириною обрізає текст на AccessibilityXL. Рішення: numberOfLines = 0 та trailing constraint. Перекриття елементів — кнопки з фіксованою висотою наїзджають одна на одну. Рішення: UIStackView з automatic spacing. Вихід за межі екрану — ScrollView обов’язковий для accessibility-рівнів.

Тестування Dynamic Type

Симулятор Xcode дозволяє змінити розмір тексту: в меню симулятора Settings → Accessibility → Display & Text Size → Larger Text. Перемикайте між усіма 11 рівнями та перевіряйте, що текст не обрізається, кнопки доступні, верстка не ламається.

Для автоматизованого тестування використовуйте налаштування contentSizeCategory в XCUIApplication:

swift
func testAccessibilitySizes() {
    let app = XCUIApplication()
    app.launchArguments += [
        "-UIPreferredContentSizeCategoryName",
        "UICTContentSizeCategoryAccessibilityXXXL"
    ]
    app.launch()
    app.scrollViews.buttons["Надіслати"].tap()
    XCTAssertTrue(app.staticTexts["Форму надіслано"]
        .waitForExistence(timeout: 5))
}

XCUITest з різними launchArguments дозволяє перевірити всі рівні масштабування в CI. Не забудьте перевірити accessibility-категорії окремо — вони найчастіше ламають верстку. За даними Apple, 70% багів Dynamic Type виявляються саме на accessibility-рівнях, оскільки розробники тестують лише стандартні розміри.

Accessibility Inspector: перевірка Dynamic Type

Xcode Accessibility Inspector показує, які шрифти використовує вибраний елемент — фіксований або масштабований. Якщо елемент не реагує на зміну розміру тексту в симуляторі, значить використовується фіксований шрифт. Замініть його на UIFont.preferredFont або UIFontMetrics.

Часто запитувані питання

Що таке Dynamic Type в iOS простими словами?

Це автоматичне масштабування тексту в додатку під системні налаштування розміру. Користувач змінює розмір в Налаштуваннях — всі підтримувані додатки адаптуються без участі розробника.

Dynamic Type працює тільки з системними шрифтами?

Ні. Для кастомних шрифтів використовуйте UIFontMetrics(scaledFont:). Метод масштабує будь-який шрифт відносно заданого текстового стилю, зберігаючи пропорції.

Скільки рівнів масштабування підтримує iOS?

11 рівнів: 5 стандартних (XS, S, M, L, XL) та 6 accessibility-рівнів (від AccessibilityXL до AccessibilityXXXXXL). Розмір шрифту body може варіюватися від 14px до 53px.

Як підписатися на зміни розміру тексту?

В UIKit через UIContentSizeCategory.didChangeNotification. В SwiftUI використовуйте @Environment(\.dynamicTypeSize) — подання оновиться автоматично при зміні системного налаштування.

Що буде, якщо не підтримувати Dynamic Type?

Користувачі з збільшеним шрифтом побачать обрізаний текст, наїжджаючі елементи та непрацюючі кнопки. Додаток може бути відхилений на App Store Review за порушення accessibility-вимог.

Підсумки

  • Dynamic Type — вбудований механізм iOS для масштабування тексту під системні налаштування; обов’язковий для App Store
  • Використовуйте UIFont.preferredFont(forTextStyle:) для системних шрифтів та UIFontMetrics для кастомних
  • iOS підтримує 11 рівнів масштабування — від XS до AccessibilityXXXXXL (14–53px для body)
  • В SwiftUI Dynamic Type працює автоматично через .font(.body) та @Environment(\.dynamicTypeSize)
  • Верстка повинна бути адаптивною: UIStackView, automaticDimension в таблицях, numberOfLines = 0
  • Тестуйте всі 11 рівнів, особливо accessibility-категорії — на них ламається 70% верстки
  • Підписка на UIContentSizeCategory.didChangeNotification обов’язкова для UIKit-додатків

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також