CSS 공간 탐색 레벨 1

W3C 워킹 드래프트 2019년 11월 26일

이 버전:
https://www.w3.org/TR/2019/WD-css-nav-1-20191126/
최신 공개 버전:
https://www.w3.org/TR/css-nav-1/
에디터스 드래프트:
https://drafts.csswg.org/css-nav-1/
이전 버전:
이슈 추적:
명세 내 인라인
GitHub 이슈
에디터:
(LG전자)
Florian Rivoal (초청 전문가)
이 명세에 대한 편집 제안:
GitHub 편집기

요약

이 명세서는 화살표 키를 사용하여 포커스를 탐색하는 일반적인 모델과 관련된 CSS, JavaScript 기능 및 이벤트를 정의합니다.

CSS는 구조화된 문서(HTML 및 XML 등)를 화면, 종이 등에서 렌더링하는 방법을 기술하는 언어입니다.

이 문서의 상태

이 섹션은 문서가 공개된 시점의 상태를 설명합니다. 다른 문서가 이 문서를 대체할 수 있습니다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 개정판은 https://www.w3.org/TR/의 W3C 기술 보고서 인덱스에서 확인할 수 있습니다.

워킹 드래프트로 게시된다고 해서 W3C 회원의 승인이나 지지를 의미하지는 않습니다. 이 문서는 초안이며 언제든지 업데이트, 교체 또는 폐기될 수 있습니다. 진행 중인 작업 외의 다른 용도로 이 문서를 인용하는 것은 적절하지 않습니다.

GitHub 이슈에서 이 명세에 대한 논의가 권장됩니다. 이슈를 등록할 때 제목에 “css-nav”라는 텍스트를 포함해 주세요. 예시: “[css-nav] …코멘트 요약…”. 모든 이슈와 코멘트는 아카이브에 저장되며, 역사적 아카이브도 있습니다.

이 문서는 CSS 워킹 그룹에서 제작되었습니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 제작되었습니다. W3C는 그룹 산출물과 관련된 공개 특허 공개 목록을 관리합니다. 해당 페이지에는 특허 공개 방법도 안내되어 있습니다. 개인이 본인이 보유한 특허가 필수 청구항을 포함한다고 판단하는 경우 W3C 특허 정책 6항에 따라 정보를 공개해야 합니다.

이 문서는 2019년 3월 1일 W3C 프로세스 문서를 따릅니다.

다음 기능들은 위험에 처해 있으며, CR 기간 동안 제외될 수 있습니다:

“위험(at-risk)”은 W3C 프로세스의 용어이며, 기능이 실제로 제외되거나 지연될 위험이 있다는 뜻은 아닙니다. 해당 기능이 WG에서 상호 운용성 있게 적시에 구현되기 어려울 수 있다고 판단된 경우 표시되며, 필요시 제안된 권고(Proposed Rec) 단계로 전환할 때 새 기능 없이도 기능을 제외할 수 있도록 합니다.

이 명세서는 다소 깁니다. 읽기 쉽고 특정 영역에 집중할 수 있도록, 아래에 몇 개의 체크박스를 제공합니다. 체크하면 명세의 일부가 숨겨집니다. 이는 단순히 읽기 보조 도구로 제공된 것이며, 명세 자체는 전체 문서로 남아 있습니다.




1. 소개

이 섹션은 규범적이지 않습니다.

역사적으로 대부분의 브라우저는 사용자가 포커스를 방향적으로 이동할 수 있는 기능을 제공하지 않았습니다. TV 브라우저와 같은 일부 브라우저는 사용자가 화살표 키로 포커스를 이동할 수 있도록 했는데, 이는 일반적인 TV 리모컨에 다른 입력 장치가 없기 때문입니다.

다른 브라우저들은 Shift 키와 화살표 키를 함께 누르는 등 다양한 키 조합으로 공간 탐색을 제어할 수 있도록 했습니다.

이렇게 페이지를 방향적으로 이동하는 기능을 공간 탐색이라고 합니다.

공간 탐색은 그리드와 같은 레이아웃이나 주로 비선형 레이아웃으로 구성된 웹 페이지에서 유용하게 사용할 수 있습니다. 아래 그림은 그리드 레이아웃으로 배치된 포토 갤러리의 예시입니다. 사용자가 Tab 키로 이미지를 이동할 때, 원하는 이미지 요소에 도달하려면 키를 여러 번 눌러야 합니다.

요소가 그리드 패턴으로 배치된 경우, 공간 탐색을 통해 포커스가 어디로 이동할지 쉽게 예측하고 제어할 수 있습니다.
그리드 레이아웃을 활용한 포토 갤러리 애플리케이션 예시

또한 공간 탐색은 포커스 가능한 요소들 사이에서 위치에 따라 포커스를 이동하므로 사용자가 예측 가능한 요소로 포커스를 이동할 수 있습니다. 때로는 페이지의 요소가 소스 순서와 관계없이 배치되어 있습니다. 따라서 공간 탐색과 달리, Tab 키를 사용하는 순차적 탐색은 포커스 이동이 예측 불가능해집니다.

화살표 키는 공간 탐색을 제어하기에 자연스럽지만, 이전 명세에서는 그 동작 방식이나 제어 방법을 정의하지 않았습니다. 이 명세서는 공간 탐색을 위한 처리 모델과 공간 탐색의 동작 방법을 저자가 제어 및 오버라이드할 수 있는 API를 소개합니다.

참고: 이 명세의 일부(예: 자바스크립트 이벤트 및 API)는 순차 탐색에도 확장될 수 있으며, 키보드 탐색이 일관되고 명확한 모델을 갖도록 하는 데 도움이 됩니다.

참고: 일반 원칙으로, 키보드 탐색, 특히 공간 탐색은 자바스크립트 없이도 사용할 수 있고 제어 가능해야 합니다. 따라서 선언적 솔루션이 권장됩니다. 공간 탐색은 레이아웃에 따라 달라지므로, CSS가 공간 탐색 관련 제어를 정의하는 데 적합한 메커니즘입니다. 하지만 Extensible Web Manifesto [EXTENSIBLE]의 취지를 반영하여, 저자가 문제 영역을 실험하고 탐구할 수 있도록 적절한 자바스크립트 프리미티브를 제공하는 것이 중요하다고 생각합니다. 이후 자바스크립트 사용을 통한 피드백과 경험을 바탕으로 더 많은 선언적 기능이 추가될 수도 있습니다.

참고: 일부 기능은 위험(at-risk)으로 표시되어 있습니다. 이 명세의 에디터들은 해당 기능들이 명세에서 정의한 기능의 사용자 또는 저자 경험에 중요한 부분이라고 생각합니다. 동시에 명세의 핵심 기능은 이 기능들을 구현하지 않아도 가능하므로, 구현자는 첫 번째 구현 범위를 줄이기 위해 우선순위를 낮출 수도 있습니다. 이러한 기능들이 구현되기를 바라지만, 우선적으로 구현되지 않을 수 있음을 인정하며 위험으로 표시하였습니다.

2. 모듈 상호작용

이 문서는 Infra Standard [infra]에 의존합니다.

"MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", "OPTIONAL" 등의 키워드는 RFC 2119에서 설명한 대로 해석되어야 합니다. [RFC2119]

3. 개요

이 섹션은 규범적이지 않습니다.

UA에서 정의한 메커니즘 (일반적으로 화살표 키, 필요에 따라 ShiftControl과 같은 수정 키 조합) 을 이용해 사용자는 User Agent에 특정 방향으로 탐색을 요청할 수 있습니다. 이 요청은 현재 위치에서 지정된 방향의 새 포커스 가능 항목으로 포커스를 이동시키거나, 적절한 항목이 없으면 스크롤합니다.

좀 더 구체적으로, User Agent는 우선 현재 공간 탐색 컨테이너 내에서 지정된 방향의 보이고 포커스 가능한 항목을 찾습니다(기본적으로 루트 요소, 스크롤 가능한 요소, iframe, 또는 공간 탐색 컨테이너로 만들 수 있는 다른 요소들은 spatial-navigation-contain 속성으로 지정할 수 있습니다).

찾은 경우, 해당 방향에 가장 적합한 항목을 선택하여 포커스를 이동시킵니다.

찾지 못하면, 공간 탐색 컨테이너를 요청된 방향으로 스크롤하며 포커스를 이동하지 않습니다. 그렇게 하면 포커스 가능한 요소가 나타나 다음에 같은 방향으로 공간 탐색을 요청할 때 포커스 이동 대상이 될 수 있습니다.

