아직 너무 생소한 성능과 웹 접근성. 막 부딪히다보면 익숙해지지 않을까라는 생각으로 lighthouse
를 돌려보고는 한다.
nextjs 빌드 후 실행해서 lighthouse
를 돌려보니 웹 접근성 항목에서 아이콘 버튼에 대해 접근 가능한 이름이 없다고 나타내주었다.
찾아보니 접근성을 위해 버튼에는 이름이 있어야 한다고 한다.
아이콘만 사용하는 버튼에는 접근 가능한 이름이 없습니다. 스크린 리더 등 보조 기술은 문서를 분석하고 접근성 트리를 생성할 때 접근 가능한 이름에 의존합니다.
왜 있어야 할까?
보조 기술은 사용하지 않더라도 아이콘의 의미나 버튼의 용도에 익숙하지 않은 사용자들도 텍스트를 읽을 수 있다면 도움이 된다는 사실을 기억하세요. 특히 기술과 친숙하지 않거나, 문화권이 달라서 아이콘을 다르게 받아들일 수 있는 사용자에게 있어 보조 텍스트의 존재 유무는 큰 차이를 만듭니다.
활용될 가능성이 적어도 누군가에게는 필요할 수 있다는 것 같다.
아이콘 모양은 읽지 못하지만 텍스트는 읽을 수 있다.
결국 아이콘 버튼이라 텍스트가 보이지는 않아야 되기 때문에 보조기술은 읽을 수 있지만 눈에는 보이지 않는 텍스트를 넣기로 했다.
Screen reader 사용해보기
크롬에서 screen reader 익스텐션을 설치하고 사용하면서 실제로 어떻게 HTML 엘리먼트들을 읽는지 확인해보았다.
헬로우
라는 텍스트를 버튼에 넣었더니 헬로우 버튼
이라고 읽었다.
텍스트가 없을 때는 그냥 버튼
이라고 읽는데 확실히 스크린리더를 사용하는 사용자 입장에서는 어떤 버튼을 현재 선택했는지 알 수 없을 것 같다.
레퍼런스 링크에서 알려준 것을 바탕으로 숨김 텍스트 컴포넌트를 만들어 아이콘 버튼에 넣어보았다.
export const HiddenText = styled.span`
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
white-space: nowrap;
width: 1px;
`;
export interface IconButtonProps {
/** 존재하는 svg 아이콘 이름 */
icon: IconType;
/** 내부 아이콘 사이즈: `px`, `rem`, `%` */
iconSize?: ElementSizeType;
/** 아이콘 색상: `기본값: theme textColor` */
color?: string;
/** 아이콘 버튼의 의도를 나타낼 숨겨질 텍스트 */
name: string;
onClick: () => void;
}
const IconButton = ({ icon, iconSize = '20px', color, name, onClick }: IconButtonProps) => (
<IconButtonWrapper onClick={onClick}>
<Icon icon={icon} size={iconSize} color={color ?? 'var(--color-text)'} />
<HiddenText>{name}</HiddenText>
</IconButtonWrapper>
);
export default IconButton;
<IconButton
icon={theme === 'light' ? 'Lightmode' : 'Darkmode'}
iconSize="20px"
onClick={toggleTheme}
name={theme === 'light' ? '다크모드로 변경' : '라이트모드로 변경'}
/>
공교롭게도 시각과 관련된 역할을 하는 아이콘버튼이긴 하지만 다음과 같이 넣고 스크린 리더를 통해 키보드로 탐색하며 음성을 들어보았다.
UI상에서는 보이지 않지만 개발자 도구에도 텍스트가 있고정말로 탐색 시 다크모드로 변경 버튼!
이라고 읽어준다.
그러고보니 다크모드 버튼 옆의 내 프로필은 버튼처럼 동작하는데 스크린리더가 탐색하지 않았다.
HTML 문서의 시맨틱 요소 중에서도 role 속성을 사용하여 접근 가능한 역할을 가진 요소들, 예를 들어 버튼(button), 링크(anchor), 목록(list) 등과 같은 요소들에 대해서 탐색 대상으로 인식한다고 한다.
어쩐지 eslint a11y
에서 일반적인 태그에 onClick
핸들러를 넣으려고 하면 뭐라고 했다.
보이기에는 버튼처럼 동작하지만 접근성 측면에서는 버튼으로 알 수 없다는 것이다.
role
속성을 사용해 일반 태그에 역할을 부여하고 tabIndex
속성을 사용해 키보드 포커스를 받을 수 있게 할 수 있지만 가장 좋은건 역할에 맞는 적절한 태그를 사용하는게 아닐까 생각한다.
그리고 input
의 aria-label
도 테스트할 때 사용하기 좋을정도로만 지정했었는데 이걸 리더가 다 읽었다. 읽기 좋게 작성해야하는구나!
추후에 접근성 측면에서 살펴보며 수정해야할 것들이 많을 것 같다.
별 것 아닌 것 같아보일 수 있으나 별 것 아닌 것 같아보이는 것들을 미리 신경써서 개발하는 습관을 들이고 추후에 접근성 측면에서 좋아야하는 상황일 때 쉽게 대처할 수 있지 않을까 생각한다.
다시 테스트 해보니 해당 접근성 문제가 개선되었다!
아직은 너무 어렵고 생소한 성능과 접근성 문제. 계속 마주하고 공부하다보면 익숙해지지 않을까 싶다!