Dynamic Type: 핵심 개념, 텍스트 스타일 및 iOS에서의 동작 방식

저자: IT Sectr 게시일: 2026-05-16 읽는 시간: 9 분

Dynamic Type은 사용자의 시스템 설정에 따라 앱에서 글꼴 크기를 자동으로 변경하는 iOS 내장 기능입니다. 사용자는 설정 → 디스플레이 및 명도 → 텍스트 크기에서 선호하는 텍스트 크기를 설정하고, Dynamic Type을 지원하는 모든 앱이 추가 작업 없이 적응됩니다. Apple Human Interface Guidelines, 2024에 따르면, Dynamic Type 지원은 App Store에 출시하기 위한 필수 요구사항이며, iOS 플래폼의 접근성에서 기본 요소입니다.

중요 포인트

  • Dynamic Type — 시스템 글꼴 크기 설정에 따라 텍스트를 자동으로 스케일하는 iOS 메커니즘
  • 지원은 텍스트 스타일(UIFont.TextStyle) — body, headline, caption, title 등을 통해 제공됨
  • 시스템은 XSmall부터 AccessibilityXXXL까지 11단계의 스케일링을 지원
  • 커스텀 글꼴에는 UIFontMetrics 메서드를 사용하여 임의 글꼴을 body 스타일에 상대적으로 스케일
  • 레이아웃은 적응적이어야 함 — UIStackView, Auto Layout 및 동적 셀 높이가 필수

iOS에서 Dynamic Type이란

Dynamic Type은 iOS 7에서 도입된 iOS 기술로, 앱의 텍스트가 시스템 글꼴 크기 설정에 자동으로 적응할 수 있도록 합니다. 사용자는 모든 앱에서 동시에 글꼴을 크게 하거나 작게 할 수 있습니다 — 각 앱 내부에서 개별적으로 설정을 변경할 필요가 없습니다.

Apple WWDC 2023, “Make Your App Visually Accessible”에 따르면, iOS 사용자의 40% 이상이 기본 글꼴 크기를 변경합니다. 65세 이상 연령대의 경우 이 수치는 70%에 달합니다. Dynamic Type은 App Store 접근성 인증에 필수 요구사항입니다. 지원이 없으면 리뷰 도중 앱이 거부되는 이유가 됩니다.

작동 방식: 앱은 UIFont(name:size:)대신 UIFont.preferredFont(forTextStyle:)를 사용합니다. iOS는 현재 시스템 설정에 따라 스케일된 글꼴을 자동으로 반환합니다. 설정에서 크기가 변경되면 iOS가 UIContentSizeCategory.didChangeNotification을 생성합니다 — 앱은 레이아웃을 재계산해야 합니다.

Dynamic Type 발전사

Dynamic Type은 iOS 7에서 플랫 디자인과 함께 등장했습니다. iOS 10은 UIFontMetrics를 통한 커스텀 글꼴 지원을 추가했습니다. iOS 11은 접근성 단계(AccessibilityXXXL까지)를 도입했습니다. iOS 15는 SwiftUI에 Dynamic Type을 추가하고 자동 지원을 제공했습니다. 매 리리스마다 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까지 도달할 수 있습니다. 앱이 body에 고정 17px 글꼴을 사용하는 경우, 글꼴 크기를 늘린 사용자에게 텍스트가 읽기 어려워집니다.

스타일을 통한 시각적 계층 구조

Dynamic Type은 단순히 스케일하지 않고 시각적 계층 구조를 보전합니다. Large Title은 헥상 Title 1보다 크고, Title 1은 Body보다 큽니다. 스케일링 계수는 다릅니다: 제목은 주요 텍스트보다 깥게 스케일되어 접근성 단계에서도 계층이 유지됩니다.

스케일링 단계

iOS는 텍스트 스케일링의 11단계를 지원하며, 두 카테고리로 나뒉니다:

  • 표준 크기 (5단계): XS, S, M, L (기본), XL
  • 접근성 크기 (6단계): accessibilityXL, accessibilityXXL, accessibilityXXXL, accessibilityXXXXL, accessibilityXXXXXL, accessibilityXXXXXXL

body 스타일의 XS와 AccessibilityXXXL 사이의 차이는 14px에서 53px까지입니다 — 거의 4배입니다. 17px을 위해 설계된 레이아웃은 53px에서 완전히 깨집니다: 텍스트가 넘쳐 흑르고, 버튼이 검치며, 셀이 충돌합니다.

