Guide for Mobile Text Scaling

This page is not available in the language you requested. You have been redirected to the English version of the page.
Link to this page copied to clipboard
Not for use with personal data

Mobile applications must conform to WCAG 1.4.4 Resize Text and scale content to ensure no loss of information or functionality for users requiring larger font sizes. This guide covers recommended ways to support text scaling on both iOS and Android platforms.

Platform-Specific Features

iOS - Dynamic Type

Dynamic Type is an accessibility feature within iOS that allows font sizes to be scaled device-wide based on the user's preference. Find this option under Accessibility Settings on the device. Read more from Apple on Text Display here.

Android - Text and Display Scaling

For Android devices 13 and up, you can change the preferred text and content size in accessibility settings. Users can adjust both font size and display size independently. Read more on changing these settings in Google's support guide for text and display settings.

Preparing Your Views

Ensure Content Can Scroll

iOS: When text is scaled to larger font sizes, substantial content could be pushed off-screen. Implement a UIScrollView or ScrollView on any screen with content.

Android: Use a ScrollView element as the container for layout elements (constraint, linear, relative). ScrollViews will not scroll until the screen's height (or width, for horizontal scroll) is filled.

Exceptions:

  • Android: RecyclerViews don't need to be embedded within a ScrollView. Allow items to expand vertically or horizontally.
  • Android: Navigation elements (bottom bars, tabs, toolbars) should be at the same level as the containing ScrollView, not within it.

Ensure Content Can Expand

iOS: Utilize contentHuggingPriority, contentCompressionResistancePriority, greaterThanOrEqualTo, and lessThanOrEqualTo to allow views to expand. Limit setting constant height and width for views containing content.

Android: Most text resizing issues can be resolved by not restricting the height or width of a view. Allow TextView to expand with constraints set. Use wrap_content for height and either match_parent or 0dp for width.

Layout-Specific Considerations

Android ConstraintLayout: Set view width to match_parent and height to wrap_content, or use 0dp width to fill space between constraints. Always ensure components can expand vertically.

Android RelativeLayout: Define start and end guidelines for sibling elements to ensure components remain on-screen.

Android LinearLayout: Can adjust to changing content sizes if in a ScrollView and don't set match_parent height. Use android:minHeight for specific height requirements.

Set Number of Lines

iOS: Set numberOfLines property to 0 for any text with overflow potential. For UIButton, set numberOfLines to 0 on its titleLabel.

Android: Use SP (scale-independent pixels) for all text, not DP (density-independent pixels). You can utilize Android Studio's accessibility linter to catch SP usage issues.

Implementation

iOS Implementation

SwiftUI Views (iOS 14+)

Using Default Fonts:

.font(.system(.largeTitle, design: .rounded))

Using Custom Fonts:

.font(.custom("FontName", size: 16, relativeTo: .body))

UIKit Views

Using Default Fonts:

label.font = UIFont.preferredFont(forTextStyle: .body)
label.adjustsFontForContentSizeCategory = true

Using Custom Fonts with UIFontMetrics:

guard let font = UIFont(name: "CustomFont", size: UIFont.labelFontSize) else { return }
label.font = UIFontMetrics(forTextStyle: .caption1).scaledFont(for: font)
label.adjustsFontForContentSizeCategory = true

Manual Dynamic Type Handling:

// Via Notification Observer
NotificationCenter.default.addObserver(self,
                                       selector: #selector(changeTextSize),
                                       name: UIContentSizeCategory.didChangeNotification,
                                       object: nil)

// Via TraitCollection Override
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    // Handle font size changes based on preferredContentSizeCategory
}

Android Implementation

Basic Setup:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="16sp" />

ConstraintLayout Example:

<Button
    android:id="@+id/button"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="Button Text"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent" />

Programmatic Text Modification:

SpannableStringBuilder str = new SpannableStringBuilder(tv.getText());
str.setSpan(new AbsoluteSizeSpan(70, true), 15, 18, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(str);

Testing and Best Practices

General Guidelines

  • Test against various font sizes to ensure content displays as expected.
  • Keep headings short and descriptive for better accessibility.
  • Ensure usability isn't affected by improper constraints.
  • Verify all text controls support scaling without pushing content off-screen.

Platform-Specific Considerations

iOS:

  • Follow Apple's Typography Guidelines and Supporting Dynamic Type documentation.
  • Use appropriate TextStyles (.body, .title1, .caption1, etc.).
  • For SwiftUI, many considerations are provided by default but should be reviewed.

Android:

  • Use short titles for toolbars; avoid Toolbar widget for dynamic titles.
  • Provide distinct iconography with descriptive content descriptions for bottom navigation.
  • Utilize scrollable views for tabs, ViewPager, and TabList components.
  • Don't limit the height of controls.

Key Takeaways

  1. Always implement scrollable containers for content that might overflow.
  2. Use platform-appropriate scaling units (SP for Android, TextStyles for iOS).
  3. Test thoroughly across different font sizes and accessibility settings.
  4. Allow views to expand rather than constraining them to fixed dimensions.
  5. Follow platform guidelines for optimal user experience.