웹 접근성 개선작업(4)

jiseong·2022년 6월 22일
0

T I Learned

목록 보기
274/291
post-custom-banner

슬라이더 개선

다양한 이유로 마우스를 사용하기 어려운 경우, 키보드만으로도 앱의 모든 기능을 사용할 수 있도록 제공해주고자 키보드 접근성을 높이는 작업을 했었다. 하지만 개선하는 과정에서 인기 검색어를 슬라이더 형식으로 보여주는 부분이 생각했던 방식처럼 동작하지 않아 수정이 필요했다.

슬라이더 내에 존재하는 아이템들에 대한 포커스

첫번째는 슬라이더 내에 존재하는 아이템들에 대한 포커스이다.

컨트롤로 키보드를 사용하기 위해서는 컨트롤에 포커스가 있어야 하고, 포커스를 받으려면 탭 탐색을 통해 컨트롤에 액세스할 수 있어야 한다. 슬라이더 내에 존재하는 액세스 가능한 아이템들은 슬라이더를 움직일 수 있는 버튼, 슬라이더 아이템이 존재한다.

일반적으로 현재 화면에 보여지는 슬라이더 아이템에만 액세스가 가능해야하며 이외에 나머지 슬라이더 아이템에는 액세스할 수 없다고 생각할 것이다. 하지만 슬라이더 내에 존재하는 슬라이더 아이템들은 액세스가 가능하기 때문에 다음과 같은 현상이 일어난다.

그렇다면 화면에 보이지 않는 슬라이더 아이템들의 경우에는 액세스 할 수 없도록 해야 하는데 나의 경우에는 tabIndex값을 -1로 정의해주면 포커스가 되지 않는 특징을 이용했다.

현재 슬라이더 아이템 위치를 나타내는 position 값을 활용하여 이후의 3개 아이템 이외에 tabIndex 속성의 값으로 -1를 정의해주면 된다.

// components/Slider/Item.ts

function Item({isShow}: Props) {
  return (
    <Styled.AlbumWrapper>
      <Styled.AlbumBtn
        tabIndex={isShow ? undefined : -1}
        aria-hidden={!isShow}
      >
        {/* 슬라이더 아이템 내부 */}
      </Styled.AlbumBtn>
    </Styled.AlbumWrapper>
  );
}

다만 구현한 슬라이더는 반응형으로 구현되어 있어 일정 지점마다 슬라이더의 아이템의 갯수가 달라지기 때문에 윈도우의 사이즈가 변경될때마다 호출되는 훅을 재사용하여 일정 지점이 되었을 때, 3개 아이템이 아닌 특정 갯수 아이템으로 변경하도록 작성하였다.

// utils/slider.ts
export function sliderItemShowReader(
  position: number, // 현재 슬라이더 아이템 위치
  numberOfItemsToShow: number, // 화면에 보여지는 아이템 갯수
) {
  return function (idx: number) {
    return position <= idx && idx < position + numberOfItemsToShow;
  };
}

export function getNumberOfItemsToShow(deviceWidth: number) {
  if (deviceWidth > Number(SIZE.TABLET.replace('px', ''))) return 3;
  if (deviceWidth > Number(SIZE.MAX_MOBILE.replace('px', ''))) return 2;
  return 1;
}

// components/Slider/index.ts
const [windowWidth, _] = useResize({ type: 'throttle' });

const isShowCurrentItem = sliderItemShowReader(
  position,
  getNumberOfItemsToShow(windowWidth),
);

<Styled.SliderItemsContainer position={position}>
  {data.map((item: ITopSearched, idx: number) => (
    <Item
      isShow={isShowCurrentItem(idx)}
    />
  ))}
</Styled.SliderItemsContainer>

논리상으로 맞지 않는 포커스 순서

두번째는 논리상으로 맞지 않는 포커스 순서이다.

처음에는 추후 확장성을 고려하여 슬라이더의 컨트롤을 담당하는 (좌, 우)버튼들은 하나의 div 태그 내에 작성하였다.

변경 전
<Styled.SliderContent>
  <Styled.SliderItemsContainer position={position}>
    {data.map((item: ITopSearched) => (
      <Item
        key={item.id}
        item={item}
        handleSearchKeyword={handleSearchKeyword}
        />
    ))}
  </Styled.SliderItemsContainer>

  <Styled.ControlContainer>
    <Styled.PrevBtn
      name="prev"
      onClick={handleSlider}
      aria-label="slider prev"
      >
      &#10094;
    </Styled.PrevBtn>
    <Styled.NextBtn
      name="next"
      onClick={handleSlider}
      aria-label="slider next"
      >
      &#10095;
    </Styled.NextBtn>
  </Styled.ControlContainer>
</Styled.SliderContent>

그러다보니 키보드 사용자가 페이지를 탐색할 때 순서는 논리적이고 직관적이어야 하지만 포커스의 순서가 슬라이더 아이템 다음으로 버튼들이 포커스되어버리는 현상이 발생하게 된 것이다.

마찬가지로 tabIndex 속성에 양수값을 활용하여 조절할 수 있지만 지양하는 방식이라 페이지의 시각적 흐름대로 태그 위치를 재조정하였다.

변경 후
<Styled.SliderContent>
  <Styled.PrevBtn
    name="prev"
    onClick={handleSlider}
    aria-label="slider prev"
    >
    &#10094;
  </Styled.PrevBtn>

  <Styled.SliderMargin>
    <Styled.SliderItemsContainer position={position}>
      {data.map((item: ITopSearched, idx: number) => (
        <Item
          key={item.id}
          item={item}
          handleSearchKeyword={handleSearchKeyword}
          />
      ))}
    </Styled.SliderItemsContainer>
  </Styled.SliderMargin>

  <Styled.NextBtn
    name="next"
    onClick={handleSlider}
    aria-label="slider next"
    >
    &#10095;
  </Styled.NextBtn>
</Styled.SliderContent>

결과

이제 키보드 사용자의 경우에도 논리적인 순서대로 슬라이더를 탐색할 수 있게 되었다.

post-custom-banner

0개의 댓글