공간 탐색 컨테이너가 스크롤 불가능할 경우, 예를 들어 해당 요소가 스크롤 가능한 요소가 아니거나 이미 해당 방향으로 최대치까지 스크롤된 경우, User Agent는 상위 컨테이너(공간 탐색 컨테이너)를 선택해 위의 과정을 재귀적으로 반복합니다. 포커스 또는 스크롤할 요소를 찾거나 루트 요소에 도달할 때까지 반복합니다.

참고: 이 처리 모델의 결과로 순차 탐색과 공간 탐색 모두에서 접근 가능한 요소는 거의 동일합니다. 스크롤 가능한 요소의 뷰포트 밖에 있는 요소는 해당 요소가 뷰 안에 들어와야만 공간 탐색으로 접근할 수 있습니다. 따라서 기본적으로 스크롤로 뷰에 들어올 수 없는 요소는 접근할 수 없습니다.

공간 탐색 요청에 적합한 응답을 찾는 과정에서 User Agent는 주요 위치마다 이벤트를 발생시킵니다. 저자는 preventDefault()를 호출하여 예정된 동작을 방지하거나, 원한다면 focus() 메서드를 활용해 원하는 다른 요소에 포커스를 줄 수도 있습니다.

저자가 이러한 대체 동작을 작성할 수 있도록 돕고, Extensible Web 원칙에 따라 기본 플랫폼 프리미티브를 노출하기 위해, 이 명세는 기본 모델의 핵심 개념을 노출하는 자바스크립트 API도 정의합니다.

자바스크립트 API에 대한 자세한 내용은 § 5 JavaScript API, 다양한 이벤트에 대한 내용은 § 6.2 Navigation Event Types, CSS 속성에 대한 내용은 § 9 선언적 방법을 통한 공간 탐색 제어를 참고하세요.

이 예시는 스크롤 가능한 요소 내에 배치된 일련의 포커스 가능한 요소들이 공간 탐색으로 어떻게 이동되는지 보여줍니다. 설명을 단순하게 하기 위해, 이 예시는 화살표 키로 공간 탐색이 트리거되는 User Agent를 가정합니다.
공간 탐색 컨테이너 내의 보이는 요소로 포커스 이동

그림 2의 좌측에서 "Box 2"가 포커스되어 있습니다. ArrowDown 키를 누르면 "Box 3"이 scrollport 내에 보이기 때문에 스크롤 없이 "Box 3"으로 포커스가 이동합니다.

공간 탐색 컨테이너 내의 숨겨진 요소로 포커스 이동

그림 3의 첫 번째에서 "Box 3" 아래에는 scrollport 내에 보이는 요소가 없습니다. 따라서 ArrowDown 키를 누르면 두 번째 그림처럼 아래로 스크롤됩니다. ArrowDown 키를 다시 누르면 "Box 4"가 scrollport에 들어오고, 추가로 ArrowDown 키를 누르면 네 번째 그림과 같이 포커스가 이동합니다.

이 예제의 마크업은 다음과 같습니다:

#scroller {
    width: 700px;
    height: 700px;
    overflow-x: hidden;
    overflow-y: auto;
}

.box {
    width: 150px;
    height: 110px;
    background-color: blue;
}

.box:focus {
    background-color: red;
}
<div id="scroller">
    <div class="box" tabindex="0">Box 1</div>
    <div class="box" tabindex="0">Box 2</div>
    <div class="box" tabindex="0">Box 3</div>
    <div class="box" tabindex="0">Box 4</div>
</div>

4. 공간 탐색 트리거

사용자가 특정 방향으로 공간 탐색을 트리거하면, User Agent는 해당 방향으로 공간 탐색 단계를 실행해야 합니다.

이 명세서는 User Agent가 사용자가 공간 탐색을 트리거할 수 있도록 제공해야 하는 UI 메커니즘을 정의하지 않습니다. 이는 의도적으로 User Agent의 선택에 맡겨져 있습니다.

참고: 리모컨으로 조작하는 TV, 피처폰, 게임 컨트롤러로 조작하는 기기 등 입력 기능이 제한된 기기에서의 User Agent는 공간 탐색을 주된 또는 유일한 탐색 메커니즘으로 사용할 것으로 예상됩니다.

User Agent는 명세에서 정의한 처리 모델과 API를 구현할 수 있지만, 본 명세서는 User Agent가 사용자가 직접 공간 탐색을 트리거할 수 있는 수단을 제공할 것을 권장합니다. API를 반드시 사용하지 않아도 됩니다.

참고: 반대로, 저자는 User Agent가 사용자 동작에 응답해 공간 탐색을 트리거할 수 있음을 가정해야 하며, 저자가 어떤 API도 호출하지 않은 경우에도 발생할 수 있습니다.

공간 탐색을 트리거하기 위해 선택된 실제 메커니즘과 관계없이, 아래 요구사항이 적용됩니다:

5. 자바스크립트 API

5.1. 프로그래밍 방식으로 탐색 트리거

navigate() 메서드는 저자가 프로그래밍 방식으로 공간 탐색을 트리거할 수 있게 해줍니다. 사용자가 직접(예: 브라우저에서 화살표 키를 눌러 공간 탐색을 트리거하는 방식 등) 실행한 것처럼 동작합니다.

참고: 이 메서드는 수동 탐색과 동일한 처리 모델을 트리거하므로 동일한 결과가 예상됩니다: 동일한 이벤트 체인이 발생하고 동일한 요소가 스크롤 또는 포커스됩니다.

참고: 저자는 User Agent가 지정한 것과 다른 UI 메커니즘에 매핑하거나, 클릭 가능한 화면 내 방향 패드 등에서 공간 탐색을 트리거하거나, UI 이벤트가 아닌 다른 이벤트에 반응해 공간 탐색을 트리거하는 등 다양한 방식으로 사용할 수 있습니다. 저자가 비동기 작업(예: 무한 스크롤에서 콘텐츠 추가) 후 탐색을 중단하고, 다시 탐색을 이어가고자 할 때도 사용할 수 있습니다.

참고: 이 API는 테스트 목적에도 유용합니다. 벤더별 UI 관행에 의존하지 않고 공간 탐색을 트리거하는 것이 어렵기 때문입니다.

enum SpatialNavigationDirection {
    "up",
    "down",
    "left",
    "right",
};

partial interface Window {
    void navigate(SpatialNavigationDirection dir);
};
navigate(dir) 메서드가 호출되면, User Agent는 다음 단계를 실행해야 합니다:
  • 방향 dir"up", "down", "left", "right" 중 하나라면, dir 방향으로 공간 탐색 단계를 실행합니다.

이 API의 이름은 논의 중입니다 <https://github.com/w3c/csswg-drafts/issues/3387>

5.2. 저수준 API

이 API들은 처리 모델을 밀접하게 따르는 저수준 구성요소로 설계되었습니다. 따라서 공간 탐색의 동작 방식을 확장하거나 오버라이드하고자 하는 저자가 쉽게 사용할 수 있어야 합니다.

enum FocusableAreaSearchMode {
    "visible",
    "all"
};

dictionary FocusableAreasOption {
    FocusableAreaSearchMode mode;
};

dictionary SpatialNavigationSearchOptions {
    sequence<Node>? candidates;
    Node? container;
};

partial interface Element {
    Node getSpatialNavigationContainer();
    sequence<Node> focusableAreas(optional FocusableAreasOption option);
    Node? spatialNavigationSearch(SpatialNavigationDirection dir, optional SpatialNavigationSearchOptions options);
};

참고: 방향을 표현하는 방식은 향후 필요할 경우 4방향 이상의 탐색으로 확장될 수 있도록 해줍니다. 더 많은 방향 키워드나 숫자 각도가 추가될 수 있습니다.

참고: focusableAreas()getSpatialNavigationContainer() 메서드는 위험(at-risk)입니다.

이 메서드들이 호출되면, User Agent는 아래에 설명된 단계를 실행해야 합니다:

getSpatialNavigationContainer()
  1. 요소의 가장 가까운 상위 요소 중 공간 탐색 컨테이너인 요소를 반환하거나, 가장 가까운 공간 탐색 컨테이너가 뷰포트인 경우 문서(document)를 반환합니다.

참고: 해당 요소가 공간 탐색 컨테이너인 경우, getSpatialNavigationContainer() 역시 가장 가까운 공간 탐색 컨테이너를 반환하며, 자기 자신은 반환하지 않습니다.

