UIタイポグラフィーの詳細 〜その2〜 – WWDC2020

Session概要

UIタイポグラフィーの詳細 〜その1〜ではOptical size、Variable sizeについて、Trackingの仕組みやLeadingについて説明しました。
ここでは一貫したタイポグラフィーを作成するのに役立つ、フォントとテキストのパワフルなAPIについて紹介します

Text styleとDynamic Typeについて

Text Style

  • システムフォントのウェイト、ポイントサイズ、Leadingを組み合わせて定義したもの
    • このシステム機能はタイポグラフィーの階層を提供し、読みやすいレイアウトを実現する助けになる
  • テキストスタイルには、情報の階層を表せるよう幅広いフォントサイズがありますが、細かな違いを表すのにサイズだけでは不十分な場合がある
    • フォントウェイトを変更することで強調させる
    • テキストスタイルには、Line-heightが設定されており大抵は適切な幅となっているが、スペースが限られる場合は、行間を狭めることで情報の密度を高められる
    • 多くのテキストを表示する時は、読みやすさのために空間(スペース)が欲しい場合がある
      • スペースの設定はテキストスタイルのleadingを調整する
      • iOS, macOSでは狭いleadingを使うとLine heightが2pt減り、広いleadingを使うと2pt増える
      • watchOSでは増減幅は1pt
// Getting emphasized text styles
// フォントウェイトの設定により強調させる

let label = UILabel()
label.text = "Ready. Set. Code."

if let descriptor = UIFontDescriptor
    .preferredFontDescriptor(withTextStyle: .title1)
    .withSymbolicTraits(.traitBold) {
    // 28 pt Bold on iOS
    label.font = .init(descriptor: descriptor, size: 0)
}
// Getting emphasized text styles
// boldを使用したテキストの強調サンプル

// AppKit
let descriptor = NSFontDescriptor
    .preferredFontDescriptor(forTextStyle: .body)
    .withSymbolicTraits(.bold)
// 13 pt Semibold on macOS
let emphasizedBodyFont = NSFont(descriptor: descriptor, size: 0)

// UIKit/Catalyst
if let descriptor = UIFontDescriptor
    .preferredFontDescriptor(withTextStyle: .body)
    .withSymbolicTraits(.traitBold) {
    // 17 pt Semibold on iOS
    let emphasizedBodyFont = UIFont(descriptor: descriptor, size: 0)
}

// SwiftUI
let emphasizedFootnoteFont = Font.footnote.bold() // 13 pt Semibold on iOS
アプリの性質によって適切なスペースを設定する
// Getting tight/loose leading variant
// 適切なleading幅を設定し、コンテンツの可読性を向上させる

// AppKit
let descriptor = NSFontDescriptor.preferredFontDescriptor(forTextStyle: .headline)
    .withSymbolicTraits(.tightLeading) // Use .looseLeading for loose leading font
let tightLeadingFont = NSFont(descriptor: descriptor, size: 0) // 14 pt line height

// UIKit/Catalyst
if let descriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .title1)
    .withSymbolicTraits(.traitTightLeading) { // Use .traitLooseLeading for loose leading
    let tightLeadingFont = UIFont(descriptor: descriptor, size: 0) // 36 pt line height
}

// SwiftUI
// Use .loose for loose leading font
let tightLeadingFootnoteFont = Font.footnote.leading(.tight) // 16 pt line height on iOS
// Access system font designs
// Use .serif for New York, .monospaced for SF Mono
// .rounded を指定することで、丸みのあるフォントを設定可能

// AppKit
let descriptor = NSFontDescriptor.preferredFontDescriptor(forTextStyle: .body)
    .withDesign(.rounded)
let roundedBodyFont = NSFont(descriptor: descriptor, size: 0) // SF Pro Rounded

// UIKit/Catalyst
if let descriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body)
    .withDesign(.rounded) {
    let roundedBodyFont = UIFont(descriptor: descriptor, size: 0) // SF Pro Rounded
}

