웹 접근성

실무에서 웹 접근성 개선해보기

권끼리마끼리 2025. 3. 14. 21:52

안녕하세요 :) 웹 접근성 개선은 모든 사용자가 불편함 없이 웹을 이용할 수 있도록 하는 중요한 작업입니다. 하지만 리소스가 한정적인 스타트업에서는 단순히 “좋은 일이니까 하자”는 이유만으로 시간을 할애하기가 쉽지 않습니다. 그래서 우리는 웹 접근성을 개선해야 하는지보다, 어떻게 현실적으로 추진할 수 있었는지를 중심으로 이야기해보려고 합니다.

 

저희 회사는 일본과 미국을 포함한 글로벌 프로젝트를 많이 진행했습니다. 해외에서는 웹 접근성이 법적으로도 중요한 요소이고, 이를 준수하지 않으면 소송의 대상이 될 수도 있습니다. 따라서 프론트엔드 팀에서 더 나은 사용자 경험을 제공하면서도 최소한의 법적 기준을 충족할 수 있도록 접근성 개선을 주도하게 되었습니다.

 

그 과정에서 저는 사내 접근성 스터디를 열었고, A11y Calender와 접근성 지침을 잘 준수한 컴포넌트들을 모아둔 GitHub 저장소 등을 참고하면서 공부를 시작했습니다. 스터디가 끝난 후에는 핵심 내용을 정리해 사내 비개발 직군 팀원들과도 공유했습니다. 다행히 팀원들이 적극적으로 관심을 가져줘서 더 의미 있는 시간이 되었습니다.

 

여러분에게도 이 아티클이 의미있길 바라며 저희가 진행한 접근성 개선 경험과 실무에서 적용할 수 있는 방법들을 공유해보려고 합니다.

 

접근성 확인하기: 확장프로그램

먼저, 현재 웹 접근성이 잘 준수되고 있는지 간단하게 확인할 수 있는 프로그램을 소개해 드리겠습니다. 다양한 도구가 있지만, 저희가 실무에서 사용했던 도구를 중심으로 안내해 드릴게요. 혹시 다른 도구들도 궁금하시다면, 이 아티클을 참고해 보시는 것도 좋겠습니다.

 

저희가 사용한 도구는 WAVE라는 크롬 확장 프로그램입니다. 테스트하고자 하는 페이지에서 확장 프로그램을 실행하면 아래 이미지와 같은 UI가 나타납니다.

티스토리 ㅎㅎ

 

Details를 누르면 세부항목도 알려줍니다. 예를 들어, 이 페이지에서 에러가 2개 발생한 이유는 이미지에 alt 태그가 포함되지 않았기 때문이라는 점을 알려주기도 합니다.

 

 

이외에도 Order 기능을 통해 링크마다 사용자가 식별할 수 있는 적절한 제목이 들어가 있는지 확인할 수 있으며, Structure 기능을 활용해 페이지의 구조가 적절하게 구성되어 있는지도 점검할 수 있습니다.

 

접근성 확인하기: 스크린리더

시각장애인분들은 웹페이지를 이용할 때 스크린리더 프로그램을 사용합니다. 저희도 접근성 테스트를 할 때 스크린리더를 자주 실행하여 실제 사용 환경을 경험해 보았습니다.

 

Mac에는 기본적으로 VoiceOver가 설치되어 있으며, Windows 사용자는 NVDA라는 프로그램을 설치하여 사용할 수 있습니다. 저희는 Mac을 사용하고 있어 VoiceOver를 중심으로 테스트를 진행했으며, windows 사용자는 이 아티클에서 NVDA 사용 방법을 참고해 보시면 좋겠습니다.

 

voiceover는 Command + F5 단축키로 실행 및 종료할 수 있습니다. 단축키를 누르면 아래와 같은 팝업이 열립니다.

단축키를 누르면 아래와 같은 팝업이 나타나며, “VoiceOver 사용” 버튼을 클릭한 후 Tab 키를 이용해 조작할 수 있습니다. 사용법이 어렵지 않으니 직접 실행해 보시면 좋겠습니다.

 

스크린리더를 활용하여 저희는 다음과 같은 요소들을 점검했습니다.

 

엘리먼트가 포커스로 조작이 가능한지

적절한 라벨이 제공되고 있는지

 

