논리적 순차 포커스 탐색에 CSS 읽기 흐름 사용

게시일: 2025년 5월 1일

CSS reading-flowreading-order 속성은 Chrome 137부터 사용할 수 있습니다. 이 게시물에서는 이러한 속성의 설계 이유와 속성을 시작하는 데 필요한 간단한 세부정보를 설명합니다.

그리드 및 플렉스와 같은 레이아웃 메서드는 프런트엔드 개발을 혁신했지만 유연성으로 인해 일부 사용자에게 문제가 발생할 수 있습니다. 시각적 순서가 DOM 트리에서 소스 순서와 일치하지 않는 상황을 만드는 것은 매우 쉽습니다. 이 소스 순서는 키보드를 사용하여 사이트를 탐색할 때 브라우저가 따르는 순서이므로 일부 사용자는 페이지를 탐색할 때 예기치 않은 점프를 경험할 수 있습니다.

reading-flowreading-order 속성은 이 오랜 문제를 해결하기 위해 CSS 디스플레이 사양에 설계되고 추가되었습니다.

reading-flow

reading-flow CSS 속성은 플렉스, 그리드 또는 블록 레이아웃의 요소가 접근성 도구에 노출되는 순서와 선형 순차 탐색 방법을 사용하여 포커스가 지정되는 방식을 제어합니다.

DOM 순서로 요소를 정렬하는 동작을 유지하는 기본값 normal를 사용하여 하나의 키워드 값을 사용합니다. 플렉스 컨테이너 내에서 사용하려면 값을 flex-visual 또는 flex-flow로 설정하세요. 그리드 컨테이너 내에서 사용하려면 값을 grid-rows, grid-columns 또는 grid-order로 설정하세요.

reading-order

reading-order CSS 속성을 사용하면 읽기 흐름 컨테이너 내에서 항목의 순서를 수동으로 재정의할 수 있습니다. 그리드, 플렉스 또는 블록 컨테이너 내에서 이 속성을 사용하려면 컨테이너의 reading-flow 값을 source-order로 설정하고 개별 항목의 reading-order를 정수 값으로 설정합니다.

Flexbox의 예

예를 들어 행 순서가 반대인 요소 3개가 있는 플렉스 레이아웃 컨테이너가 있고 order 속성을 사용하여 순서를 다시 섞고 싶을 수 있습니다.

<div class="box">
 <a href="#">One</a>
 <a href="#">Two</a>
 <a href="#">Three</a>
</div>
.box {
  display: flex;
  flex-direction: row-reverse;
}

.box :nth-child(1) {
  order: 2;
}

TAB 키를 사용하여 다음 포커스 가능 요소를 찾고 TAB+SHIFT 키를 사용하여 이전 포커스 가능 요소를 찾아 이러한 요소를 탐색해 보세요. 소스 순서대로 항목이 나열됩니다. One, Two, Three.

최종 사용자 관점에서 이는 말이 안 되며 매우 혼란스러울 수 있습니다. 접근성 공간 탐색 도구를 사용하여 페이지를 탐색하는 경우에도 마찬가지입니다.

이 문제를 해결하려면 reading-flow 속성을 설정하세요.

.box {
  reading-flow: flex-visual;
}

이제 포커스 순서는 1, 3, 2입니다. 이는 영어로 왼쪽에서 오른쪽으로 읽을 때 표시되는 시각적 순서와 같습니다.

대신 포커스 순서를 원래 의도한 대로 역순으로 유지하려면 다음을 설정하면 됩니다.

.box {
  reading-flow: flex-flow;
}

이제 포커스 순서가 역방향 플렉스 순서인 2, 3, 1로 지정됩니다. 두 경우 모두 CSS order 속성이 고려됩니다.

그리드 레이아웃이 있는 예

그리드에서 이 기능이 어떻게 작동하는지 확인하려면 포커스 가능 영역이 12개인 CSS 그리드 자동 배치 항목으로 레이아웃을 만든다고 가정해 보세요.

<div class="wrapper">
 <a href="#">One</a>
 <a href="#">Two</a>
 <a href="#">Three</a>
 <a href="#">Four</a>
 <a href="#">Five</a>
 <a href="#">Six</a>
 <a href="#">Seven</a>
 <a href="#">Eight</a>
 <a href="#">Nine</a>
 <a href="#">Ten</a>
 <a href="#">Eleven</a>
 <a href="#">Twelve</a>
</div>

다섯 번째 하위 요소가 맨 위에 가장 큰 공간을 차지하고 두 번째 하위 요소가 그리드 중앙에 위치하도록 하려고 합니다. 다른 모든 하위 요소는 열 템플릿에 따라 그리드 내에 자동으로 배치할 수 있습니다.

.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
}
.wrapper a:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper a:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}

TAB 키를 사용하여 다음 포커스 가능 요소를 찾고 TAB+SHIFT 키를 사용하여 이전 포커스 가능 요소를 찾아 이러한 요소를 탐색해 보세요. 이는 소스 순서(1~12)를 따릅니다.

이 문제를 해결하려면 reading-flow 속성을 설정하세요.

