접근성을 고려한
UI 제작
Web Tech
Concert


seulbinim@gmail.com
김데레사
(HTML&CSS)
Web Tech
Concert

Part 1 . 웹접근성과 웹표준
Part 2 . 웹접근성을 고려한 HTML 마크업
Part 3 . 웹접근성을 고려한 디자인과 Animation
Web Tech
Concert

Web Tech
Concert

Visual
Studio
Code
Visual Studio Code, Microsoft
Code Editor
Web Tech
Concert

Live
Server
Extension
Part 1. 웹접근성과 웹표준


정보 격차 해소를 이끌어낸 이 시대의 영웅들
웹접근성(Web Accessibility)
웹사이트에서 제공하는 정보를 차별 및 제한없이 동등하게
이용할 수 있도록 보장하는 것

장애인 및 고령자를 포함한
모든 사람
다양한 platform 및
Device와 웹브라우저 등
모든 환경

카푸친 원숭이(Capuchin Monkey) 실험


평등 VS 공평
웹접근성을 고려한 UI 제작 준비

웹접근성 지침 준수
웹표준 기술의 활용
웹접근성 지침

웹표준 기술
웹에서 표준적으로 사용되는 기술이나 규칙

견고한
구조 설계를 위한
HTML
레이아웃 및
스타일을 위한
CSS
동작 및 제어를 위한 DOM과 Javascript
WAI-ARIA

WAI-ARIA 사례집
AOA YouTube 채널



특별한 도움을
필요로 하는 이들을 위해
길을 닦는 것은
모두를 위해
길을 닦는 것과
같습니다.


고객 감동은
바로 이런 모습과 태도가 아닐까요?
Part 2. HTML 마크업

웹접근성을 고려한



실습 예제

기본 언어 설정 및 문서 제목

<!DOCTYPE html>
<html lang="ko-KR">
<head>
<meta charset="UTF-8">
<title>이디야(Ediya)</title>
......
</head>
html 요소에 기본 언어로 한국어 설정과
적절한 제목을 지정해 보시기 바랍니다.

콘텐츠 구조(HTML5)

1
2
3
<body>
<header>
헤더
</header>
<main>
메인
</main>
<footer>
푸터 (숨김 콘텐츠)
</footer>
</body>

콘텐츠 구조 (WAI-ARIA)

1
2
3
<body>
<div role="banner">
헤더
</div>
<div role="main">
메인
</div>
<div role="contentinfo">
푸터 (숨김 콘텐츠)
</div>
</body>
헤더 및 메인과 푸터 콘텐츠에 적절한
ARIA 역할을 지정해 보세요.

콘텐츠 제목

1
2
3
Text
<body>
<header class="app-header">
<h1 class="brand">
<a href="#">EDIYA COFFEE</a>
</h1>
<nav class="app-navigation">
<h2 class="a11y-hidden">
메인 메뉴
</h2>
</nav>
</header>
<main class="app-main">
<h2 class="a11y-hidden">
이디야 음료
</h2>
</main>
</body>
SEO와 보조 기기를 위한 제목 제공


HTML의 제목 관련 요소를 사용하여
콘텐츠에 대한 제목을 지정해 보세요.
단, 계층 구조를 건너뛰지 않도록
주의 하시기 바랍니다.
Voice Over의 로터 기능을 사용한 "제목 간 탐색"




1
2
3
메인 메뉴

<button> 메뉴 열기
<nav>
<button> 메뉴 닫기
<h2> 메인 메뉴(숨김 제목)
<ul> 메뉴 목록 ...

<button type="button" class="button is-open-menu"
title="메뉴 열기" aria-label="메뉴 열기">
<span class="ir"></span>
</button>
<nav hidden class="app-navigation">
<h2 class="a11y-hidden">메인 메뉴</h2>
<ul class="reset-list">
<li><a href="#">메뉴</a></li>
<li><a href="#">이디야멤버스</a></li>
<li><a href="#">이디야커피랩</a></li>
<li><a href="#">이디야컬쳐랩</a></li>
<li><a href="#">공지사항</a></li>
<li><a href="#">매장찾기</a></li>
</ul>
<button type="button" class="button is-close-menu"
title="메뉴 닫기" aria-label="메뉴 닫기">
<span class="close" aria-hidden="true">x</span>
</button>
</nav>
"title 속성(attribute)은 툴팁에 적절할 것 같은 조언 정보를
나타냅니다. 링크에서, 이것은 제목(title)이나 대상 리소스의 설명이
될 수 있고 이미지에서, 이미지 제공자(image credit)나 이미지의 설명,
문단에서, 텍스트의 각주나 주석, 인용구에서 소스에 대한 추가적인 정보,
대화형(interactive) 콘텐츠에서, 요소(element)의 사용에 대한
레이블이나 지시사항 등등이 될 수 있습니다.
메인 메뉴 제어 버튼에 ARIA 관련 속성을 사용하여 레이블을 제공해 보세요.
또한 보조기기가 인식하지 않아야 하는 정보를 찾아 ARIA 속성을 지정해 보세요
메인 메뉴