focusableAreas(option)
  1. option이 존재하고 그 값이 all과 같으면 visibleOnlyfalse로, 그렇지 않으면 true로 합니다.

  2. areas는 해당 요소 내에서 visibleOnly를 인자로 포커스 가능한 영역 찾기의 결과로 합니다.

  3. areas를 반환합니다.

아래 코드는 focusableAreas()를 사용해 현재 페이지에서 모든 보이는 포커스 가능한 요소를 얻는 방법을 보여줍니다. 만약 해당 메서드가 공간 탐색 컨테이너를 찾으면, 내부의 포커스 가능한 영역도 재귀적으로 찾습니다. 이 메서드의 mode 속성 값이 visible이므로, scrollport 내부에 있지 않은 포커스 가능한 요소는 결과에서 제외됩니다.
<body>
    <button></button>
    <div style="width:300px; height:200px; overflow-x: scroll;">
        <button style="left:25px;"></button>
        <button style="left:150px;"></button>
        <button style="left:350px;"></button>
    </div>
</body>
const focusableAreas = document.body.focusableAreas({mode: 'visible'});
focusableAreas && focusableAreas.forEach(focusable => {
  focusable.style.outline = '5px solid red';
});

아래 그림은 해당 코드의 결과입니다.

focusableAreas()에 관한 이미지
문서 내의 모든 보이는 포커스 가능한 영역을 찾습니다.
spatialNavigationSearch(dir, options)
  1. dir의 값을 direction으로 합니다.

  2. container는 다음과 같습니다.

  3. areas는 다음과 같습니다.

  4. 요소에서 direction 방향으로 container 내의 areas최적의 후보 선택의 결과를 반환합니다.

참고: container와 후보 리스트가 모두 없는 경우, 가장 가까운 공간 탐색 컨테이너 상위 요소의 보이는 포커스 가능한 영역만 검색합니다. 만약 없으면 상위 체인을 더 오르지 않으며, 결과는 null입니다.

6. 내비게이션 이벤트

6.1. NavigationEvent 인터페이스

NavigationEvent 인터페이스는 공간 탐색과 관련된 특정 컨텍스트 정보를 제공합니다.

NavigationEvent 인터페이스 인스턴스를 생성하려면 NavigationEvent 생성자에, 선택적으로 NavigationEventInit 딕셔너리를 넘깁니다.

[Exposed=Window]
interface NavigationEvent : UIEvent {
    constructor(DOMString type,
                optional NavigationEventInit eventInitDict);
    readonly attribute SpatialNavigationDirection dir;
    readonly attribute EventTarget? relatedTarget;
};

dictionary NavigationEventInit : UIEventInit {
    SpatialNavigationDirection dir;
    EventTarget? relatedTarget = null;
};

6.2. 내비게이션 이벤트 타입

이 섹션과 하위 섹션은 규범적이지 않습니다.

내비게이션 이벤트 타입은 아래에 요약되어 있습니다. 완전한 규범적 세부사항은 § 8 처리 모델을 참고하세요.

6.2.1. navbeforefocus

이 이벤트는 최적의 후보 선택의 결과가 유효할 때 발생합니다.

Type navbeforefocus
Interface NavigationEvent
Bubbles
Cancelable
이벤트의 속성
Event.target
포커스된 요소 또는 포커스된 요소가 없을 경우, body 요소(가능하다면), 아니면 루트 요소
NavigationEvent.relatedTarget
포커스될 포커스 가능한 영역의 DOM 앵커
NavigationEvent.dir
사용자가 요청한 탐색 방향

User Agent는 공간 탐색으로 포커스를 이동하기 전에 navbeforefocus 이벤트를 dispatch합니다. 이벤트 타겟은 포커스된 요소이며, relatedTarget 은 포커스를 받을 예정인 요소입니다.

navigation-overrideeventTarget의 노드 문서에서, active document의 origin에 대해 비활성화되어 있다면, 이 이벤트는 dispatch되지 않습니다.

이 예시는 UI Events §event-order에서 ArrowRight 키를 눌렀을 때의 동작을 보여줍니다. 설명을 간단히 하기 위해, 이 예시는 공간 탐색이 화살표 키로 트리거되는 User Agent를 가정합니다.
이벤트 타입 KeyboardEvent.key 설명
1 keydown ArrowRight 공간 탐색을 활성화할 수 있는 키여야 하며, (화살표 키 등), 아니면 공간 탐색이 활성화되지 않음
2 navbeforefocus 공간 탐색 후보가 null이 아니면 전송, 아니면 생성되지 않음
3 focusin 타겟 요소가 포커스를 받기 전에 전송
4 focus 타겟 요소가 포커스를 받은 후 전송
아래 코드는 공간 탐색 동작을 변경하여 스크롤 컨테이너에 포커스가 이동할 때, 만약 보이는 포커스 가능한 하위 요소가 하나 이상 있으면 포커스를 재귀적으로 해당 하위 요소로 자동 이동시키는 예시입니다.
document.addEventListener('navbeforefocus', e => {
    e.preventDefault();

    let nextTarget = e.relatedTarget;
    if (isSpatialNavigationContainer(nextTarget)) {
        const areas = nextTarget.focusableAreas();

        if (areas.length > 0) {
            nextTarget = nextTarget.spatialNavigationSearch(e.dir, { candidates: areas });
        }
    }
    nextTarget.focus();
});

function isSpatialNavigationContainer(element) {
    return (!element.parentElement) ||
        (element.nodeName === 'IFRAME') ||
        (isScrollContainer(element)) ||
        (isCSSSpatNavContain(element));
}

6.2.2. navnotarget

이 이벤트는 공간 탐색이 현재 공간 탐색 컨테이너 내에서 후보를 찾지 못했을 때, 가장 가까운 상위 공간 탐색 컨테이너에서 후보를 찾으려고 트리 내를 올라가기 전에 발생합니다. 공간 탐색 컨테이너가 스크롤 가능하며, 더 이상 스크롤할 수 없는 경우에도 발생합니다.

Type navnotarget
Interface NavigationEvent
Bubbles
Cancelable
이벤트의 속성
Event.target
포커스된 요소 또는 포커스된 요소가 없으면, body 요소(가능하다면), 아니면 루트 요소
NavigationEvent.relatedTarget
검색 대상이 된 공간 탐색 컨테이너
NavigationEvent.dir
사용자가 요청한 탐색 방향

User Agent는 navnotarget 이벤트를 dispatch합니다. 이 때 이벤트 타겟은 포커스된 요소이며, relatedTarget이벤트 타겟공간 탐색 컨테이너입니다.

navigation-overrideeventTarget의 노드 문서에서, active document의 origin에 대해 비활성화되어 있다면, 이 이벤트는 dispatch되지 않습니다.

이 예시는 아래 그림과 같은 상황에서 ArrowDown 키를 눌렀을 때 UI Events §event-order의 동작을 보여줍니다. 설명을 간단히 하기 위해, 이 예시는 공간 탐색이 화살표 키로 트리거되는 User Agent를 가정합니다.
navnotarget에 관한 이미지
스크롤 컨테이너 내에 후보가 없을 때 포커스 이동
이벤트 타입 이벤트 타겟 relatedTarget 설명
1 keydown #box2 N/A 공간 탐색을 활성화할 수 있는 키여야 하며, (화살표 키 등), 아니면 공간 탐색이 트리거되지 않음
2 navnotarget #box2 #scrollContainer #scrollContainer에 후보가 없고 더 이상 스크롤할 수 없으면 전송, 아니면 생성되지 않음
3 navbeforefocus #box2 #box3 #container에 후보가 null이 아니면 전송, 아니면 발생하지 않음
4 focusin #box3 #box2 타겟 요소가 포커스를 받기 전에 전송
5 focus #box3 #box2 타겟 요소가 포커스를 받은 후 전송

이 예시의 결과는 다음 그림과 같습니다:

navnotarget 결과 이미지
scrollport 내에 후보가 없고 스크롤 컨테이너가 더 이상 스크롤할 수 없을 때 포커스 이동 결과

이 예제의 마크업은 다음과 같습니다:

#container {
    width: 900px;
    height: 1400px;
}

#scrollContainer {
    width: 700px;
    height: 700px;
    overflow-x: hidden;
    overflow-y: auto;
}

.item {
    width: 150px;
    height: 110px;
    background-color: blue;
}