.wrapper {
  reading-flow: grid-rows;
}

이제 포커스 순서는 5, 1, 3, 2, 4, 6, 7, 8, 9, 10, 11, 12입니다. 시각적 순서에 따라 행별로 진행됩니다.

읽기 흐름이 열 순서를 따르도록 하려면 grid-columns 키워드 값을 대신 사용하면 됩니다. 그러면 포커스 순서는 Five, Six, Nine, Seven, Ten, One, Two, Eleven, Three, Four, Eight, Twelve가 됩니다.

.wrapper {
  reading-flow: grid-columns;
}

grid-order를 사용해 볼 수도 있습니다. 포커스 순서는 1~12로 유지됩니다. 이는 상품에 설정된 CSS 주문이 없기 때문입니다.

reading-order를 사용하는 블록 컨테이너

reading-order 속성을 사용하면 읽기 흐름에서 항목을 방문해야 하는 시점을 지정하여 reading-flow 속성으로 설정된 순서를 재정의할 수 있습니다. reading-flow 속성이 normal이 아닌 경우 유효한 읽기 흐름 컨테이너에만 적용됩니다.

.wrapper {
  display: block;
  reading-flow: source-order;
}

.top {
  reading-order: -1;
  inset-inline-start: 50px;
  inset-block-start: 50px;
}

다음 블록 컨테이너에는 5개의 항목이 포함되어 있습니다. 소스 순서에서 요소를 재정렬하는 레이아웃 규칙은 없지만 먼저 방문해야 하는 흐름 외 항목이 있습니다.

<div class="wrapper">
  <a href="#">Item 1</a>
  <a href="#">Item 2</a>
  <a href="#">Item 3</a>
  <a href="#">Item 4</a>
  <a class="top" href="#">Item 5</a>
</div>

이 항목의 reading-order-1로 설정하면 포커스 순서가 먼저 이 항목을 방문한 후 나머지 읽기 흐름 항목의 소스 순서로 돌아갑니다.

chrome.dev 사이트에서 더 많은 예를 확인할 수 있습니다.

tabindex와의 상호작용

기존에는 개발자가 HTML tabindex 전역 속성을 사용하여 HTML 요소를 포커스 가능하게 만들고 순차적 포커스 탐색의 상대적 순서를 결정했습니다. 하지만 이 속성에는 여러 단점과 접근성 문제가 있습니다. 주요 문제는 양수 tabindex를 사용하여 만든 tabindex 순서 지정 포커스 탐색이 접근성 트리에서 인식되지 않는다는 것입니다. 잘못 사용하면 스크린 리더의 환경과 일치하지 않는 점프 포커스 순서가 발생할 수 있습니다. 이 문제를 해결하려면 aria-owns HTML 속성을 사용하여 순서를 추적하세요.

이전의 플렉스 예시에서 reading-flow: flex-visual를 사용하는 것과 동일한 결과를 얻으려면 다음을 실행하면 됩니다.

<div class="box" aria-owns="one three two">
  <a href="#" tabindex="1" id="one">One</a>
  <a href="#" tabindex="3" id="two">Two</a>
  <a href="#" tabindex="2" id="three">Three</a>
</div>

하지만 컨테이너 외부의 다른 요소에도 tabindex=1가 있는 경우에는 어떻게 될까요? 그런 다음 다음 증분 tabindex 값으로 이동하기 전에 tabindex=1이 있는 모든 요소가 함께 방문됩니다. 이러한 불안정한 순차 탐색은 사용자 환경을 저해합니다. 따라서 접근성 전문가들은 양수 tabindex를 피할 것을 권장합니다. reading-flow를 설계할 때 이 문제를 해결하려고 노력했습니다.

reading-flow 속성이 설정된 컨테이너는 포커스 범위 소유자가 됩니다. 즉, 웹 문서에서 다음 포커스 가능 요소로 이동하기 전에 컨테이너 내의 모든 요소를 방문하도록 순차적 포커스 탐색의 범위를 지정합니다. 또한 직접 하위 요소는 reading-flow 속성을 사용하여 정렬되며, 정렬 목적으로는 양수 tabindex가 무시됩니다. 읽기 흐름 항목의 하위 요소에 양수 tabindex를 설정하는 것은 여전히 가능합니다.

레이아웃 상위 요소에서 reading-flow 속성을 상속하는 display: contents가 있는 요소도 유효한 읽기 흐름 컨테이너가 됩니다. 사이트를 디자인할 때 이 점을 유의하세요. reading-flowdisplay: contents에 대한 의견 요청에서 자세히 알아보세요.

의견 보내기

이 게시물과 chrome.dev의 reading-flow 예시의 예시를 사용해 보고 사이트에서 이러한 CSS 속성을 사용해 보세요. 의견이 있으면 CSS 작업 그룹 GitHub 저장소에 문제로 제출하세요. tabindex 및 포커스 범위 지정 동작에 관한 의견이 있으면 HTML WHATNOT GitHub 저장소에 문제로 신고하세요. 이 기능에 대한 의견을 보내주세요.