View in English

  • 메뉴 열기 메뉴 닫기
  • Apple Developer
검색
검색 닫기
  • Apple Developer
  • 뉴스
  • 둘러보기
  • 디자인
  • 개발
  • 배포
  • 지원
  • 계정
페이지에서만 검색

빠른 링크

5 빠른 링크

비디오

메뉴 열기 메뉴 닫기
  • 컬렉션
  • 주제
  • 전체 비디오
  • 소개

WWDC25 컬렉션으로 돌아가기

스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.

  • 소개
  • 요약
  • 자막 전문
  • 코드
  • 모든 사람이 Mac 앱을 더 손쉽게 사용하도록 만들기

    macOS의 강점과 유연성을 최대한 활용하는 손쉬운 사용 기능을 통합하는 방법을 알아보세요. 기본적인 내용뿐만 아니라, VoiceOver 및 음성 명령을 지원하고, 뷰 레이아웃을 개선하며, 보조 기술로 콘텐츠를 탐색하는 방법 등을 살펴봅니다.

    챕터

    • 0:00 - Welcome
    • 0:44 - Layout
    • 7:48 - Navigation
    • 9:52 - Interaction

    리소스

    • Accessibility
    • Human Interface Guidelines: Accessibility
      • HD 비디오
      • SD 비디오

    관련 비디오

    WWDC24

    • SwiftUI의 손쉬운 사용 관련 업데이트

    WWDC21

    • SwiftUI Accessibility: Beyond the basics
  • 비디오 검색…

    Hello, I’m Nicholas, an engineer on the Accessibility team. Accessibility empowers everyone to experience and love the apps that you create.

    Today I’m going to go beyond the basics to explore how you can make your Mac app more accessible. Mac apps are primarily designed for keyboard and mouse interactions with denser user interfaces and powerful multitasking. These Mac-specific qualities bring important accessibility considerations that I will go over today.

    This includes representing your app’s layout to accessibility, accelerating navigation in your app, and making interactions in your app more accessible.

    On Mac, your app has a lot of space to display controls and content. Just as you visually lay out your interface to be understandable and intuitive, it is important to think about the way that this is conveyed to accessibility technologies. SwiftUI conveys the individual views that make up your app as accessibility elements.

    Accessibility elements contain the information that is needed for accessibility technologies to understand and interact with your app. If you are not familiar with accessibility elements, I recommend checking out Catch Up on Accessibility in SwiftUI from WWDC 2024. I have been building a new Mac app in SwiftUI to edit text documents.

    There’s a sidebar where I can switch pages and mark the important ones with bookmarks.

    There’s also an inspector with controls I can use to format selected text, including a list of style presets that I can use to apply multiple formatting options at once.

    I really want this to be a great Mac app, and I know that means making it accessible to everyone. So from the beginning, I’ve been doing the accessibility basics and testing new features I add with VoiceOver.

    As a reminder, VoiceOver is a screen reader that enables people with varying levels of vision to use your app.

    VoiceOver allows the interface of your app to be heard as speech.

    VoiceOver on accessible text editor. Or felt as braille. Using VoiceOver is also a fantastic way to test the accessibility of your app because it makes full use of all the accessibility information your app provides. If your app works well with VoiceOver, you are well on the way to having a great experience with other accessibility technologies like Voice Control and Switch Control.

    On Mac, VoiceOver is primarily controlled by keyboard shortcuts. For example, there are keyboard shortcuts to move to the next and previous element on screen. Using these keyboard shortcuts, I can move the VoiceOver focus by one element at a time to hear a description of it.

    Minimize, button, full screen, button, toolbar, my text document, sidebar, table, vertical splitter, edit text, insertion at end of text, vertical splitter, format inspector, scroll area. What may take a quick mouse movement across the screen could take someone who uses VoiceOver many key presses.

    Behind the scenes, VoiceOver is moving to the next accessibility element provided by SwiftUI.

    To make navigation faster with VoiceOver, SwiftUI can group accessibility elements into a container accessibility elements.

    keyboard shortcuts to focus in and out of these containers. By default on Mac, VoiceOver navigates by container so that it is quicker to move across your app and only focus into a container when needed.

    A key difference with accessibility on Mac from other platforms like iPhone and iPad is that containers on Mac often contain nested containers. This creates a tree-like structure of accessibility elements representing your app’s interface. In your app, group related elements into containers, to make navigation quicker with VoiceOver.

    At the same time, be mindful of creating too many levels of nested containers.

    Sometimes this can make it harder to find elements in your app and adds time spent repeatedly focusing into containers.

    To refine containers in your app, use the accessibility element children modifier.

    When you apply the modifier to a view, the supplied behavior determines how the view and its subviews are represented to accessibility.

    There are three different behavior options.

    Contain will represent the view as an accessibility container where the subviews are the accessibility elements within it.

    Combine will represent the view and its subviews as one accessibility element that merges all their attributes and actions together. Ignore will represent the view as one accessibility element that completely ignores the subviews.

    When I was testing my app with VoiceOver, I notice a couple areas I want to revisit.

    First, I will move VoiceOver one by one through the formatting inspector on the right. In Format Inspector, scroll area, 22 items, heading styles. Title, Apply - button, Subtitle, Apply - button, Heading, Apply - button, Body, Apply - button, Bold, Toggle - button.

    I noticed I have to navigate through every single style preset before I get to the “Bold, Toggle - button”.

    These style presets are displayed using a VStack.

    I can use the accessibility element children modifier with the contain behavior on the VStack to create a container. I can also use the accessibility label modifier to give this container a name.

    Now I will once again try moving VoiceOver one by one through the formatting inspector on the right.

    In Format Inspector, Scroll Area, 15 Items, Heading Styles, Style Presets, Group, Bold, Toggle Button. This is great. I don’t need to go through every style preset unless that's what I'm looking for. I want to make sure navigating within this style presets container works. I will focus VoiceOver into the style presets container, then move VoiceOver one by one.

    In style presets, Group, eight items title, Apply, Button, Subtitle, Apply, Button, Heading, Apply, Button, Body, Apply, Button.

    This is working, but I notice that the VoiceOver focuses onto the title and the apply button of each style preset separately.

    A style preset is represented as a H stack containing a title view and a button view.

    I can use the accessibility element children modifier with the combined behavior on the age stack to create one accessibility element that merges the properties of the title view and the button view.

    Now I will once again try moving VoiceOver one by one within the style presets container. In style presets, Group. For items, Title, Apply - button. Subtitle, Apply - button. Heading, Apply - button. Body, Apply - button. I can now go through each style preset as one element. This is easier to navigate and understand.

    Another aspect of the accessibility structure you can refine is the ordering of elements. In this example, visually Book Author is before Book Title. But I want the Book Title to be read first by VoiceOver, as it is easier to quickly skim through a lot of books. I can change the order of accessibility elements using the accessibility sort priority modifier.

    If I give the book title view a higher priority, it will be sorted first. By default, views have a sort priority of zero. The views with equal priorities are then sorted based off their visual position.

    Now the book title will be spoken by VoiceOver before the author and description.

    When testing your app with VoiceOver, if the ordering doesn’t feel right, use the accessibility sort priority modifier.

    Now that the accessibility structure of my app has been refined, I want to take navigation even further with rotors.

    With the bookmarks feature in my app, someone may be able to quickly visually scan through the list of pages to see which are bookmarked. However, someone using VoiceOver would instead have to navigate over every page just to know if they have any bookmarks.

    Page 2 bookmarked. Page 3. Page 4. Page 5 bookmarked. Page 6. Page 7, Page 8 bookmarked, page 9, page 10. To make this as easy as the visual experience, someone using VoiceOver needs the ability to navigate by only bookmarked pages.

    To do this, I can use rotors. Rotors are an essential way to accelerate navigation for someone using VoiceOver. Rotors allow you to define collections of views or text ranges in your app that can be quickly moved between. To add a rotor of bookmarks to my pages list, I will use the accessibility rotor modifier, giving it the name Bookmarks. I can conditionally declare which of my pages I want included in the Bookmarks rotor.

    Now when I focus VoiceOver on the Pages list in the sidebar, I can open the rotor menu with a keyboard shortcut, where I can go through all of my bookmarks quickly and jump right to the bookmark page I want. Bookmarks menu.

    Page 2. Page 5. Page 5 bookmarked.

    Accessibility routers make what would have been time-consuming or complex navigation for someone using VoiceOver into a great experience.

    When I navigate around my app with VoiceOver, I’m moving what’s called the VoiceOver focus. Accessibility technologies like VoiceOver maintain their own focus state separate from keyboard focus.

    In macOS and iOS 26, your app can suggest an initial focus for accessibility technologies like VoiceOver using the accessibility default focus modifier. When a new scene appears, SwiftUI will suggest the view with the modifier become focused, while still allowing the accessibility technology to make the best decision based on someone’s preferences.

    Now that navigating to all the elements in my app is a breeze, I want to make sure that I can easily interact with them as well.

    In my app, I added the ability to bookmark a page with a button that appears when I hover the pointer over a page thumbnail. Visually, this is nice as the thumbnails are not obstructed when I don't need the button. However, since someone using VoiceOver isn’t moving the pointer, they would never be able to access the button.

    In your app, any interaction that requires hovering the pointer or performing a trackpad gesture may not be accessible to everyone.

    You should provide other ways of discovering and performing these interactions.

    Fortunately, SwiftUI provides an easy way to do this. You can add accessibility actions to a view that accessibility technologies like VoiceOver can perform in a way that is accessible. To add an accessibility action to a view, use the accessibility action modifier. I use this modifier to add a bookmark action to the views in my pages list. It's as simple as adding a button.

    Now I will use VoiceOver to focus on a page thumbnail and use my new bookmark accessibility action. Page 3. Actions menu. Two items. Show alternate items. Bookmark page 3. Bookmark page 3.

    I was able to open the Actions menu with a keyboard shortcut and easily bookmark the page. Other accessibility technologies like Switch Control and Voice Control also rely on these accessibility actions.

    Another quick way to improve interaction with your app is keyboard shortcuts.

    Adding keyboard shortcuts for common tasks in your app is not only a great power user feature, it also has a huge impact on accessibility, especially for anyone who may not be able to use a mouse. Lastly, if you create your own custom controls, they may not have the accessibility information that other controls have built in.

    To learn how to easily make controls accessible in SwiftUI, I recommend checking out “SwiftUI Accessibility: Beyond the basics” from WWDC 2021.

    Now it’s your turn to try your app with VoiceOver on Mac, refine the containers in your app, and investigate where you can add custom rotors. And finally, you can showcase the great accessibility of your app with accessibility nutrition labels. To learn more, check out “Evaluate your app for Accessibility Nutrition Labels”. Thank you for watching.

    • 4:15 - Contain subviews within accessibility container

      // Contain subviews within accessibility container
      
      import SwiftUI
      
      struct ContentView: View {
        var body: some View {
          VStack {
            FirstView()
            SecondView()
          }
          .accessibilityElement(children: .contain)
        }
      }
    • 4:23 - Combine subviews into one accessibility element

      // Combine subviews into one accessibility element
      
      import SwiftUI
      
      struct ContentView: View {
        var body: some View {
          VStack {
            FirstView()
            SecondView()
          }
          .accessibilityElement(children: .combine)
        }
      }
    • 4:33 - Hide subviews from accessibility

      // Hide subviews from accessibility
      
      import SwiftUI
      
      struct ContentView: View {
        var body: some View {
          VStack {
            FirstView()
            SecondView()
          }
          .accessibilityElement(children: .ignore)
        }
      }
    • 5:12 - Contain style presets in accessibility container

      // Contain style presets in accessibility container
      
      import SwiftUI
      
      struct FormattingInspectorView: View {
        var body: some View {
          Form {
            VStack {
              StylePresetView(type: .title)
              StylePresetView(type: .heading)
              StylePresetView(type: .subHeading)
              StylePresetView(type: .body)
            }
            .accessibilityElement(children: .contain)
            .accessibilityLabel("Style Presets")
          }
        }
      }
    • 6:21 - Merge Title View and Button into one accessibility element

      // Merge Title View and Button into one accessibility element
      
      import SwiftUI
      
      struct StylePresetView: View {
        let preset: StylePreset
        
        var body: some View {
          HStack {
            PresetTitleView(preset: preset)
            Button("Apply") { /* ... */ }
          }
          .accessibilityElement(children: .combine)
        }
      }
    • 7:01 - Set the order of accessibility elements

      // Set the order of accessibility elements
      
      import SwiftUI
      
      struct BookDetailsView: View {
        let book: Book
      
        var body: some View {
          VStack {
            Text(book.author)
            Text(book.title)
              .accessibilitySortPriority(1)
            DescriptionView(book: book)
          }
          .accessibilityElement(children: .combine)
        }
      }
    • 8:43 - Add an accessibility rotor for bookmarked pages

      // Add an accessibility rotor for bookmarked pages
      
      import SwiftUI
      
      struct PagesView: View {
        @Binding var pages: [Page]
        
        var body: some View {
          List(pages) { page in
            PageListItemView(page: page)
          }
          .accessibilityRotor("Bookmarks") {
            ForEach(pages) { page in
              if page.isBookmarked {
                AccessibilityRotorEntry(page.title, id: page.id)
              }
            }
          }
        }
      }
    • 9:33 - Set the default VoiceOver focus

      // Set the default VoiceOver focus
      
      struct MyView: View {
        @AccessibilityFocusState(for: .voiceOver) var focusedForVoiceOver
      
        var body: some View {
          FirstView()
          SecondView()
            .accessibilityDefaultFocus($focusedForVoiceOver, true)
          ThirdView()
        }
      }
    • 10:28 - Add an accessibility action to bookmark the page

      // Add an accessibility action to bookmark the page
      
      import SwiftUI
      
      struct PageListItemView: View {
        var page: Page
        
        var body: some View {
          VStack() {
            ThumbnailView(page: page)
            Text(page.title)
          }
          .onHover { /* ... */ }
          .accessibilityAction(named: page.isBookmarked ? "Remove Bookmark" : "Bookmark") {
            page.isBookmarked.toggle()
          }
        }
      }
    • 0:00 - Welcome
    • Learn about enhancing Mac app accessibility. Discover best practices for layout representation, navigation acceleration, and interaction accessibility to ensure everyone can enjoy Mac apps.

    • 0:44 - Layout
    • SwiftUI on macOS lets you make your apps accessible to everyone, particularly those who rely on VoiceOver. SwiftUI creates accessibility elements from views, but you should refine this structure for optimal navigation. Key aspects of macOS accessibility include grouping related elements into containers to create a tree-like structure, which speeds up navigation. You can use modifiers like 'accessibilityElement(children:)' to specify how views and their subviews are represented — as containers, combined elements, or ignored. For example, in Nicholas's text editor app, improvements in the formatting inspector are made by grouping style presets and combining title and apply buttons into single elements. Additionally, use the 'accessibilitySortPriority' modifier to reorder elements, ensuring that more important information is read first.

    • 7:48 - Navigation
    • The example app's accessibility is enhanced with rotors, a VoiceOver feature that allows someone to quickly jump between specific content, such as bookmarked pages. This streamlines navigation, making it as efficient for people using VoiceOver. A new modifier in SwiftUI can suggest initial focus points.

    • 9:52 - Interaction
    • In SwiftUI apps, ensure all interactions are accessible beyond pointer-based methods. Use accessibility actions and keyboard shortcuts for people using VoiceOver, Switch Control, and Voice Control.