음료 정보
1
2
1
2
1
2
3
4

<ul> 음료 목록
<li> 음료
<a>
<div>
<a>
<figure>
<img>
<figcaption>

<div>
<h3>
<p>
<div>
<dl>
<button> 모달 닫기
<ul> 음료 목록
<li> 음료
<a>
<div>

<ul class="ediya-menu reset-list">
<li class="ediya-menu__item">
<a href="#" role="button"
aria-haspopup="dialog"
aria-pressed="false">
<figure>
<img
src="./images/iced-cherry-blossoms-latte.png"
alt
width="323"
height="323"
>
<figcaption>ICED 벚꽃라떼</figcaption>
</figure>
</a>
</li>
......
</ul>
a 요소는 해당 음료 이미지를 Clickable한 콘텐츠로 만들기 위해
사용했으나 스크린 리더 등의 보조 기기 사용자는 링크 기능으로
오인할 수 있습니다.
또한 a 요소를 클릭할 경우 팝업(모달)이 실행되는데 보조기기
사용자가 해당 버튼을 클릭 시 팝업(모달)이 실행된다는 것을
인지할 수 있도록 제공하는 것이 필요 합니다.
이 문제를 해결하기 위해 ARIA의 역할 모델인 role 속성으로
링크가 아닌 button으로 인식될 수 있도록 수정하고
버튼의 실행으로 인해 팝업이 실행된다는 사실을 알 수 있도록
ARIA 속성을 제공해 보시기 바랍니다.
이때 해당 버튼은 선택되지 않은(눌러지지 않은) 상태임도 함께
알려주어야 합니다.
링크 요소를 버튼으로 역할 변경하기

<div class="ediya-menu__item--detail" hidden
role="dialog" aria-modal="true" aria-labelledby="ediya-menu__item1">
<h3 id="ediya-menu__item1" class="ediya-menu__item--name">
ICED 벚꽃라떼
<span lang="en">Cherry Blossom Latte</span>
</h3>
<p>은은한 벚꽃향과 라즈베리 화이트 초콜릿 토핑이 올라간 핑크빛 라떼</p>
<div class="ediya-menu__item--multi-column is-2">
<dl>
<dt>칼로리</dt> <dd>(393kcal)</dd>
<dt>당류</dt> <dd>(35g)</dd>
......
</dl>
</div>
<button type="button" class="button is-close-panel"
title="닫기" aria-label="음료 정보 패널 닫기">
<span aria-hidden>×</span>
</button>
</div>
hidden 속성은 HTML5에 추가된 논리속성으로 해당 속성이
선언 될 경우 화면에도 보이지 않고 보조 기기에서도
인식할 수 없는 콘텐츠가 됩니다.
javascript를 사용하여 hidden 속성을 삭제하면 음료 정보로
접근할 수 있습니다. 이때 음료 정보가 팝업(모달)으로 제공됨을
알 수 있도록 role="dialog"를 선언하고 aria-modal 속성의
값을 true로 지정해 보시기 바랍니다.
이때 팝업 창의 경우 레이블이 필요하기때문에 팝업 내 콘텐츠 중
제목 요소를 aria-labelledby 속성의 값으로 제공하였습니다.
팝업 창 정보 제공하기

지금까지 작성한 마크업이
문법적 오류가 없는지
검증해 보시기 바랍니다.
HTML Validation(유효성 검사)
Part 3. 디자인과 Animation

웹접근성을 고려한

.a11y-hidden {
position: absolute !important;
clip: rect(0, 0, 0, 0);
clip-path: polygon(0 0, 0 0, 0 0);
width: 1px;
height: 1px;
margin: -1px;
overflow: hidden;
white-space: nowrap;
}
display: none; 을 사용하여 콘텐츠를 숨길 경우
스크린리더 등 보조기기가 인식할 수 없는 문제가 있음.
숨김 콘텐츠