코드에서 현재 카테고리 확인:

swift
let category = UIApplication.shared.preferredContentSizeCategory
// .extraSmall, .small, .medium, .large, .extraLarge ...
if category.isAccessibilityCategory {
    // 대체 레이아웃 활성화
}

traitCollection과 텍스트 크기

텍스트 크기 카테고리는 traitCollection.uiContentSizeCategory를 통해 사용할 수 있습니다. 시스템 설정이 변경되면 iOS가 모든 UIView에서 traitCollectionDidChange를 호출합니다. 이 메서드에서 글꼴을 업데이트하고 레이아웃을 재계산해야 합니다. SwiftUI는 이를 자동으로 수행하지만 UIKit은 수동 구독이 필요합니다.

UICollectionView에서는 UICollectionViewCompositionalLayout을 사용하세요 — 화면 너비와 텍스트 크기에 따라 열 수를 자동으로 조정합니다. 접근성 단계에서는 2열 레이아웃에서 1열 레이아웃으로 전환하여 텍스트가 잘리지 않고 요소가 검치지 않도록 합니다. 조건부 레이아웃을 사용하세요: 일반 너비에서는 2열, 압축된 경우나 접근성에서는 1열입니다.

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
)

Interface Builder에서 UILabel에 대해서는 글꼴을 텍스트 스타일로 설정하고 “Automatically Adjusts Font”를 율 크기만 하면 됩니다. 커스텀 글꼴의 경우 Interface Builder는 UIFontMetrics를 지원하지 않으므로 코드를 통해서만 가능합니다.

UIFontMetrics와 스케일링 곡선

UIFontMetrics는 preferredFont와 동일한 스케일링 곡선을 사용합니다. fromTextStyle: .body, .headline 등을 지정할 수 있습니다. 각 스타일에는 고유한 스케일링 계수가 있습니다. Body는 중등하게 스케일하고, Large Title은 깥게 스케일합니다. 커스텀 글꼴을 주요 텍스트에 사용하는 경우 .body를 사용하세요.

SwiftUI에서 Dynamic Type

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는 시스템 텍스트 크기가 변경될 때 뷰를 자동으로 업데이트합니다 — 추가 알림 구독이 필요하지 않습니다.

SwiftUI에서 Dynamic Type 제한

.font(.body) 수정자는 시스템 글꼴에서만 작동합니다. SwiftUI에서 커스텀 글꼴에 대해서는 UIFontMetrics를 내장 사용하는 Font.custom를 사용하세요. iOS 16부터 SwiftUI는 @Environment에서 DynamicTypeSize를 지원하여 여백과 레이아웃을 적응할 수 있습니다.

큰 글꼴에 맞초 레이아웃 적응

Auto Layout은 Dynamic Type 지원의 전제 조건입니다. 고정 너비와 높이(>=, <=)는 접근성 크기에서 깨집니다. UILabel에서는 intrinsicContentSize를 사용하세요 — 현재 글꼴 크기에 끔 높이를 자동으로 계산합니다.

적응적 레이아웃 규칙:

  • distribution = fill 및 spacing >= 8의 UIStackView — 요소가 다음 줄로 래핑됨
  • automaticDimension의 UITableViewCell — 셀 높이가 콘텐츠에 맞게 조정됨
  • UILabel에서 numberOfLines = 0 — 텍스트가 잘리지 않고 래핑됨
  • edgeInsets가 있는 버튼 — traitCollection.preferredContentSizeCategory를 통해 접근성 단계에서 여백 추가

긴 텍스트(예: 기사, 이용약관)에는 UILabel에서 minimumScaleFactor를 설정하세요 — 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)

접근성 단계에서의 일반적인 레이아웃 문제

텍스트 잘리기 — numberOfLines = 1과 고정 너비의 UILabel은 AccessibilityXL에서 텍스트를 잘랍니다. 해결 방법: numberOfLines = 0 및 trailing 제약. 요소 검침 — 고정 높이의 버튼이 서로 검칭니다. 해결 방법: 자동 간격의 UIStackView. 화면 밖으로 나가는 콘텐츠 — 접근성 단계에서는 ScrollView가 필수입니다.

Dynamic Type 테스트