Developer Footer

  • 비디오
  • WWDC25
  • 모든 사람이 Mac 앱을 더 손쉽게 사용하도록 만들기
  • 메뉴 열기 메뉴 닫기
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    메뉴 열기 메뉴 닫기
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    메뉴 열기 메뉴 닫기
    • 손쉬운 사용
    • 액세서리
    • 앱 확장 프로그램
    • App Store
    • 오디오 및 비디오(영문)
    • 증강 현실
    • 디자인
    • 배포
    • 교육
    • 서체(영문)
    • 게임
    • 건강 및 피트니스
    • 앱 내 구입
    • 현지화
    • 지도 및 위치
    • 머신 러닝
    • 오픈 소스(영문)
    • 보안
    • Safari 및 웹(영문)
    메뉴 열기 메뉴 닫기
    • 문서(영문)
    • 튜토리얼
    • 다운로드(영문)
    • 포럼(영문)
    • 비디오
    메뉴 열기 메뉴 닫기
    • 지원 문서
    • 문의하기
    • 버그 보고
    • 시스템 상태(영문)
    메뉴 열기 메뉴 닫기
    • Apple Developer
    • App Store Connect
    • 인증서, 식별자 및 프로파일(영문)
    • 피드백 지원
    메뉴 열기 메뉴 닫기
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(영문)
    • News Partner Program(영문)
    • Video Partner Program(영문)
    • Security Bounty Program(영문)
    • Security Research Device Program(영문)
    메뉴 열기 메뉴 닫기
    • Apple과의 만남
    • Apple Developer Center
    • App Store 어워드(영문)
    • Apple 디자인 어워드
    • Apple Developer Academy(영문)
    • WWDC
    Apple Developer 앱 받기
    Copyright © 2025 Apple Inc. 모든 권리 보유.
    약관 개인정보 처리방침 계약 및 지침