색상에 의존한 정보 제공


전경 색상과 배경 색상의 명도 대비


이웃한 콘텐츠 간의 구분


CSS3 Animation
Fade Slide In from Top
Fade Slide In from Left
Fade In
Fade Slide Up from Bottom
Overview
1
2
3
4
5
6
7
Sequence Animation

name / duration / delay / timing function / fill-mode | @keyframes

CSS3 Animation
Timing Function | Cubic Bezier

CSS3 Animation
Fade In
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
button[title="메뉴 열기"] {
opacity: 0;
animation:
fade-in /* name */
0.35s /* duration */
0.4s /* delay */
ease-out /* timing function */
forwards; /* fill mode */
}

CSS3 Animation
Fade Out
@keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.button[title="메뉴 열기"] {
animation:
fade-out
0.35s
0.4s
ease-out
forwards;
}

CSS3 Animation
Fade Slide In From Top
@keyframes fade-slide-in-from-top {
0% {
transform: translateY(-4rem);
opacity: 0;
}
100% {
transform: none;
opacity: 1;
}
}
.app-header {
opacity: 0;
animation:
fade-slide-in-from-top
0.35s
0.4s
ease-out
forwards;
}

CSS3 Animation
Fade Slide In From Left
@keyframes fade-slide-in-from-left {
0% {
transform: translateX(-4rem);
opacity: 0;
}
100% {
transform: none;
opacity: 1;
}
}
.brand {
opacity: 0;
animation:
fade-slide-in-from-left
0.35s
0.4s
ease-out
forwards;
}

CSS3 Animation
Fade Slide In From Right
@keyframes fade-slide-in-from-right {
0% {
transform: translateX(4rem);
opacity: 0;
}
100% {
transform: none;
opacity: 1;
}
}
.brand {
opacity: 0;
animation:
fade-slide-in-from-right
0.35s
0.4s
ease-out
forwards;
}

CSS3 Animation
Fade Slide In From Bottom
@keyframes fade-slide-in-from-bottom {
0% {
transform: translateY(4rem);
opacity: 0;
}
100% {
transform: none;
opacity: 1;
}
}
.ediya-menu__item {
opacity: 0;
animation:
fade-slide-in-from-bottom
0.35s
0.4s
ease-out
forwards;
}

CSS3 Animation
@keyframes transform-none {
to {
transform: none;
opacity: 1;
}
}
Effective Management
.app-header {
/* 0% */
opacity: 0;
transform: translateY(-4rem);
/* 100% */
animation: transform-none 0.35s 0.4s ease-out forwards;
}

CSS3 Animation
Effective Management
.brand {
/* 0% */
opacity: 0;
transform: translateX(-4rem);
/* 100% */
animation: transform-none 0.3s 0.7s cubic-bezier(0, 0, 0.23, 1.43) forwards;
}
button[title="메뉴 열기"] {
/* 0% */
opacity: 0;
transform: translateX(4rem);
/* 100% */
animation: transform-none 0.45s 0.65s cubic-bezier(0, 0, 0, 1) forwards;
}

CSS3 Animation
.ediya-menu__item {
/* 0% */
opacity: 0;
transform: translateY(4rem);
/* 100% */
animation: transform-none 0.3s 0.85s cubic-bezier(0.6, 0.01, 0.16, 1) forwards;
}
/* 시간 차 애니메이션 */
.ediya-menu__item:nth-child(1) { animation-duration: 0.8s }
.ediya-menu__item:nth-child(2) { animation-duration: 1.2s }
.ediya-menu__item:nth-child(3) { animation-duration: 1.6s }
.ediya-menu__item:nth-child(4) { animation-duration: 2.0s }


CSS3 Animation

CSS3 Animation
접근성 고려


CSS3 Animation

CSS3 Animation
A11y Class 활용 (코드 재사용을 위한)

UI Interaction
Needs JavaScript Programming
CSS 애니메이션을 사용해 UI 모션을 구현 적용할 수
있으나, 사용자의 요구에 맞는 동작을 작동시키려면
JavaScript 프로그래밍이 필요합니다.


Thanks!
웹접근성을 고려한 UI 제작 — Web Tech Concert 2019
By seulbinim
웹접근성을 고려한 UI 제작 — Web Tech Concert 2019
웹 테크 콘서트 2019 UI 제작 강의 슬라이드
- 410