웹 접근성은 웹 사이트, 도구, 기술이 장애를 가진 사용자들이 사용할 수 있도록 설계 및 개발된 것을 말한다. 여기서 장애는 웹에 접근하는 데에 영향을 주는 모든 장애 (청각, 인지, 신경, 신체, 언어, 시각)를 포함한다.
한편, 다음과 같은 사례를 보아 알 수 있듯, 장애를 갖지 않은 사용자에게도 웹 접근성은 유의미하다.
웹의 힘은 보편성에 있습니다. 장애에 상관없이 모두가 접근할 수 있다는 것이 가장 중요한 부분입니다. - 팀 버너스리, W3C 디렉터 및 World Wide Web의 창시자
어떤 운영체제나 브라우저에서든 사용자들이 동일한 콘텐츠를 볼 수 있도록 웹페이지를 만들 때 지켜야 하는 규칙을 말한다.
img 태그에는 적절한 대체 텍스트가 alt 속성을 통해 제공되어야 한다.
ARIA(Accessible Rich Internet Applications)은 장애를 가진 사용자가 웹 콘텐츠와 웹 어플리케이션(특히 JavaScript를 사용하여 개발한 경우)에 더 쉽게 접근할 수 있는 방법을 정의하는 여러 특성을 말한다.
대부분의 위젯은 최근에 HTML5 자체적으로 대체되었으므로, 되도록 HTML5로 ARIA를 충분히 대체할 수 있는 경우에는 ARIA 사용을 지양한다. 즉, 시멘틱 태그를 사용하는 것만으로도 충분한 경우를 말한다.
역할(Role), 속성(Property), 상태(State) 정보를 제공하여 접근성을 개선할 수 있도록 지원한다.
UI에 포함된 특정 컴포넌트의 역할을 정의하며, role=속성명
과 같이 사용할 수 있다.
속성명 | 설명 |
---|---|
banner | 일반적으로 로고, 회사 이름, 검색 기능, 글로벌 내비게이션 또는 슬로건을 포함하는 글로벌 사이트 헤더를 정의하며, 일반적으로 페이지 상단에 위치함 |
속성은 컴포넌트의 특징이나 상황을 정의하며 aria=*
접두사를 사용하고, 상태는 컴포넌트의 상태 정보를 정의한다.
접미사 | 설명 | 옵션 |
---|---|---|
label | 상호작용되는 html 요소에 label된 문자열 값(간단한 설명)을 정의 | |
live | 실시간으로 변화하는 콘텐츠를 사용자에게 즉시 알림 | off(default), polite, assertive |
메인페이지 Lighthouse 성능 측정 시, Accesibility에서 아래와 같은 경고가 뜬다.
‘Heading levels should only increase by one’
이는 h 제목 태그가 1부터 하나씩 순차적으로 나와야 함을 의미한다. footer의 바로가기 링크를 보여주는 부분에서, h4 태그가 h1,h2,h3의 앞선 제목 태그 없이 바로 나오고 있었다. 스크린 리더는 hn 태그를 ‘제목 n’이라고 읽는다. 따라서 스크린 리더의 도움을 받는 사용자(이하 스크린 리더 사용자)의 경우, 이를 통해 본문의 구조를 파악할 수 있다.
가령, 바로가기 링크에서 세부적으로 ‘교내 사이트 바로가기’, ‘교외 사이트 바로가기’라는 세부 분류가 추가되었다고 하자. 이 때, ‘바로가기’와 두 개의 세부분류의 h 태그가 역전되어 있거나 순서대로 지정되어 있지 않는다면 스크린 리더 사용자가 본문의 구조를 파악하기 힘들 것이다.
Axe Rules | Deque University | Deque Systems
사진 게시판 목록의 썸네일 이미지는 기존의 대체 텍스트에는 단순히 썸네일 이미지임을 알려주고 있었다. 하지만 이렇게 하면 스크린 리더는 모든 썸네일을 구분하지 못하고 스크린 리더 사용자도 자신이 보고 싶은 앨범으로 한 번에 들어갈 방법이 없을 것이다. 따라서 서버에서 넘어온 값들 중 하나인 ‘앨범 제목’을 활용했다 대체 텍스트에 적용했다.
{/* 썸네일 이미지 */}
<img
src={StringCombinator.getImageURL(thumbnailData.saveFilePath, thumbnailData.saveFileName)}
alt='photo-album_thumbnail'
className='ThumbnailImage'
/>
{/* 썸네일 이미지 */}
<img
src={StringCombinator.getImageURL(thumbnailData.saveFilePath, thumbnailData.saveFileName)}
alt={`${thumbnailData.title} 앨범의 썸네일`}
className='ThumbnailImage w-full'
/>
메인 페이지의 로고
현재 동아리 홈페이지 메인페이지의 배너에는 위와 같이 동아리 로고가 위치한다.
<Link to={'/'}>
<div className='h-[4rem] w-[12rem] md:w-[14rem] lg:w-[16rem] xl:w-[18rem]'>
<img
className='h-full w-full object-contain'
src={'/_assets/images/nestnet-logo-primary.png'}
alt={'NestNetLogo'}
/>
</div>
</Link>
변경 전의 코드에서는 스크린 리더는 해당 부분을 단순히 ‘링크’임을 인식할 뿐이었다.<Link to={'/'} role='banner'>
<div className='h-[4rem] w-[12rem] md:w-[14rem] lg:w-[16rem] xl:w-[18rem]'>
<img
className='h-full w-full object-contain'
src={'/_assets/images/nestnet-logo-primary.png'}
alt={''}
/>
</div>
</Link>
banner 역할을 부여하고, 이미지가 중요 부분이 아니라고 판단하여 alt에 빈 값을 부여하였다. 참고 링크 중 우아한 기술 블로그에 ‘alt 속성을 없애는 것이 아닌 빈 값을 넣어 주어야 하는 이유는 스크린리더기가 이미지의 alt 속성이 없는 경우 이미지명을 읽어주기 때문에요.’ 실제로 스크린 리더를 실행했을 때도 alt 속성을 없앤 경우에는 ‘이미지’를 앞에 붙여 말하는 것을 확인할 수 있다. (제가 해석한 ‘이미지명’이 이게 맞는지는 정확하지가 않네요. 정확히 아시는 분이 계시다면 알려주시면 좋을 것 같아요ㅎ)에러 메시지
{/* 제목 작성란 */}
<label htmlFor='title'>
{errors.title?.message && errors?.title?.type === 'required' && (
<span className={'m-1 text-sm text-secondary'}>
※ {errors.title.message}
</span>
)}
<input />
</label>
{/* 제목 작성란 */}
<label htmlFor='title'>
{errors.title?.message && errors?.title?.type === 'required' && (
<span role='alert' className={'m-1 text-sm text-secondary'}>
※ {errors.title.message}
</span>
)}
<input />
</label>
aria-label
을 사용해 ‘출석 체크’ 버튼임을 명시해보자. <button
className={`relative h-[4rem] w-[4rem] cursor-pointer ...`}
onClick={() => createMyAttd()}
disabled={isMyAttdPending}
>
<div className=''>
<FaCalendar className='text-2xl' />
</div>
</button>
<button
aria-label='출석 체크'
className={`relative h-[4rem] w-[4rem] cursor-pointer ...`}
onClick={() => createMyAttd()}
disabled={isMyAttdPending}
>
<div className=''>
<FaCalendar className='text-2xl' />
</div>
</button>
참고자료