이처럼 실제 스크린리더를 사용해 보면서, 우리가 만든 웹페이지가 다양한 사용자에게 어떻게 전달되는지를 직접 확인해보시면 좋을 것 같습니다 :) 

 

프로젝트 개선해보기

접근성을 준수하기 위해 개선할 부분은 무궁무진하지만, 실무에서 저희가 특히 자주 실수했던 부분들을 공유해 보려고 합니다.

 

1. 텍스트 없이 이미지로만 구성된 버튼에는 적절한 텍스트를 추가해야 합니다.

웹 접근성에 관심이 있는 분들이라면 한 번쯤 들어보셨을 내용일 텐데요. 이미지로만 구성된 버튼은 스크린리더에서 포커스가 잡혀도 빈 텍스트로 인식되기 때문에 사용자 경험에 큰 불편을 줄 수 있습니다. 이를 방지하려면 적절한 텍스트를 추가해야 합니다.

 

이때 사용할 수 있는 방법은 두 가지입니다.

1️⃣ aria-label 속성을 사용하는 방법

2️⃣ .sr-only CSS 클래스를 활용하여 스크린리더만 읽을 수 있는 텍스트를 추가하는 방법

 

이 두 방법의 가장 큰 차이점은 브라우저 번역 기능에 있습니다.

 

요즘 널리 쓰이는 영어의 경우 aria-label에 대해 브라우저 번역 기능이 정상적으로 작동합니다. 하지만 잘 쓰이지 않는 외국어의 경우 번역이 제대로 지원되지 않을 수도 있습니다. 관련된 아티클이 있으니 참고해 보시는 것도 좋겠습니다.

 

따라서 프로젝트의 특성을 고려해 적절한 방법을 선택해야 합니다. 저희는 영어와 일본어 외에 다른 언어를 고려할 필요가 없다고 판단하여, 코드의 가독성과 유지보수 측면에서 더 유리한 aria-label을 사용하기로 결정했습니다.

 

2. 버튼의 disabled 속성을 사용할때는 주의해야합니다.

폼 검증(Validation) 과정에서 입력값이 유효하지 않을 경우, 버튼을 비활성화하는 경우가 많습니다. 이때 disabled 속성을 자주 사용하게 되는데요.

 

하지만 disabled 속성을 사용하면 해당 버튼이 접근성 트리에서 아예 사라지게 됩니다. 즉, 스크린리더가 이 버튼을 인식할 수 없다는 뜻이죠.

 

사용자가 입력을 완료하지 않은 상태에서 Tab 키를 이용해 버튼에 접근하려고 할 때, 버튼이 보이지 않는다면 “제출 버튼이 없네?” 하고 오해할 수도 있습니다. 저희도 이 사실을 몰랐다가 한참 후에야 깨닫고 정말 놀랐던 기억이 있습니다! 😨

 

해결 방법: aria-disabled 속성 사용하기

 

이 문제를 해결하기 위해, 저희는 버튼 컴포넌트에서 disabled 상태를 받아 HTML 엘리먼트의 disabled 속성이 아닌 aria-disabled 속성으로 적용하도록 변경했습니다.

 

또한, 버튼의 기본 동작을 막아 클릭 이벤트가 실행되지 않도록 처리했어요.

 

아래 코드를 보면 더 이해가 쉬우실 것 같습니다.

interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {}

export default function Button(props: ButtonProps) {
  const { disabled, onClick, ...rest } = props;

  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    if (disabled) {
      e.preventDefault();
    }

    onClick?.(e);
  };

  return (
    <StyledButton aria-disabled={disabled} onClick={handleClick} {...rest} />
  );
}

const StyledButton = styled.button`
  &[aria-disabled="true"] {
    cursor: not-allowed;
  }
`;

 

3. Input과 Label 연결하기

 

모든 입력 필드에는 반드시 label을 지정해야 합니다. 디자인상 숨길 필요가 있더라도 forid 속성을 사용해 DOM에 포함해야 하며, placeholderlabel을 대신할 수 없습니다. (입력을 시작하면 사라지니ㅠ)

 

또한, 입력 형식이 필요한 경우 이를 명확하게 표시해야 하며, 필수 입력 필드인지 여부도 전달되어야 합니다. 만약 모든 필드가 필수라면, 개별 필드마다 표시하기보다는 Form 상단에 안내 메시지를 추가하는 것이 더 효과적입니다.