Xcode 시뮬레이터를 통해 텍스트 크기를 변경할 수 있습니다: 시뮬레이터 메뉴에서 Settings → Accessibility → Display & Text Size → Larger Text로 이동하세요. 11개의 모든 단계를 전환하면서 텍스트가 잘리지 않고, 버튼이 접근 가능하고, 레이아웃이 깨지지 않는지 확인하세요.

자동 테스트에는 XCUIApplication에서 contentSizeCategory 설정을 사용하세요:

swift
func testAccessibilitySizes() {
    let app = XCUIApplication()
    app.launchArguments += [
        "-UIPreferredContentSizeCategoryName",
        "UICTContentSizeCategoryAccessibilityXXXL"
    ]
    app.launch()
    app.scrollViews.buttons["제출"].tap()
    XCTAssertTrue(app.staticTexts["폼이 제출되었습니다"]
        .waitForExistence(timeout: 5))
}

다양한 launchArguments를 사용한 XCUITest를 통해 CI에서 모든 스케일링 단계를 확인할 수 있습니다. 접근성 카테고리를 별도로 테스트하는 것을 잊지 마세요 — 이것들이 가장 자주 레이아웃을 깨튜립니다. Apple에 따르면 Dynamic Type 버그의 70%가 접근성 단계에서 발견되는데, 그 이유는 개발자가 표준 크기만 테스트하기 때문입니다.

Accessibility Inspector: Dynamic Type 확인

Xcode Accessibility Inspector는 선택된 요소가 사용하는 글꼴(고정 또는 스케일 가능)을 보여줍니다. 요소가 시뮬레이터에서 텍스트 크기 변경에 반응하지 않는 경우 고정 글꼴이 사용되고 있는 것입니다. UIFont.preferredFont 또는 UIFontMetrics로 교체하세요.

자주 묻는 질문

간단하게 말하면 iOS에서 Dynamic Type이란 무엇인가요?

시스템 크기 설정에 따라 앱에서 자동으로 텍스트 크기를 조절하는 것입니다. 사용자가 설정에서 크기를 변경하면 지원되는 모든 앱이 개발자 개입 없이 적응됩니다.

Dynamic Type은 시스템 글꼴에서만 작동하나요?

아닙니다. 커스텀 글꼴에는 UIFontMetrics(scaledFont:)를 사용하세요. 이 메서드는 지정된 텍스트 스타일에 상대적으로 임의 글꼴을 스케일하며 비율을 유지합니다.

iOS는 몇 가지 스케일링 단계를 지원하나요?

11단계: 5개의 표준 (XS, S, M, L, XL)과 6개의 접근성 단계(AccessibilityXL부터 AccessibilityXXXXXL까지)입니다. body 글꼴 크기는 14px에서 53px까지 다양합니다.

텍스트 크기 변경을 구독하려면 어떻게 하나요?

UIKit에서는 UIContentSizeCategory.didChangeNotification을 통해 구독합니다. SwiftUI에서는 @Environment(\.dynamicTypeSize)를 사용하세요 — 시스템 설정이 변경되면 뷰가 자동으로 업데이트됩니다.

Dynamic Type을 지원하지 않으면 어떻게 됩나요?

글꼴을 크게 설정한 사용자는 잘린 텍스트, 검침 된 요소 및 고장난 버튼을 보게 됩니다. 접근성 요구사항 위반으로 앱이 App Store 리뷰에서 거부될 수 있습니다.

요약

  • Dynamic Type — 시스템 설정에 따라 텍스트를 스케일하는 내장 iOS 메커니즘; App Store에 필수
  • 시스템 글꼴에는 UIFont.preferredFont(forTextStyle:)을, 커스텀 글꼴에는 UIFontMetrics를 사용
  • iOS는 11단계의 스케일링을 지원 — XS부터 AccessibilityXXXXXL까지 (body 14–53px)
  • SwiftUI에서 Dynamic Type은 .font(.body) 및 @Environment(\.dynamicTypeSize)를 통해 자동으로 동작
  • 레이아웃은 적응적이어야 함: UIStackView, 테이블의 automaticDimension, numberOfLines = 0
  • 11개 단계 모두를 테스트하고, 특히 접근성 카테고리를 테스트 — 70%의 레이아웃이 이것들에서 깨짐
  • UIKit 앱에서는 UIContentSizeCategory.didChangeNotification 구독이 필수

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기