.item:focus {
    background-color: red;
}
<div id="container">
    <div id="scrollContainer">
        <div id="box1" class="item" tabindex="0">Box 1</div>
        <div id="box2" class="item" tabindex="0">Box 2</div>
    </div>
    <div id="box3" class="item" tabindex="0">Box 3</div>
</div>
아래 코드는 공간 탐색 동작을 변경하여, 세로로 스크롤 가능한 공간 탐색 컨테이너 내에서 포커스를 가두는 예시입니다. 요청된 방향에 포커스 가능한 요소가 더 이상 없고, 공간 탐색 컨테이너가 더 이상 스크롤할 수 없을 때, 포커스는 컨테이너 바깥으로 이동하는 대신 반대편으로 루프됩니다.

단, 순차적 탐색, 마우스 상호작용, 혹은 focus()를 통한 프로그래밍 호출로는 컨테이너 바깥으로 이동할 수 있습니다.

scrollContainer.addEventListener('navnotarget', e => {
    let nextTarget = null;
    const verticalDir = ['up', 'down'];
    const candidates = e.relatedTarget.focusableAreas({'mode': 'all'});

    // y축 방향일 때만 preventDefault
    if (verticalDir.includes(e.dir) && (candidates.length > 0)) {
        e.preventDefault();

        if (e.dir === 'down') {
            nextTarget = candidates[0];
        } else if (e.dir === 'up') {
            nextTarget = candidates[candidates.length-1];
        }
        nextTarget.focus();
    }
});

7. navigation-override 정책 제어 기능

navigation-override 정책 제어 기능은 페이지 저자가 공간 탐색 동작을 제어하거나 완전히 취소할 수 있는 메커니즘의 사용 가능성을 제어합니다.

§ 8.3 Navigation에서 더 자세히 정의한 대로, 만약 문서에서 navigation-override가 비활성화되어 있으면, 내비게이션 이벤트(§ 6 Navigation Events 참고)는 발생하지 않습니다.

참고: 이것은 악의적인 iframe이 포커스를 탈취하기 위해 이러한 이벤트를 사용하는 것을 방지하기 위한 것입니다. 공간 탐색 이전부터 저자가 사용자의 포커스 제어 능력을 방해할 수 있는 다른 메커니즘이 존재함을 인식합니다. 그럼에도, 이 공격 표면을 넓히지 않는 것이 가치 있다고 판단되며, 이미 그러한 공격이 충분히 쉽게 수행될 수 있다면 효과가 없을 수도 있습니다. 구현 또는 대응 경험을 바탕으로 한 추가 피드백을 환영합니다.

8. 처리 모델

§ 3 개요 섹션은 공간 탐색이 어떻게 동작하는지에 대해 높은 수준의 아이디어를 제공하여, 이 명세서를 읽는 이들이 개략적인 정신적 모델을 구축하는 데 도움을 줍니다. 직관적이지만 정확하지 않은 용어를 사용하고, 가독성을 위해 많은 세부사항을 생략합니다.

이 섹션은 해당하는 규범적 동작을 정의하며, 동작을 완전히 정의하는 데 필요한 만큼의 세부사항을 목표로 합니다.

8.1. 용어집

공간 탐색의 처리 모델을 설명하기 위해 다음 용어 정의가 지정되었습니다. 정의 내의 링크를 참고하면 더 많은 정보를 얻을 수 있습니다.

객체의 경계 박스는 다음과 같이 정의됩니다:

객체의 내부 영역은 다음과 같이 정의됩니다:

참고: 객체가 화면 밖에 있을 경우, 내부 영역은 가장 가까운 보이는 상위 컨테이너여야 합니다.

CSS는 "border-radius와 같은 코너 쉐이핑 속성을 고려한 테두리 박스"를 위한 용어를 가져야 합니다. <https://github.com/w3c/csswg-drafts/issues/2324>

탐색 기점은 다음 타겟을 찾기 위한 기준점입니다.

공간 탐색 시작점은 User Agent가 설정하는 다음 타겟 탐색의 기준점입니다. 초기에는 설정되지 않으며, 요소 또는 점일 수 있습니다.

참고: 예를 들어, User Agent는 사용자가 문서 내용을 클릭하면 그 위치로 설정할 수 있으며, 포커스가 이동하면(공간 탐색 또는 다른 방법으로) 설정을 해제할 수 있습니다.

User Agent가 공간 탐색 시작점순차 포커스 탐색 시작점을 모두 설정한 경우, 서로 다르게 설정하면 안 됩니다.

8.2. 요소 그룹화

공간 탐색의 처리 모델은 문서의 레이아웃과 포커스 가능한 요소의 상대적 위치를 기반으로 작동하지만, User Agent는 로컬 논리적 그룹에서 우선적으로 요소를 찾도록 요구됩니다. 그룹 내부에서 적합한 요소를 찾을 수 없을 때만 그룹 밖에서 포커스 가능한 요소를 찾도록 해야 합니다(§ 8.3 Navigation 참고).

이러한 그룹을 공간 탐색 컨테이너라고 합니다.

기본적으로, 공간 탐색 컨테이너는 다음에 의해 설정됩니다:

추가적인 공간 탐색 컨테이너spatial-navigation-contain 속성을 사용하여 생성할 수 있습니다(§ 9.1 추가 공간 탐색 컨테이너 만들기: spatial-navigation-contain 속성 참고).

공간 탐색의 처리 모델은 공간 탐색이 일반적으로 어떻게 동작하는지 설명합니다.

공간 탐색 처리 모델 개요
이 그림은 규범적이지 않습니다. 이 섹션에서 더 자세히 정의된 처리 모델의 개요를 제공합니다. spatial-navigation-action 속성이 초기값 auto일 때를 가정합니다.
공간 탐색 단계direction 방향으로 실행하려면 다음을 수행합니다:
  1. searchOrigin탐색 기점 설정의 결과로 합니다.

    • searchOrigin노드라면, eventTargetsearchOrigin으로 합니다.

    • 그 외(assert: searchOrigin이 위치일 경우) eventTargetsearchOrigin을 포함하는 노드로 합니다.

  2. eventTargetDocument문서 요소(document element)라면, eventTargetbody 요소로(만약 null이 아니면), 아니면 문서 요소로 설정합니다.

  3. containereventTarget의 가장 가까운 상위 공간 탐색 컨테이너로 합니다.

  4. Loop: candidates포커스 가능한 영역 찾기의 결과로, container 내에서 visibleOnlyfalse로 설정하여 구합니다. 만약 spatial-navigation-action 속성의 계산값이 focus이면 false, 아니면 true, eventTarget을 제외합니다.

  5. candidates가 비어 있으면:

  6. spatial-navigation-action 속성의 계산값이 focus가 아니고, container스크롤 컨테이너이며 수동 스크롤 가능하다면, 해당 요소를 방향 기반으로 스크롤 containerdirection 방향으로 실행하고 반환합니다.
  7. 그 외,
    1. navnotarget 이벤트 발생eventTarget에서 directioncontainer로 실행합니다.

  8. bestCandidate최적의 후보 선택의 결과로, candidates 내에서 direction 방향으로 eventTarget을 기준으로 구합니다.

  9. navbeforefocus 이벤트 발생eventTarget에서 directionbestCandidate로 실행합니다.

  10. 포커스 단계bestCandidate에 실행하고 반환합니다.

8.4. 포커스 탐색 휴리스틱

참고: 다음 알고리즘은 Chrome의 구현과 옛 WICD 명세에서 영감을 받았습니다. 더 나은 접근 방식이나 개선점을 발견한 구현자는 적극적으로 피드백을 제공하여 이 명세의 상호 운용성을 극대화하는 데 도움을 주시길 바랍니다. 특히, User Agent가 포커스 가능한 영역 찾기 방식이 서로 다르면 일부 요소가 어떤 User Agent에서는 포커스 가능하지만 다른 곳에서는 불가능한 문제가 발생하여, 사용자에게 좋지 않을 수 있습니다.

이 섹션의 모든 기하 연산은 CSS 레이아웃의 결과에 대해 동작하도록 정의되며, 상대 위치 지정이나 [CSS-TRANSFORMS-1]과 같은 모든 그래픽 변환을 포함합니다.

탐색 기점 설정을 위해, 다음 단계를 실행합니다:

  1. searchOriginDOM 앵커최상위 브라우징 컨텍스트의 현재 포커스된 영역으로 합니다.

  2. 공간 탐색 시작점null이 아니고 searchOrigin 내부에 있으면, 그 값을 반환합니다.

  3. 그렇지 않으면 searchOrigin을 반환합니다.