<label for="ssn">Social Security Number (xxx-xxx-xxx) (required)</label>
<input type="text" name="ssn" id="ssn" required />

 

 

혹은 아래와 같이 구현하여 암시적 레이블링을 사용하는 방법도 있습니다.

<label>Social Security Number (xxx-xxx-xxx) (required)
  <input type="text" name="ssn" required />
</label>

 

4. Form 에러 처리시 고려할 점

 

유효하지 않은 입력 필드에 대해 에러 메세지를 제공할 때도 주의할 점이 있습니다. 각 input은 aria-described-by/ id 속성 쌍을 통해 해당 error 컨테이너에 매핑되어야 합니다. 

 

그리고 접근성 트리에서 매핑을 수행할 수 있도록 오류 컨테이너는 오류 발생 여부와 관계없이 DOM에 항상 존재해야 하며, JavaScript로 동적으로 삽입되지 않도록 하는 것이 좋습니다.

<label for="age">Age</label>
<input type="number" name="age" id="age" aria-describedby="age-errors" />
<div id="age-errors"></div>

 

또 오류가 발생했을 때 해당 필드로 초점을 이동해주면 사용자가 더욱 편리하게 사용할 수 있습니다 :) 

 

5. 화면 확대기 사용자를 고려하기

 

저도 화면 확대/축소 기능을 자주 사용하지만, 저시력자인 사용자들에게는 필수적인 기능입니다.

그런데 일부 웹사이트에서는 <meta> 태그를 사용해 확대/축소 기능을 비활성화하는 경우가 있는데, 이는 접근성 측면에서 바람직하지 않습니다.

 

사용자들이 자유롭게 화면을 확대할 수 있도록 설정을 제한하지 않는 것이 중요합니다. 화면 확대기 사용자를 고려해 개발자로서 신경 써야 할 몇 가지 사항을 정리해 보았습니다. 😊

 

때론 hover말고 클릭을 사용하기

 

위와 같은 툴팁이 떴을 때 글자를 확대하려고 마우스를 가져가면 오른쪽 화면처럼 사라져버립니다. 이럴 때 hover가 아니라 클릭을 사용해 구현하면 툴팁이 사라지지 않겠죠?

 

안내문은 실행된 곳과 가까이 위치하게 하기

 

위와 같이 에러 안내문이 화면 맨 위에 위치하게 되면 확대를 하다가 놓치는 경우가 생깁니다. 패스워드가 틀렸다면 패스워드 근처에 에러 메세지가 떴을 때 유저가 놓치지 않도록 할 수 있습니다.

 

한 열에 최대한 많은 정보 넣기

 

 

화면 확대기를 사용하는 사용자는 다른 사용자만큼 개요를 잘 볼 수 없습니다. 따라서 form과 문서에서 두 번째 열을 놓칠 가능성이 높습니다. 위 form에서 화면 확대기를 사용하는 사용자는 필수 필드인 '메시지'가 별도의 열에 있기 때문에 놓칠 수 있습니다.


여기까지 프론트엔드 개발자가 접근성을 고려해 체크해 보면 좋을 사항들을 정리해 보았습니다.

 

이 외에도 컴포넌트별 적절한 aria 및 role 속성 추가, 모달을 Esc 키로 닫을 수 있도록 설정, Skip to Content’ 버튼 제공 등 고려할 요소들이 정말 많습니다. 제가 번역한 A11Y Calendar에도 좋은 내용이 많으니, 관심 있으신 분들은 한 번씩 읽어보셔도 좋을 것 같습니다. 😊

 

제가 말씀드린 내용이 실무에서도 도움이 되었으면 좋겠네요!

지금까지 읽어주셔서 감사합니다. 🙌✨

 

 

 

 

출처

https://kittygiraudel.com/2020/12/01/a11y-advent-calendar/

 

A11y Advent Calendar

I’m Kitty Giraudel, a non-binary trans frontend developer based in Berlin, focused on accessibility and inclusivity.

kittygiraudel.com

https://axesslab.com/make-site-accessible-screen-magnifiers/

 

How to make your site accessible for screen magnifiers | Axess Lab

There are around ten times as many people who use screen magnifiers than screen readers. However, focus always seems to fall on screen readers in…

axesslab.com