// SwiftUI
let roundedBodyFont = Font.system(.body, design: .rounded) // SF Pro Rounded

CSSでの新しいfont-familyの設定

macOS向けのText Style API

  • macOSでもText Styleをサポート
  • フォントサイズはmacOSテキストに沿って調整され、Dynamic Typeは未対応
  • CatalystアプリのテキストスタイルサイズはiOS向けに77%縮小したサイズだが、2020年からCatalystアプリのインタフェースがMac用に最適化された(77%に近いスタイルなので変更は最小限で済む)

Dynamic Type

  • iOSに追加されたテキストスタイルの新機能で、設定に沿ってフォントを自動的に拡大、縮小する
  • Dynamic Typeを使うとテキストスタイルのサイズを調整可能
    • Dynamic Typeはカスタムフォントにも利用可能
  • 拡大縮小の比率はテキストスタイルによって異なる
  • アクセシビリティ向上のため、Dynamic Typeをサポートするのが望ましい

カスタムフォントのDynamic Typeのサポート

  • iOS 11 からUIFontMetricsクラスが導入されており、このクラスでテキストスタイルのDynamic Type機能を取得し 
// Support Dynamic Type with custom font in UIKit

if let customFont = UIFont(name: "Charter-Roman", size: 17) {
    let bodyMetrics = UIFontMetrics(forTextStyle: .body)
    
    // Charter-Roman scaled relative to body text style
    // in different content size categories.
    let customFontScaledLikeBody = bodyMetrics.scaledFont(for: customFont)
    label.font = customFontScaledLikeBody
    label.adjustsFontForContentSizeCategory = true

    // Scaling constant 10 relative to body text style.
    let scaledValue = bodyMetrics.scaledValue(for: 10)
}

SwiftUIでのフォントの拡大縮小

  • iOS 13ではカスタムフォントを使用するとDynamic Typeに対応できなくなる問題があった
  • しかし、iOS 14からfontの指定時にrelativeToでtitleスタイルと相対的に拡大縮小が可能となった
    • 指定しない場合はbodyから相対的に指定
  • iOS 14ではカスタムフォントはデフォルトでbodyスタイルと相対的に拡大縮小される
  • @ScaledMetricプロパティラッパーにより、Dynamic Typeに合わせてpaddingも動的に変更可能
struct ContentView: View {
    let prose = "Apple provides two type families you can use in your iOS apps. San Francisco (SF). San Francisco is a sans serif type family that includes SF Pro, SF Pro Rounded, SF Mono, SF Compact, and SF Compact Rounded."
    @ScaledMetric(relativeTo: .body) var padding: CGFloat = 20

    var body: some View {
        VStack {
            Text("Typography")
                .font(.custom("Avenir-Medium", size: 34, relativeTo: .title))
            Text(prose)
                .font(.custom("Charter-Roman", size: 17))
                .padding(padding)
        }
    }
}
// Support Dynamic Type with custom fonts in SwiftUI

// Text with font Avenir-Roman, scaling relative to title text style.
Text("Typography").font(.custom("Avenir-Roman", size: 34, relativeTo: .title))

// Text with font Helvetica, scaling relative to body text style.
Text("Title").font(.custom("Helvetica", size: 17))

// Text with font Courier, always use fixed size, do not scale according to user setting.
Text("Fixed").font(.custom("Courier", fixedSize: 17))

// Constant 10, scaled relative to title text style.
@ScaledMetric(relativeTo: .title) private var spacing: CGFloat = 10.0

原則

  • SF Pro, SF Pro Rounded, SF Mono, NewYorkのシステムフォントの使用を試みる
  • デフォルトのシステム動作から変更するのは例外的な場合のみとする
  • インタフェースでカスタムのTrackingを使う場合、サイズを限定する
    • 小さいサイズのトラッキングは大きいサイズに合わないことがある
最新情報をチェックしよう!