만약 focus target의 상태가 포커스 이동이 아닌 이유로 변경되었다면, 탐색 기점 업데이트를 다음과 같이 수행합니다:

  1. focus target실제로 비활성화되거나 명시적으로 inert되었거나 렌더링되지 않음이라면, searchOriginfocus target경계 박스로 합니다.

  2. focus target제거됨이면, searchOriginfocus target이 존재했을 때 위치의 경계 박스로 합니다.

  3. focus target이 완전히 화면 밖에 있다면, searchOriginfocus target의 가장 가까운 보이는 공간 탐색 컨테이너의 뷰포트로 합니다.

참고: User Agent는 예를 들어, 포커스된 요소가 마우스 스크롤로 뷰포트 밖으로 나가거나 사라진 경우 탐색 기점 업데이트를 해야 합니다.

포커스 가능한 영역 찾기를 포함 요소 C 내에서, true를 기본값으로 하는 선택적 visibleOnly 인자와 함께 실행하려면 다음 단계를 수행합니다:

  1. focusablesC의 자손인 포커스 가능한 영역DOM 앵커집합(set)으로 합니다. 박스가 여러 박스 조각을 가지는 경우, 각 박스 조각을 별도로 취급합니다.

  2. User Agent는 focusables에서 DOM 앵커tabindex 속성이 음수로 설정된 항목을 제거해야 합니다.

    참고: 이는 순차 포커스 탐색 순서에서 음수 tabindex를 가진 요소를 제외하는 tabindex 규정과 맞추기 위한 "SHOULD"입니다.

  3. visibleOnlyfalse이면, focusables을 반환합니다.

    참고: focusables가 비어있을 수 있습니다

  4. visiblesfocusables경계 박스C내부 영역에 일부라도 포함되어 있는 항목의 부분집합으로 합니다.

    스크롤러의 현재 보이지 않는 부분에 있는 요소를 제외하면, 공간 탐색은 클릭할 수 없는 요소(예: 다른 요소에 의해 가려진 경우)를 자동으로 제외하지 않습니다. 사용자가 실질적으로 포커스하고 활성화할 때 애플리케이션 로직의 가정을 깨뜨리거나, 사용자에게 보이지 않거나 접근 불가능한 요소에 포커스가 이동해 혼란을 줄 수 있으므로, 저자는 tab-index="-1" 또는 inert 속성 등 순차 탐색과 동일한 모범 사례로 공간 탐색에서도 이런 요소들을 접근 불가로 만드는 것이 좋습니다.
  5. visibles을 반환합니다.

    참고: visibles가 비어있을 수 있습니다

최적의 후보 선택집합(set) candidates에서, 방향 dirsearchOrigin을 기준으로 실행하려면 다음 단계를 수행합니다:

  1. candidates비어있으면 null을 반환합니다.

  2. candidates에 단일 항목만 있으면 그 항목을 반환합니다.

  3. insiderscandidates의 부분집합으로 합니다.

    • 경계 박스가 searchOrigin내부 영역과 완전히 겹치는 항목

    • 경계 박스가 searchOrigin내부 영역과 부분적으로 겹치는 항목으로서

      • 위쪽 에지가 dirdown일 때 searchOrigin경계 박스의 위쪽 에지보다 아래에 있음

      • 아래쪽 에지가 dirup일 때 searchOrigin경계 박스의 아래쪽 에지보다 위에 있음

      • 오른쪽 에지가 dirleft일 때 searchOrigin경계 박스의 오른쪽 에지 왼쪽에 있음

      • 왼쪽 에지가 dirright일 때 searchOrigin경계 박스의 왼쪽 에지 오른쪽에 있음

      참고: 요소가 탐색 기점과 어떻게 겹치는지 더 상세한 조건은 포커스 이동 순서에 영향을 주며, 포커스 이동 순서는 UX와 관련이 있으므로 UA 정의 메커니즘에 따라 달라집니다.

    참고: 이 부분집합 설정은 요청한 방향과 반대 방향으로 이동하는 것을 방지하기 위해 필요합니다.

    • insiders가 비어있지 않으면,

      1. closest subsetinsiders 중에서 경계 박스

        • 위쪽 에지가 dirdown일 때 내부 영역의 위쪽 에지와 가장 가까운 항목

        • 아래쪽 에지가 dirup일 때 내부 영역의 아래쪽 에지와 가장 가까운 항목

        • 오른쪽 에지가 dirleft일 때 내부 영역의 오른쪽 에지와 가장 가까운 항목

        • 왼쪽 에지가 dirright일 때 내부 영역의 왼쪽 에지와 가장 가까운 항목

      2. closest subset이 단일 항목이면 그 항목을 반환하고, 아니면 closest subset의 첫 번째 항목을 문서 순서대로 반환합니다. 단, 그 경계 박스가 다른 항목의 경계 박스와 겹치고 그 항목이 CSS 페인팅 순서상 더 위에 있다면, 그 항목을 반환합니다(더 위 항목이 또 겹치는 경우 재귀적으로 적용).

    • 그 외

      1. candidates를 다음 조건 중 하나를 만족하는 항목의 부분집합으로 설정합니다:

        • 해당 항목이 searchOrigin과 겹치지 않고, 경계 박스

          • 위쪽 에지가 dirdown일 때 searchOrigin경계 박스의 아래쪽 에지 아래에 위치

          • 아래쪽 에지가 dirup일 때 searchOrigin경계 박스의 위쪽 에지 위에 위치

          • 오른쪽 에지가 dirleft일 때 searchOrigin경계 박스의 왼쪽 에지 왼쪽에 위치

          • 왼쪽 에지가 dirright일 때 searchOrigin경계 박스의 오른쪽 에지 오른쪽에 위치

      2. candidates의 각 candidate에 대해 최단 거리 찾기searchOrigin과 계산합니다.

      3. candidates 집합에서 최단 거리를 가진 항목을 반환합니다. 여러 항목이 동일 거리라면, 문서 순서의 첫 번째 항목을 반환합니다. 단, 그 경계 박스가 동일 거리의 다른 항목의 경계 박스와 겹치고 그 항목이 CSS 페인팅 순서상 더 위에 있다면, 그 항목을 반환합니다(더 위 항목이 또 겹치는 경우 재귀적으로 적용).

최단 거리 찾기referencecandidate 사이, 방향 dir에서 구하려면, 각각 referencecandidate의 경계 박스 내에서 P1P2를 찾아, 아래와 같이 정의된 distance를 최소화합니다:
distance = euclidean + displacement - alignment - sqrt(Overlap)

각 용어의 의미는 다음과 같습니다:

euclidean
P1P2 사이의 유클리드 거리
displacement
referencecandidate 사이 dir에서의 변위 정도. 아래와 같이 정의됨:
displacement = (dir에 직교하는 축에서 P1P2 사이의 절대 거리 +
                orthogonalBias) *
               orthogonalWeight
orthogonalBias:
  • dirleft 또는 right면, reference의 축에 정렬된 바운딩 박스의 높이 / 2

  • 그 외 dirup 또는 down면, reference의 축에 정렬된 바운딩 박스의 너비 / 2

orthogonalWeight:
alignment
referencecandidate 사이 dir에서의 정렬 정도. 아래와 같이 정의됨:
alignment = alignBias * alignWeight
alignBias:
  • dirleft 또는 right면, projectedOverlap / reference의 축에 정렬된 바운딩 박스의 높이

  • 그 외 dirup 또는 down면, projectedOverlap / reference의 축에 정렬된 바운딩 박스의 너비

projectedOverlap:
  • dirleft 또는 right면, referencecandidate의 수직축에 수평 투영된 부분의 겹치는 길이

  • 그 외 dirup 또는 down면, referencecandidate의 수평축에 수직 투영된 부분의 겹치는 길이

projectedOverlap
alignWeight:
5
sqrt(Overlap)
referencecandidate 사이의 겹친 영역의 제곱근 값, 겹치지 않으면 0

참고: 이 일반 공식은 여러 가능한 대안 중에서 직관적으로 가장 자주 맞는 결과를 주는 공식을 UX 테스트 케이스(UX test cases)에서 선택하여 채택한 것입니다. alignWeightorthogonalWeight의 값도 같은 테스트 케이스를 기반으로 실험적으로 결정되었습니다. 결과 공식은 다소 복잡하지만, 좋은 결과를 주는 듯합니다. 개선이나 단순화 제안도 환영합니다.

