Типографика в SwiftUI: как подключать и масштабировать текст

Типографика в SwiftUI строится вокруг системных текстовых стилей, Dynamic Type и корректно зарегистрированных шрифтов. Чтобы текст оставался читаемым на разных экранах и при увеличенном размере шрифта, используйте семантические стили, подключайте гарнитуру через настройки проекта, масштабируйте ее относительно роли текста и проверяйте интерфейс в специальных возможностях.
Что означает типографика в SwiftUI
Типографика в SwiftUI — это не только выбор гарнитуры и размера. Она включает иерархию заголовков, межстрочный интервал, начертания, выравнивание, переносы, контраст и поведение текста при изменении настроек доступности. SwiftUI дает декларативный способ описывать эти свойства: разработчик задает роль и правила отображения, а фреймворк учитывает размер экрана, Dynamic Type и особенности платформы.
Главный принцип — отделять смысловой стиль от конкретного числа. Вместо того чтобы задавать всем надписям размер 17 или 24 пункта, определите роли: заголовок экрана, подзаголовок, основной текст, подпись и вспомогательная информация. Такой подход упрощает поддержку дизайн-системы и снижает риск того, что интерфейс распадется после увеличения шрифта.
Как подключить собственный шрифт к проекту
SwiftUI не использует файл шрифта автоматически только потому, что он добавлен в папку проекта. Гарнитуру нужно включить в target, зарегистрировать в настройках приложения и затем вызвать по ее внутреннему имени. Обычно используются форматы OTF или TTF, но перед публикацией важно проверить лицензию шрифта и разрешение на встраивание в мобильное приложение.
Добавьте файлы и включите Target Membership
Перетащите файлы начертаний в навигатор проекта Xcode и убедитесь, что для каждого файла включен Target Membership нужного приложения. Если гарнитура состоит из обычного, полужирного и курсивного начертаний, добавьте их отдельно. Не переименовывайте файлы без необходимости: имя файла и внутреннее имя шрифта могут отличаться, и именно это часто становится причиной ошибки при вызове Font.custom.
Зарегистрируйте шрифт в Info.plist
В настройках приложения добавьте ключ Fonts provided by application, известный также как UIAppFonts, и перечислите названия файлов ресурсов с расширениями. Пример значения: Inter-Regular.ttf, Inter-Semibold.ttf, Inter-Bold.ttf. После сборки проверьте, что файлы действительно попали в bundle приложения, иначе SwiftUI не сможет найти гарнитуру во время выполнения.
Найдите внутреннее имя гарнитуры
Вызов Font.custom принимает имя шрифта, а не обязательно имя файла. Например, файл может называться Inter-Semibold.ttf, а внутреннее имя — Inter Semi Bold или Inter-SemiBold. Если текст не меняется или в консоли появляется сообщение о невозможности загрузить шрифт, проверьте PostScript name через Font Book либо выведите доступные имена шрифтов с помощью UIFont семейства UIKit во время отладки.
Как применить шрифт в SwiftUI
Для единичного текстового элемента достаточно вызвать Font.custom с именем гарнитуры и размером. Пример: Text(«Заголовок»).font(.custom(«Inter-SemiBold», size: 24)). Такой вариант подходит для декоративных надписей и фиксированных элементов, но сам по себе не гарантирует корректное масштабирование при изменении системного размера текста.
Для интерфейсного текста используйте относительный текстовый стиль: Text(«Описание»).font(.custom(«Inter-Regular», size: 17, relativeTo: .body)). Параметр relativeTo связывает размер пользовательского шрифта с ролью body, поэтому гарнитура участвует в механизме Dynamic Type. Для заголовка можно выбрать .title2, для подписи — .caption, а конкретное начальное значение оставить частью типографического токена.
Если собственная гарнитура не обязательна, применяйте системные варианты: .font(.system(.body, design: .default)), .font(.system(.headline, design: .rounded)) или .font(.system(.title, design: .serif)). Системный шрифт уже согласован с платформой, поддерживает Dynamic Type и обычно лучше ведет себя в локализациях, чем случайно выбранная декоративная гарнитура.
Dynamic Type: масштабирование без потери доступности
Dynamic Type позволяет пользователю менять размер текста в настройках устройства. SwiftUI автоматически масштабирует системные текстовые стили, если вы используете .body, .headline, .title и другие семантические роли. При работе с Font.custom применяйте инициализатор relativeTo, иначе размер останется практически фиксированным и может стать слишком мелким для пользователя с увеличенным шрифтом.
Проверяйте не только стандартный размер, но и крупные категории доступности. Длинный заголовок должен переноситься, кнопка — увеличиваться по высоте, а соседние элементы — сохранять расстояние. Не ограничивайте основной текст жестким lineLimit без необходимости: обрезанная фраза может скрыть важную информацию и сделать экран непонятным.
Когда применять dynamicTypeSize
Модификатор dynamicTypeSize подходит, когда компонент должен работать в ограниченном диапазоне размеров. Например, компактный виджет может использовать .dynamicTypeSize(.small ... .large), а основной экран лучше не ограничивать. Ограничение допустимо только после проверки сценария: оно не должно превращаться в способ скрыть проблемы верстки или лишить пользователя выбранного размера текста.
Когда нужен @ScaledMetric
@ScaledMetric масштабирует не сам текст, а связанные с ним числовые значения: размер иконки, отступ, высоту изображения или радиус элемента. Пример: @ScaledMetric(relativeTo: .body) private var iconSize: CGFloat = 20. Это помогает сохранить визуальную связь между надписью и иконкой при увеличении Dynamic Type, но не заменяет использование семантического шрифта.
Постройте типографическую иерархию
Хорошая иерархия показывает, что читать в первую очередь, где находится действие и какие сведения вторичны. В SwiftUI ее удобно оформить как набор переиспользуемых стилей: screenTitle, sectionTitle, body, secondary и caption. Каждый стиль должен описывать не только размер, но и начертание, цвет, межстрочный интервал и допустимое поведение в компактной ширине.
- Определите роли текста до верстки отдельных экранов.
- Выберите системные стили как основу для масштабирования.
- Назначьте собственные начертания каждой роли, а не каждому Text отдельно.
- Проверьте контраст основного, вторичного и отключенного текста.
- Согласуйте переносы, отступы и высоту строк с дизайн-системой.
- Протестируйте длинные локализованные строки и крупные настройки Dynamic Type.
Практический компонент может выглядеть так: Text(title).font(.custom(«Inter-SemiBold», size: 28, relativeTo: .title2)).foregroundStyle(.primary).multilineTextAlignment(.leading). Такая запись сохраняет семантическую связь с title2, поддерживает увеличение текста и не привязывает заголовок к одному экрану или конкретной ширине контейнера.
Пример масштабируемого текстового блока
Представим карточку статьи с заголовком, описанием и метаданными. Заголовок можно связать с .title2, описание — с .body, дату — с .caption. Для текста карточки используйте lineLimit только там, где обрезка предусмотрена дизайном, например в списке превью. На экране подробностей дайте описанию занять столько строк, сколько нужно пользователю.
Пример структуры: VStack(alignment: .leading, spacing: 8) { Text(title).font(.custom(«Inter-SemiBold», size: 22, relativeTo: .title2)); Text(summary).font(.custom(«Inter-Regular», size: 17, relativeTo: .body)); Text(date).font(.custom(«Inter-Regular», size: 13, relativeTo: .caption)); }.padding(). При необходимости вынесите эти параметры в отдельный ViewModifier или типографический объект, чтобы обновлять систему централизованно.
Для однострочной кнопки, где текст должен помещаться в компактный контейнер, можно использовать .lineLimit(1) и .minimumScaleFactor(0.85). Не переносите этот прием на основной контент: уменьшение кегля вместо адаптации контейнера ухудшает читаемость и делает поведение интерфейса непредсказуемым на крупных настройках текста.
Цвет, начертание и межстрочный интервал
Размер не является единственным параметром читаемости. Основной текст должен иметь достаточный контраст с фоном, вторичный — оставаться различимым, а disabled-состояние не должно быть единственным способом передать критически важную информацию. Для начертания используйте заранее выбранные веса: .regular для длинного текста, .semibold для акцентов и .bold только там, где он действительно усиливает иерархию.
Модификатор .lineSpacing помогает настроить расстояние между строками, но его следует проверять вместе с Dynamic Type. Слишком большая величина раздувает карточки, а слишком маленькая ухудшает чтение абзацев. Для длинных материалов важнее стабильная ширина текстовой колонки, корректные поля и естественные переносы, чем попытка уместить больше строк на экране.
Частые ошибки при работе со шрифтами
- Использовать имя файла вместо внутреннего имени шрифта и получать незаметную подмену гарнитуры.
- Задать Font.custom только с size и забыть параметр relativeTo, из-за чего текст плохо масштабируется.
- Применить фиксированный frame к заголовку и обрезать строку при крупном Dynamic Type.
- Сделать lineLimit(1) для описания, хотя пользователю нужно прочитать весь текст.
- Подключить только Regular и ожидать, что SwiftUI корректно имитирует все начертания.
- Проверить макет только на одном устройстве и не учесть компактную ширину, iPad или локализацию.
- Смешать несколько несогласованных гарнитур и разрушить визуальную иерархию экрана.
Отдельная ошибка — считать, что автоматическое масштабирование решает все проблемы. Dynamic Type меняет размер букв, но не исправляет жестко заданные высоты, недостаточные отступы, конфликтующие кнопки и слишком узкие колонки. Адаптивная типографика всегда проверяется вместе с компоновкой, жестами, VoiceOver и реальным содержанием.
Чеклист типографики перед релизом
- Проверьте наличие всех файлов шрифта в Target Membership.
- Сверьте внутренние имена гарнитур с вызовами Font.custom.
- Используйте relativeTo для каждого масштабируемого собственного начертания.
- Протестируйте стандартный и увеличенный размеры Dynamic Type.
- Проверьте переносы заголовков, кнопок, полей ввода и сообщений об ошибках.
- Оцените контраст и различимость вторичного текста.
- Откройте экран на разных размерах устройств и при длинных строках.
- Убедитесь, что лицензия разрешает встраивание выбранного шрифта.
Часто задаваемые вопросы
Почему Font.custom не меняет шрифт в приложении?
Чаще всего проблема связана с отсутствием файла в Target Membership, ошибкой в UIAppFonts или неверным внутренним именем гарнитуры. Имя файла и PostScript name могут различаться, поэтому проверьте оба значения. Также убедитесь, что вызывается именно то начертание, которое добавлено в bundle приложения.
Как сделать собственный шрифт совместимым с Dynamic Type?
Используйте Font.custom с параметром relativeTo, например relativeTo: .body или relativeTo: .headline. Если задать только фиксированный size, SwiftUI не получит семантическую роль текста и не сможет корректно связать гарнитуру с системными категориями Dynamic Type. После этого проверьте крупные размеры вручную.
Можно ли использовать один шрифт для всего приложения?
Можно, если гарнитура имеет нужные начертания, хорошо читается на малом размере и поддерживает языки приложения. Однако один шрифт не означает один размер и один вес: для заголовков, основного текста, подписей и действий все равно нужны разные семантические роли и токены типографической системы.
Что выбрать: системный или собственный шрифт?
Системный шрифт подходит, когда важны максимальная нативность, доступность и минимальные затраты на поддержку. Собственная гарнитура оправдана для брендинга, редакционного характера интерфейса или визуальной идентичности продукта. В обоих случаях приоритетом остаются читаемость, локализация и корректное масштабирование.
Нужно ли использовать @ScaledMetric для размера текста?
Нет. Размер текста должен задаваться через системный стиль или Font.custom с relativeTo. @ScaledMetric предназначен для связанных величин интерфейса: иконок, отступов, размеров иллюстраций и других элементов, которые должны изменяться вместе с текстом.
Как проверять типографику на больших размерах текста?
Запустите приложение с увеличенной категорией текста в настройках доступности и пройдите ключевые сценарии: чтение, поиск, заполнение формы и подтверждение действия. Ищите обрезанные строки, перекрытия, исчезнувшие кнопки и слишком плотные группы элементов. Для каждого дефекта меняйте компоновку, а не просто уменьшайте шрифт.
Вывод: масштабируемая типографика без компромиссов
Надежная типографика в SwiftUI начинается с правильной регистрации шрифта и заканчивается проверкой всего интерфейса в разных размерах Dynamic Type. Используйте семантические роли, Font.custom с relativeTo, @ScaledMetric для связанных размеров и отдельные токены дизайн-системы. Так текст сохранит и фирменный характер, и доступность.
Нужна собственная гарнитура для приложения, сайта или бренда? Создайте и настройте шрифт на fontgenerator.ru, а затем подключите подходящие начертания в свою типографическую систему SwiftUI.