9. 선언적 방법을 통한 공간 탐색 제어

9.1. 추가 공간 탐색 컨테이너 생성: spatial-navigation-contain 속성

이름: spatial-navigation-contain
값: auto | contain
초기값: auto
적용 대상: 모든 요소
상속: 아니오
백분율: 해당 없음
계산값: 명시된 그대로
정규 순서: 문법 순서에 따라
애니메이션 유형: 불연속(discrete)
auto
해당 요소가 스크롤 컨테이너인 경우 공간 탐색 컨테이너를 생성하며, 그렇지 않으면 생성하지 않습니다.
contain
해당 요소가 공간 탐색 컨테이너를 생성합니다.

참고: 또한 § 8.2 요소 그룹화에 따라, 브라우징 컨텍스트의 뷰포트(최상위 브라우징 컨텍스트에 한정되지 않음) 역시 공간 탐색 컨테이너를 생성합니다.

다음 예시는 TV 프로그램 편성표 또는 캘린더를 단순화한 예시입니다. TV 프로그램이나 일정 항목을 나타내는 요소로 이루어진 그리드와 그 주변 UI 버튼들이 있습니다.

이 경우, 그리드가 비교적 드물게 배치되어 있어 사용자가 "Foo"에서 아래로 이동하려고 하면, 포커스가 "Next Week"로 옮겨집니다. 왜냐하면 실제로 아래 방향에서 가장 가까운 위치이기 때문입니다. "Bar"에서 아래로 이동할 때도 마찬가지로 포커스가 "Previous Week"로 이동합니다.

M T W T F S S
0-6 Foo
6-9 Bar
9-12 Bat
12-18
18-21 Woo
21-24 Baz
<div>
    <button>Previous Week</button>
    <table>
        <tr><td><th>M<th>T<th>W<th>T<th>F<th>S<th>S
        <tr><td>0-6<td><td><td><td><td><td><td><a href="#">Foo</a>
        <tr><td>6-9<td><a href="#">Bar</a><td><td><td><td><td><td>
        <tr><td>9-12<td><td><a href="#">Bat</a><td><td><td><td><td>
        <tr><td>12-18<td><td><td><td><td><td><td>
        <tr><td>18-21<td><td><td><td><td><td><td><a href="#">Woo</a>
        <tr><td>21-24<td><td><td><td><td><td><a href="#">Baz</a><td>
    </table>
    <button>Next Week</button>
</div>

하지만 저자가 테이블 내의 항목에 포커스가 맞춰졌을 때 그리드 내부 이동을 우선시하는 다른 탐색 경험을 제공하고 싶을 수도 있습니다. 왜냐하면 테이블의 요소들은 서로 의미적으로 관련되어 있기 때문입니다.

스타일시트에 table { spatial-navigation-contain: contain; } 을 추가하면 이런 동작을 얻을 수 있습니다.

이후에는 "Foo"에서 아래로 이동하면 "Next Week" 대신 "Woo"로, "Bar"에서 아래로 이동하면 "Previous Week" 대신 "Bat"로 포커스가 이동합니다.

여전히 테이블 밖으로 포커스를 이동하는 것도 가능합니다. 예를 들어, "Foo"에서 오른쪽으로 이동하면 그리드에 오른쪽에 아무것도 없으므로 포커스가 "Next week"로 이동합니다.

참고: spatial-navigation-contain 속성은 위험(at-risk)입니다.

9.2. 스크롤과의 상호작용 제어: spatial-navigation-action 속성

이름: spatial-navigation-action
값: auto | focus | scroll
초기값: auto
적용 대상: 스크롤 컨테이너
상속: 아니오
백분율: 해당 없음
계산값: 명시된 그대로
정규 순서: 문법 순서에 따라
애니메이션 유형: 불연속(discrete)

포커스가 스크롤 컨테이너 안에 있을 때 사용자가 공간 탐색을 트리거하면, 포커스를 해당 방향으로 이동하려는 것인지, 아니면 문서를 해당 방향으로 스크롤하려는 것인지가 다소 모호합니다. 기본적으로 이 동작은 자동으로 결정되지만, 이 속성을 통해 저자가 포커스 이동 또는 스크롤 중 하나를 명확하게 지정할 수 있습니다.

정확한 동작은 § 8.3 탐색에서 정의되지만, 각 값의 효과에 대한 상위 설명은 아래에 제공합니다.

공간 탐색이 트리거될 때, 동작은 현재 포커스된 요소의 spatial-navigation-action 값을 따르며, 해당 요소가 스크롤 컨테이너인 경우에는 그 요소의, 아니면 가장 가까운 상위 스크롤 컨테이너의 값을 따릅니다.

auto
요청된 방향에 스크롤 컨테이너 내에 보이는 포커스 가능한 요소가 있다면, 가장 가까운 요소에 포커스가 이동합니다. 그렇지 않으면 해당 스크롤 컨테이너가 요청된 방향으로 스크롤됩니다.
focus
스크롤 컨테이너 내에서 가장 가까운 포커스 가능한 요소로 포커스를 이동합니다. 해당 요소가 보이지 않더라도 이동합니다. 만약 포커스 가능한 요소가 없다면, 스크롤 컨테이너는 스크롤되지 않으며, 대신 상위 체인으로 탐색이 이어집니다.

참고: 스크롤 컨테이너는 포커스 이동으로 인해 보이지 않던 요소가 보이게 되어 스크롤될 수 있지만, 방향 기반 스크롤은 아닙니다.

참고: focus 값이 spatial-navigation-action에 지정된 경우, 뷰포트 내에 보이는 후보가 없는 방향으로 공간 탐색을 시도하면(컨테이너가 더 스크롤될 수 있더라도) navnotarget 이벤트가 발생합니다.

scroll
현재 포커스된 요소가 스크롤 컨테이너가 아니라면, 상위 스크롤 컨테이너에서 이 값을 지정한 것은 auto와 동일하게 동작합니다.

현재 포커스된 요소가 스크롤 컨테이너라면, 포커스된 요소를 변경하지 않고 요청된 방향으로 스크롤만 하며, 포커스 가능한 하위 요소의 존재와 관계없이 동작합니다.

참고: 이는 공간 탐색을 통해 스크롤 컨테이너로 포커스를 옮기고 스크롤할 수 있지만, 하위 요소로 포커스를 이동하는 것은 불가능함을 의미합니다. 다만 Tab 키를 누르거나 <focus()> 메서드를 사용하는 등 다른 방법으로 하위 요소에 포커스가 이동한 경우, 공간 탐색을 이용해 다른 포커스 가능한 하위 요소로 이동할 수 있습니다.

참고: scroll 값은 위험(at-risk)입니다.

참고: 이 명세의 이전 버전에서는 focus 동작을 선언적으로 사용하도록 하는 방법이 없었고, 대신 스크롤 전에 발생하는 취소 가능한 이벤트를 제공하여 저자가 직접 해당 동작을 구현할 수 있게 했습니다. 하지만 스크롤과 관련된 취소 가능한 이벤트는 성능 문제를 일으킬 수 있으므로, 해당 이벤트는 제거되고 spatial-navigation-action 속성이 도입되었습니다.

이 예제에서는 spatial-navigation-action: focus가 지정된 스크롤 가능한 컨테이너가 있습니다. 컨테이너 내부에 scrollport 뷰 안에 보이지 않는 요소가 있습니다. 아래쪽 화살표 키를 누르면 수동 스크롤 없이 바로 해당 요소로 포커스가 이동합니다.
"Box 2"에서 "Box 3"으로 수동 스크롤 없이 포커스 이동
<div class='scroller'>
    <button class='item'>Box 1</button>
    <button class='item'>Box 2</button>
    <button class='item'>Box 3</button>
</div>
.scroller {
    display: grid;
    grid-template-columns: repeat(1, 1fr);
    height: 300px;
    width: 200px;
    overflow-y: scroll;
    spatial-navigation-action: focus;
}
.item {
    height: 100px;
    width: 100px;
    margin: 50px auto;
    background-color: blue;
}
:focus {
    background-color: red;
}

9.3. 탐색 알고리즘 선택: spatial-navigation-function 속성

이름: spatial-navigation-function
값: normal | grid
초기값: normal
적용 대상: 공간 탐색 컨테이너
상속: 아니오
백분율: 해당 없음
계산값: 명시된 그대로
정규 순서: 문법 순서에 따라
애니메이션 유형: 불연속(discrete)

§ 8 처리 모델에서 지정된 공간 탐색의 기본 알고리즘은 레이아웃 유형에 따라 미세 조정이 필요할 수 있습니다. 이 속성을 통해 저자가 공간 탐색 동작에 적합한 탐색 알고리즘을 지정할 수 있습니다.

값 정의는 다음과 같습니다:

normal
UA가 정의한 기본 포커스 탐색 알고리즘으로 포커스를 이동합니다.

일반적으로, 포커스는 최단 거리 계산을 통해 가장 가까운 요소로 이동합니다.

grid
탐색 방향으로 가장 정렬된 요소로 포커스를 이동합니다.
  • 탐색 방향으로 둘 이상의 정렬 후보가 있다면, 탐색 방향과 일치하는 축에서 가장 가까운 요소를 선택합니다. 여러 요소가 동일 거리일 경우, 정렬 정도가 가장 작은 요소를 선택합니다.

  • 지정된 방향에 정렬된 후보가 없다면, 탐색 방향과 일치하는 축에서 가장 가까운 요소를 선택합니다. 여러 요소가 동일 거리일 경우, 탐색 방향에 직교하는 축에서 거리가 가장 짧은 요소를 선택합니다.

참고: 이러한 값들은 사용자의 페이지에서 자연스러운 공간 탐색 동작으로 보이는 사용자의 선호와 협의되어 결정됩니다.

이 예시는 spatial-navigation-function 값에 따라 포커스가 다르게 이동하는 방식을 보여줍니다.
"A"에서 후보 요소 중 하나로 포커스 이동

"A", "B", "C"를 포함하는 요소가 공간 탐색 컨테이너라고 가정합니다.

사용자가 아래쪽 화살표 키를 누를 때, 해당 요소의 spatial-navigation-function 값이 normal이면 포커스가 "B"로 이동합니다. 반면 grid 값이 지정되면 포커스가 "C"로 이동합니다.

부록 A. 스크롤 확장

이 섹션에서는 CSS에 대한 몇 가지 확장 제안을 다룹니다. 향후 공식 명세에 통합되어야 하지만, 그 전까지는 여기에서 관리합니다.

이런 용어는 [CSSOM-VIEW-1], [CSS-OVERFLOW-3], [CSS-SCROLL-SNAP-1]에 포함되어야 합니다. <https://github.com/w3c/csswg-drafts/issues/2322>

요소 e는 주어진 방향 d수동으로 스크롤될 수 있다:

[CSSOM-VIEW-1]에서는 명시적 위치 없이 주어진 방향으로 스크롤하는 방법을 정의해야 합니다. 그 전까지는 직접 정의함. <https://github.com/w3c/csswg-drafts/issues/2323>

요소 e를 방향 dir방향 기반 스크롤하려면:

  1. d를 User Agent가 정의한 거리로 설정합니다.

  2. xe의 현재 x축 스크롤 위치로 설정합니다.

  3. ye의 현재 y축 스크롤 위치로 설정합니다.

  4. scroll an element 알고리즘([CSSOM-VIEW-1])을 e에 적용하여

    • dirup일 때 (x, y - d)

    • dirdown일 때 (x, y + d)

    • dirleft일 때 (x - d, y)

    • dirright일 때 (x + d, y)

부록 B. 개인정보 및 보안 고려사항

명세 기여자들은 이 명세와 관련된 모든 알려진 잠재적 보안 위험이 충분히 해결되었다고 믿습니다. 자세한 내용은 아래에 있습니다.

TAG에서는 명세의 위험을 평가할 수 있도록 셀프 리뷰 질문지를 개발했습니다. 이에 대한 답변은 아래에 있습니다.

이 명세가 개인 식별 정보와 관련되어 있습니까?
아닙니다.
이 명세가 고가치 데이터와 관련되어 있습니까?
아닙니다.
이 명세가 오리진에 대해 브라우징 세션 간에 지속되는 새로운 상태를 도입합니까?
아닙니다.
이 명세가 웹에 지속적이고 크로스 오리진 상태를 노출합니까?
아닙니다.
이 명세가 오리진에 현재 접근할 수 없는 다른 데이터를 노출합니까?
거의 없습니다.

예외가 있을 수 있는 시나리오: 저자가 `window.navigate`를 사용하고 포커스가 크로스 오리진 iframe에 있을 때 이벤트를 받지 못하면, iframe 내에 스크롤 가능하거나 포커스 가능한 것이 있었다는 의미가 됩니다. 이벤트가 발생하는 유일한 경우는 탐색이 아무것도 못 찾고 트리 상위로 올라갈 때입니다.

이 정보는 매우 제한적이어서 실질적인 보안 위험을 초래한다고 보긴 어렵지만, 저자가 일반적으로 얻을 수 없는 정보임은 분명합니다.

이 명세가 새로운 스크립트 실행/로딩 메커니즘을 허용합니까?
아닙니다.
이 명세가 오리진에 사용자의 위치 접근을 허용합니까?
아닙니다.
이 명세가 오리진에 사용자 장치의 센서 접근을 허용합니까?
아닙니다.
이 명세가 오리진에 사용자 로컬 컴퓨팅 환경의 측면 접근을 허용합니까?
아닙니다.
이 명세가 오리진에 다른 장치 접근을 허용합니까?
아닙니다.
이 명세가 오리진에 User Agent의 네이티브 UI에 대한 일부 제어권을 허용합니까?
User Agent UI의 모양에 대한 제어권은 제공되지 않습니다. User Agent가 공간 탐색을 수행하는 방식에 대한 일부 제어권은 제공합니다. 이는 저자가 페이지에 맞게 공간 탐색 동작을 맞춤화할 수 있도록 의도된 것입니다. 악의적인 저자가 사용자의 포커스 제어 및 문서 탐색을 방해하는 것을 막기 위해 이 오버라이드 메커니즘은 기본적으로 크로스 오리진 iframe에서는 비활성화되어 있습니다. § 7 navigation-override 정책 제어 기능 참고.
이 명세가 웹에 임시 식별자를 노출합니까?
아닙니다.
이 명세가 1st-party와 3rd-party 맥락에서 동작을 구분합니까?
아닙니다.
이 명세는 User Agent의 "시크릿 모드"에서 어떻게 동작해야 합니까?
차이 없음.
이 명세가 사용자의 로컬 장치에 데이터를 저장합니까?
아닙니다.
이 명세에 "보안 및 개인정보 고려사항" 섹션이 있습니까?
네, 지금 읽고 계신 바로 이 섹션입니다.
이 명세가 기본 보안 특성의 다운그레이드를 허용합니까?
관련 없는 보안 메커니즘의 다운그레이드는 허용하지 않습니다.

신뢰하는 크로스 오리진 iframe에서 공간 탐색의 기본 동작을 오버라이드하는 데 필요한 이벤트를 허용하도록 저자가 명시적으로 opt-in할 수 있게 [feature-policy]를 통해 허용합니다. § 7 navigation-override 정책 제어 기능 참고.

감사의 글

이 명세의 에디터들은 피드백과 기여를 해주신 다음 분들께 감사드립니다(알파벳 순):

변경 사항

이 섹션은 규범적이지 않습니다.

다음은 2019년 4월 23일 첫 공개 작업 초안 이후 변경된 내용입니다.

적합성

문서 규약

적합성 요구사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현됩니다. 핵심 단어 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”은 본 명세의 규범적 부분에서 RFC 2119에 기술된 대로 해석되어야 합니다. 다만, 가독성을 위해 이 단어들은 본 명세서에서 모두 대문자로 표기되지 않습니다.

본 명세의 모든 텍스트는 명시적으로 비규범적, 예시, 노트로 표시된 섹션을 제외하고는 규범적입니다. [RFC2119]

이 명세서의 예제는 “for example”로 시작하거나, class="example"처럼 규범적 텍스트와 구분되어 있습니다, 예시:

이것은 안내 예시의 한 예입니다.

안내 노트는 “Note”로 시작하며 class="note"로 규범 텍스트와 구분됩니다, 예시:

Note, 이것은 안내 노트입니다.

Advisement(경고문)는 특별한 주의를 환기하도록 스타일링된 규범 섹션이며, <strong class="advisement">로 다른 규범 텍스트와 구분됩니다, 예시: UA는 반드시 접근 가능한 대안을 제공해야 합니다.

적합성 클래스

본 명세에 대한 적합성은 세 가지 적합성 클래스로 정의됩니다:

스타일 시트
CSS 스타일 시트.
렌더러
UA로, 스타일 시트의 의미를 해석하고 이를 사용하는 문서를 렌더링합니다.
저작 도구
UA로, 스타일 시트를 작성합니다.

스타일 시트가 본 명세에 적합하려면, 본 모듈에 정의된 구문을 사용하는 모든 선언문이 일반 CSS 문법과 각 기능의 개별 문법에 따라 유효해야 합니다.

렌더러가 본 명세에 적합하려면, 스타일 시트를 적합한 명세대로 해석하는 것 외에도, 본 명세에서 정의한 모든 기능을 올바르게 파싱하고 문서를 그에 따라 렌더링해야 합니다. 단, 디바이스의 제한으로 인해 UA가 문서를 올바르게 렌더링하지 못하는 경우는 비적합으로 간주하지 않습니다. (예: UA는 단색 모니터에서 색상을 렌더링할 필요는 없습니다.)

저작 도구가 본 명세에 적합하려면, 본 모듈의 일반 CSS 문법 및 각 기능의 개별 문법에 따라 구문적으로 올바른 스타일 시트를 작성하고, 본 모듈에서 기술된 스타일 시트의 모든 다른 적합성 요구도 충족해야 합니다.

CSS 책임 구현을 위한 요구사항

다음 섹션들은 현재와 미래의 상호운용성을 촉진하는 방식으로 CSS를 책임 있게 구현하기 위한 여러 적합성 요구사항을 정의합니다.

부분 구현

저자가 미래 호환 파싱 규칙을 활용해 대체 값을 지정할 수 있도록, CSS 렌더러는 반드시 지원 가능한 수준이 없는 모든 at-규칙, 속성, 속성 값, 키워드, 기타 구문적 구조를 무효로 처리하고 (필요시 무시) 해야 합니다. 특히, UA는 지원하지 않는 속성 값을 선택적으로 무시하고, 단일 다값 속성 선언에서 지원값만 적용해서는 안됩니다: 어떤 값이 무효(지원하지 않는 값이어야 함)로 간주되는 경우, CSS는 전체 선언문을 무시해야 함을 요구합니다.

불안정 및 독점 기능 구현

향후 안정적인 CSS 기능과 충돌을 방지하기 위해, CSSWG는 모범 사례를 따라 불안정 기능 및 독점 확장을 구현할 것을 권장합니다.

CR 단계 기능 구현

명세가 Candidate Recommendation(CR) 단계에 도달하면, 구현자는 본 명세에 따라 올바르게 구현되었음을 입증할 수 있는 모든 CR 단계 기능의 접두사 없는 구현을 공개해야 하며, 해당 기능의 접두사 버전 노출은 지양해야 합니다.

CSS의 구현 간 상호운용성을 확립 및 유지하기 위해, CSS Working Group은 실험적이지 않은 CSS 렌더러가 접두사 없는 CSS 기능 구현을 공개하기 전에 W3C에 구현 보고서(필요시 해당 테스트케이스 포함)를 제출할 것을 요청합니다. W3C에 제출된 테스트케이스는 CSS Working Group의 검토 및 수정 대상이 됩니다.

테스트케이스 및 구현 보고서 제출 관련 추가 정보는 CSS Working Group 웹사이트 http://www.w3.org/Style/CSS/Test/에서 확인할 수 있습니다. 문의는 public-css-testsuite@w3.org 메일링 리스트로 보내면 됩니다.

색인

본 명세에서 정의된 용어

참조로 정의된 용어

참고문헌

규범적 참고문헌

[CSS-BREAK-4]
Rossen Atanassov; Elika Etemad. CSS Fragmentation Module Level 4. 2018년 12월 18일. WD. URL: https://www.w3.org/TR/css-break-4/
[CSS-CASCADE-4]
Elika Etemad; Tab Atkins Jr.. CSS Cascading and Inheritance Level 4. 2018년 8월 28일. CR. URL: https://www.w3.org/TR/css-cascade-4/
[CSS-DISPLAY-3]
Tab Atkins Jr.; Elika Etemad. CSS Display Module Level 3. 2019년 7월 11일. CR. URL: https://www.w3.org/TR/css-display-3/
[CSS-OVERFLOW-3]
David Baron; Elika Etemad; Florian Rivoal. CSS Overflow Module Level 3. 2018년 7월 31일. WD. URL: https://www.w3.org/TR/css-overflow-3/
[CSS-POSITION-3]
Rossen Atanassov; Arron Eicholz. CSS Positioned Layout Module Level 3. 2016년 5월 17일. WD. URL: https://www.w3.org/TR/css-position-3/
[CSS-SCROLL-SNAP-1]
Matt Rakow; et al. CSS Scroll Snap Module Level 1. 2019년 3월 19일. CR. URL: https://www.w3.org/TR/css-scroll-snap-1/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 2019년 1월 31일. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 2011년 6월 7일. REC. URL: https://www.w3.org/TR/CSS2/
[CSSOM-VIEW-1]
Simon Pieters. CSSOM View Module. 2016년 3월 17일. WD. URL: https://www.w3.org/TR/cssom-view-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[FEATURE-POLICY]
Ian Clelland. Feature Policy. 2019년 4월 16일. WD. URL: https://www.w3.org/TR/feature-policy-1/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997년 3월. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[UIEVENTS]
Gary Kacmarcik; Travis Leithead; Doug Schepers. UI Events. 2019년 5월 30일. WD. URL: https://www.w3.org/TR/uievents/
[WebIDL]
Boris Zbarsky. Web IDL. 2016년 12월 15일. ED. URL: https://heycam.github.io/webidl/

참고 문헌

[CSS-TRANSFORMS-1]
Simon Fraser; 외. CSS Transforms Module Level 1. 2019년 2월 14일. CR. URL: https://www.w3.org/TR/css-transforms-1/
[EXTENSIBLE]
Extensible Web 선언문. 2013년 6월 10일. URL: https://extensiblewebmanifesto.org/

속성 색인

이름 초기값 적용 대상 상속 %값 애니메이션 유형 정규 순서 계산값
spatial-navigation-action auto | focus | scroll auto 스크롤 컨테이너 아니오 해당 없음 불연속 문법 순서 명시된 그대로
spatial-navigation-contain auto | contain auto 모든 요소 아니오 해당 없음 불연속 문법 순서 명시된 그대로
spatial-navigation-function normal | grid normal 공간 탐색 컨테이너 아니오 해당 없음 불연속 문법 순서 명시된 그대로

IDL 색인

enum SpatialNavigationDirection {
    "up",
    "down",
    "left",
    "right",
};

partial interface Window {
    void navigate(SpatialNavigationDirection dir);
};

enum FocusableAreaSearchMode {
    "visible",
    "all"
};

dictionary FocusableAreasOption {
    FocusableAreaSearchMode mode;
};

dictionary SpatialNavigationSearchOptions {
    sequence<Node>? candidates;
    Node? container;
};

partial interface Element {
    Node getSpatialNavigationContainer();
    sequence<Node> focusableAreas(optional FocusableAreasOption option);
    Node? spatialNavigationSearch(SpatialNavigationDirection dir, optional SpatialNavigationSearchOptions options);
};

[Exposed=Window]
interface NavigationEvent : UIEvent {
    constructor(DOMString type,
                optional NavigationEventInit eventInitDict);
    readonly attribute SpatialNavigationDirection dir;
    readonly attribute EventTarget? relatedTarget;
};

dictionary NavigationEventInit : UIEventInit {
    SpatialNavigationDirection dir;
    EventTarget? relatedTarget = null;
};

이슈 색인

이 API의 명칭은 논의 중입니다 <https://github.com/w3c/csswg-drafts/issues/3387>
CSS는 “border-radius처럼 모서리 형태 속성을 고려한 border box” 용어를 가져야 합니다. <https://github.com/w3c/csswg-drafts/issues/2324>
이런 용어는 [CSSOM-VIEW-1], [CSS-OVERFLOW-3], [CSS-SCROLL-SNAP-1]에 포함되어야 합니다. <https://github.com/w3c/csswg-drafts/issues/2322>
[CSSOM-VIEW-1]에서 명시적 위치 없이 주어진 방향으로 스크롤하는 방법을 정의해야 합니다. 그 전까지는 직접 정의함. <https://github.com/w3c/csswg-drafts/issues/2323>