Replies: 12 comments
-
👑행동대장토다리, 쿠키, 소하, 웨디 우리 서비스의 핵심 영역지출내역 생성 : 지출내역 추가하기 버튼 -> 사용 금액 입력 -> 사용 내역 입력 -> 참여 인원 입력 -> 지출 내역 생성 완료 접근성 문제 정의 및 개선 계획Title 스크린 리더 끊어 읽힘구현 목적 핵심 flow인 지출내역 생성에서 스크린리더를 사용하는 유저는 header를 제외하고는 가장 먼저 Top을 듣게 될 것입니다. Top 컴포넌트는 해당 페이지에 대한 설명을 담은 컴포넌트로, 스크린리더 사용자는 해당 페이지에서 어떤 것을 입력해야 하는지 듣게 됩니다. 그런데, 기존의 Top 컴포넌트의 text는 끊어서 읽혔습니다. 이런 점은 스크린리더 사용자에게 혼동과 불편함을 주게 될 것입니다. 따라서, Top 컴포넌트를 스크린리더가 읽혔을 때 내용이 한번에 읽히도록 수정합니다. 개선 전/후 영상🔇 영상 속 스크린리더기는 음성을 사용하지 않습니다!
구현 방법 const [childrenTexts, setChildrenTexts] = useState<string[]>([]);
useEffect(() => {
const collectedTexts: string[] = [];
React.Children.forEach(children, child => {
if (React.isValidElement(child) && child.type === Top.Line) {
collectedTexts.push(child.props.text);
}
});
setChildrenTexts(collectedTexts);
}, [children]);
return (
<div
css={css`
display: flex;
flex-direction: column;
`}
aria-label={childrenTexts.join(' ')}
tabIndex={0}
>
{children}
</div>
);
export default function Line({text, emphasize = []}: Props) {
// ...
{elements.map((text, index) => {
return (
<Text
key={`${text}-${index}`}
size="subTitle"
textColor={emphasize.includes(text) ? 'black' : 'gray'}
style={{whiteSpace: 'pre'}}
aria-hidden={true}
>
{`${text}`}
</Text>
);
})}
}
넘버 키패드 스크린 리더구현 목적 현재는 위 영상에서 00 버튼을 '공' 버튼이라고 읽습니다. 그래서 넘버 키패드 00을 추가로 지우기 버튼도 개선 전/후 영상
구현 사항
const amountKeypads = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '00', '0', '<-']; 여기에 스크린 리더가 읽어야 할 label 속성을 추가했습니다. {
keypad: '1',
label: '1',
}, 스크린 리더가 읽는 값과 화면에 표시되는 값을 다르게 설정하는 방식으로 구현했습니다. X 버튼 스크린리더 cursor구현 목적 개선 전/후 영상
구현 방법 x버튼은 따라서 IconButton컴포넌트로 Icon컴포넌트를 감싸주었습니다. <IconButton variants="none">
<Icon iconType="inputDelete" onClick={onClick} />
</IconButton> 이렇게 바꾸면 바라던대로 커서는 향하지만 "버튼"이라고만 읽히게 됩니다. export const ICON = {
inputDelete: <InputDelete aria-label="지우기" />,
rightChevron: <RightChevron aria-label="더보기" />,
search: <Search aria-label="검색" />,
error: <Error aria-label="오류" />,
confirm: <Confirm aria-label="확인" />,
trash: <Trash aria-label="삭제" />,
trashMini: <TrashMini aria-label="삭제" />,
check: <Check aria-label="선택" />,
x: <X aria-label="x" />,
pencilMini: <PencilMini aria-label="수정" />,
toss: <img src={Toss} width="16" height="16" alt="toss icon" />,
meatballs: <Meatballs aria-label="메뉴" />,
editPencil: <EditPencil aria-label="수정" />,
heundeut: <img src={`${process.env.IMAGE_URL}/heundeut.svg`} aria-label="행동대장 로고" />,
photoButton: <PhotoButton aria-label="사진" />,
} as const; alt가 아닌 aria-label을 사용한 이유는 svg파일에는 alt 속성이 없어서 입니다. |
Beta Was this translation helpful? Give feedback.
-
리뷰미⭐ 우리 서비스의 핵심 영역리뷰 작성 페이지: 강점 강화 선택 -> 꼬리 질문 선택 -> 단점 피드백 -> 추가 리뷰 -> 리뷰 작성 확인 및 제출 🤔 리뷰 작성 페이지의 접근성 문제 및 개선 계획키보드 조작
스크린 리더
✨ 실제 개선 과정과 결과키보드 조작현재 작성 중이 아닌 다른 리뷰카드로 이동 막기현재 카드의 포커스 가능한 요소 중 마지막 요소에 포커스가 되어있고, Tab키를 눌렀을 때 footer로 이동하는 기능을 구현했다. 버튼 활성화 여부의 변환를 감지해 해당 기능을 실행하게 했다. Tab을 사용해 BreadCrumb로 페이지 이동 가능React Router의 Tab으로 모달 내에서만 이동키보드의 탭과 스크린 리더의 포커스가 모달 영역 내부에서만 순환하도록 하는 FocusTrap 컴포넌트를 구현해, FocusTrap으로 모달 컴포넌트를 감싸서 문제를 해결했다. 키보드 조작만으로 리뷰 작성 가능
스크린 리더모달이 열렸을 때 안내 및 내용 읽어주기
모달 내에서만 포커스 이동모달이 마운트 되었을 때, body 하위의 모달을 포함하지 않는 영역에 리뷰 작성 페이지 버튼 접근성 개선
리뷰 작성 진행 상황 안내state와 에러 발생 시 메시지 안내ref와 체크 박스 선택 여부 안내
영상키보드 조작https://github.com/user-attachments/assets/80948271-f159-4cd7-8434-8e4bc8e5de5d https://github.com/user-attachments/assets/28f7841e-d189-4a99-bd31-bd7b7c612a38 스크린 리더https://github.com/user-attachments/assets/f34032fd-8274-4aed-8414-f3f81bbdc542 https://github.com/user-attachments/assets/5c1c4d80-de6f-4630-99fc-c1cbd173666e |
Beta Was this translation helpful? Give feedback.
-
투룻지니, 시모, 리버 우리 서비스의 핵심 영역메인 페이지 내 마음에 드는 여행기 탐색 -> 로그인이 되지 않아 로그인 페이지로 이동 -> 여행기를 여행 계획으로 전환 -> 여행 계획 등록 -> 여행 계획 확인 해당 핵심 영역에서의 접근성 문제 정의 및 개선 계획공통 (Modal, Drawer)Modal,Drawer접근성 문제 정의
개선 계획
메인 페이지접근성 문제 정의
개선 계획
로그인 페이지접근성 문제 정의
개선 계획
여행기 상세 페이지접근성 문제 정의
개선 계획
여행 계획 상세 페이지접근성 문제 정의
개선 계획
여행 계획 등록 페이지캘린더가 열리지 않는 문제<TextField
title="시작일"
subTitle="시작일을 선택하면 마감일은 투룻이 계산 해드릴게요!"
isRequired
>
{(id) => (
<>
<Input
// ...
onClick={handleOpenCalendar}
/>
{isShowCalendar && (
<Calendar
onSelectDate={(date) => handleSelectStartDate(date, handleCloseCalendar)}
onClose={handleCloseCalendar}
/>
)}
</>
)}
</TextField> 캘린더의 경우 click event를 통해서만 열릴 수 있도록 되어있기 때문에, 시각 장애인의 경우 클릭 영역을 명확히 알지 못하는 문제가 있었습니다. 따라서, 시작일을 입력할 수 없어 여행 계획 등록 자체가 불가능한 문제가 있었습니다. 캘린더 각 날을 tab 할 수 있도록 변경<S.DayCell
onClick={() => isSelectable && onSelectDate(date)}
>
<Text textType="detail">{isCurrentMonth ? date.getDate() : ""}</Text>
</S.DayCell> 캘린더가 열릴 경우 각 DayCell이 onClick 이벤트만 되어있기 때문에 시각 장애인의 경우 어떤 일자도 선택할 수 없다는 문제가 있었습니다. 위 문제와 마찬가지로 시작일이 선택이 되지 않아 등록이 안된다는 문제가 있었습니다. 실제 개선 과정과 결과(개선 후 재측정)공통Modal, Drawer
Header
메인 페이지
여행기 상세 페이지
접근성 개선 후 영상 2024-10-23.12PM.mov여행 계획 상세 페이지
접근성 개선 후 영상 2024-10-23.12.36PM.mov여행 계획 등록 페이지캘린더가 열리지 않는 문제<Input
// ...
onKeyDown={handleEnterCalendarInput}
/>
const handleEnterCalendarInput = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === "Enter") {
handleOpenCalendar();
}
if (event.key === "Escape") {
handleCloseCalendar();
}
}; onKeyDown 이벤트를 통해 enter를 눌렀을 경우 캘린더를 열도록, esc를 누를 경우 캘린더를 닫을 수 있도록 로직을 추가했습니다. <VisualHidden>
{isShowCalendar
? "캘린더가 열렸습니다. esc 키를 누르면 캘린더를 닫을 수 있습니다."
: "캘린더가 닫혔습니다. shift tab 후 enter 키를 누르면 캘린더를 다시 열 수 있습니다."}
</VisualHidden>
캘린더 각 날을 tab 할 수 있도록 변경const handleKeyDown = (
event: React.KeyboardEvent<HTMLElement>,
date: Date,
isSelectable: boolean,
) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
if (isSelectable) {
onSelectDate(date);
}
}
};
<S.DayCell
onKeyDown={(event) => handleKeyDown(event, date, isSelectable)}
tabIndex={isSelectable ? 0 : -1}
aria-label={formattedDate}
>
<Text tabIndex={-1} aria-hidden="true" textType="detail">
{isCurrentMonth ? date.getDate() : ""}
</Text>
</S.DayCell> tabIndex를 동적으로 줌으로써, 선택 가능한 날짜들에 대해 tab으로 선택이 가능하며, aria-label을 통해 어떤 날짜인지 스크린 리더기가 읽을 수 있도록 변경했습니다. 또환, onKeyDown을 통해 선택하고 싶은 시작일자를 enter로 선택할 수 있도록 개선했습니다. 또한, Text 컴포넌트에 tabIndex와 aria-hidden 속성을 통해 aria-label을 읽고, text는 읽지 않도록 개선했습니다. 개선 결과lighthouse before & after lighthouse의 점수 상으론 크게 차이가 없었습니다. 2024-10-21.5.54.32.1.mov영상으로 확인해보면, 이제 시각 장애인도 무리 없이 여행 계획 등록이 가능한 것을 확인할 수 있습니다. |
Beta Was this translation helpful? Give feedback.
-
데벨업 - 프룬, 버건디, 라이언우리 서비스의 핵심 영역데벨업의 핵심 행동은 미션을 풀고 제출하는 행동입니다. 해당 핵심 영역에서의 접근성 문제 정의 및 개선스크린 리더 사용자가 데벨업의 핵심 행동을 수행할 수 있도록, '미션 리스트 -> 미션 상세 페이지 -> 미션 진행 모달 -> 미션 제출하기'에 대한 접근성을 개선했습니다. 실제 개선 과정과 결과(개선 후 재측정)핵심 행동을 수행하기 위해 거치는 페이지들의 접근성을 개선했습니다. 구체적으로는 aria 속성 사용, 시맨틱 태그 사용, heading 태그 사용을 통한 페이지 구조화, 키보드 접근성 고려를 통해 접근성을 개선했습니다. 수업 시간에 작성한 표를 바탕으로, 데벨업의 핵심 플로우인 미션을 푸는 과정을 중심으로 우선순위를 설정했습니다. 측정을 위해 크롬 스크린리더를 사용했습니다. Chrome Extensions에서 스크린 리더로 가장 많이 사용되는 것을 기준으로 선택했습니다.
github.mp4inflearn.mp4toss.mp41. 랜딩페이지(헤더)따라서 헤더에서 랜딩 페이지로 이동할 때, 랜딩 페이지의 ‘아래화살표’ 버튼으로 바로 탭이 이동할 수 있도록 지정했습니다. header.mp4header2.mp42. 미션 리스트 페이지스크린 리더 사용자가 미션 리스트 페이지에서 각 미션 항목에 대한 정보를 제공받을 수 있도록 접근성을 개선했습니다. missionList.mp43. 미션 상세 페이지스크린 리더 사용자가 미션의 상세 정보를 듣고 진행할 수 있도록 접근성을 개선했습니다. “어떻게 진행하나요?” 클릭 시 열리는 모달의 내용도 스크린리더가 읽을 수 있도록 처리했습니다. missionDetail.mp44. 미션 풀이 제출 페이지스크린 리더 사용자가 다 푼 미션을 제출할 수 있도록 접근성을 개선했습니다. 제출페이지에서는 사용자가 본인이 제출하려는 미션에 대한 충분한 정보를 제공해야한다고 판단했습니다. aria-label 속성을 활용하여 제출하려는 미션에 대한 정보를 추가했습니다.
submit1.mp4submit2.mp4느낀 점접근성을 개선하면서 다양한 사용자들이 웹을 어떻게 경험하는지 이해하게 되었습니다. 처음에는 단순한 시각적 요소만을 고려했지만, 키보드 사용자, 시각 장애인 등 여러 환경에 처한 사용자들의 요구를 동등하게 반영해야 할 필요성을 느낄 수 있었습니다. 또한, 접근성 향상은 단지 특정 사용자를 위한 것이 아니라, 전체적인 사용자 경험을 개선하는 효과가 있다는 것을 느끼기도 했습니다. |
Beta Was this translation helpful? Give feedback.
-
🥜 땅콩마루, 썬데이, 포메 ✅ 우리 서비스의 핵심 영역방 참여 → 게임 초대 → 게임 시작 → 옵션 선택 → 라운드 결과 해당 핵심 영역에서의 접근성 문제 정의 및 개선 계획개선 최종 목표: 땅콩을 스크린리더로 무리 없이 사용할 수 있다.
우선순위 결정개선 기준1.Semantic tag를 쓰자 2.ARIA 속성은 꼭 필요한 경우에만 사용한다 3.문서를 잘 읽자 4.스크린리더 전용 컴포넌트를 사용하자 ✅ 닉네임 페이지문제 상황
개선 결과
✅ 대기 방 페이지문제 상황
개선 결과
✅ 게임 페이지문제 상황
개선 결과
✅ 공통 컴포넌트 (A11yOnly)시각적으로 보이지 않는 요소 A11yOnly 컴포넌트를 사용하여 개선import { ElementType, AriaRole, PropsWithChildren } from 'react';
import { a11yOnlyLayout } from './A11yOnly.styled';
interface A11yOnlyProps<T extends ElementType = 'span'> {
as?: T;
role?: AriaRole;
}
const A11yOnly = <T extends ElementType = 'span'>({
as,
children,
...props
}: PropsWithChildren<A11yOnlyProps<T>>) => {
const Component = as || 'span';
return (
<Component css={a11yOnlyLayout} {...props}>
{children}
</Component>
);
};
export default A11yOnly; 접근성 전용 컴포넌트를 사용한 이유두 가지 방향으로 코드를 작성해 보고, A11yOnly 컴포넌트를 적용한 코드가 가독성이 더 좋고 유지 보수를 하기에 용이하다고 생각했기 때문이다. 실제 개선 과정과 결과(개선 후 재측정)
✅ Modal Focus 개선Modal을 열었을 때 Modal 로 포커싱이 안되는 상황
Modal을 열고 닫을 때 focus가 제대로 된 위치를 찾지 못하고 있는 상황
페이지 로드 시 Header에 focus
방 설정 모달
타이머
매칭 결과
Modal
페이지 로드 시 Header focus
|
Beta Was this translation helpful? Give feedback.
-
🍀 '코딩해듀오' 접근성 개선 리포트우리 팀의 핵심 기능 플로우 나열하기
해당 핵심 영역에서의 접근성 체크리스트 정의✅ 페어룸 만들기
✅ 페어룸 유형 선택하기
✅ 페어룸 정보 입력하기 (페어룸 온보딩)
✅ 타이머 시작하기
✅ 타이머 중지하기
해당 핵심 영역에서의 접근성 문제 정의
|
Beta Was this translation helpful? Give feedback.
-
⚡️ 코드잽마스터위, 헤인, 월하 내용물이 많아 다음 깃헙 WIKI 링크로 대체하겠습니다~! 감사합니다. |
Beta Was this translation helpful? Give feedback.
-
🏠 방끗리안, 헤일리, 제이드 1. 시맨틱 태그를 잘 설정하였는가?페이지에서 사용되는 주요 공통컴포넌트 시맨틱태그를 적용하였습니다. 시맨틱 태그는 스크린 리더가 이를 기반으로 읽기 때문에 매우 중요하며, SEO에도 도움이 되기 때문에 1순위로 진행했습니다. 방끗이 semantic 태그를 쓴 기준은 다음과 같습니다.
시맨틱 태그를 쓸 때 참고한 문서는 다음과 같습니다. [참고한 MDN - article](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/article) [참고한 MDN - section](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/section) [w3school - semantic](https://www.w3schools.com/html/html5_semantic_elements.asp) 인풋필드에 label/input id, htmlFor을 연결한다.저희 방끗에서 공통적으로 사용하고 있는 FormField (라벨, 인풋, 에러 메세지가 묶인 컴포넌트) 에 다음과 같이 <FormField.Label label="방 크기" htmlFor="size" /> 2. 이미지와 아이콘에서 의미있는 정보를 제공하고 있는가?
3. 에러 메세지를 읽어주는가?
4.
|
탭 키보드 접근성 before | 탭 키보드 접근성 after |
before.mov |
after.mov |
---|
(2) 지도 모달을 스크린 리더로 동작시킬 수 있는가?
- 저희 체크리스트 작성에는 주소를 넣는 란이 있는데, 이는 실시간 주소, 주소 검색같은 ‘모달’ 을 사용해서 입력할 수 있습니다.
- 기존에 모달은 켜져도 focus 가 가지 않는 문제가 있었습니다. 또한 클릭외의 방법으로 모달을 끌 수 없어, 스크린 리더 사용자는 모달을 제대로 사용할 수 없는 문제가 있었습니다.
- 적용 방법 : 이를
FocusTrap
을 사용하여 모달이 켜지면, 해당 모달의 인풋, 버튼 같은 접근 요소에서만 포커스가 되고 자동으로 포커스가 돌도록 해주었습니다. 또한 스크린 리더기로도 모달을 x 버튼을 눌러 끌 수 있도록 해주었습니다.
지도 모달 before | 지도 모달 after |
before.mp4 |
after.mp4 |
---|
(3) 체크리스트 옵션, 체크리스트 질문 템플릿을 편집 선택 상황을 스크린 리더로 잘 알 수 있는가?
- 저희 체크리스트의 핵심 기능들은 집의 정보를 선택하는 부분이 많은데, 스크린 리더로 해당 옵션과 선택 유무를 알 수 없었습니다. 불필요한 요소의 포커스 및 메세지 부재, 스크린 리더로 상호작용 불가 등 다양한 문제점이 있었습니다.
- 적용 방법 : 이를 해결하기 위해
statusMessage
에visually-hidden
속성을 주어, 적절한 메세지가 전달되도록 하였습니다. 또한tabIndex
를 사용하여 포커스가 타겟 요소에만 가도록 했습니다.statusMessage
의 경우 응집성을 위해 보통 클릭 이벤트를 관리하는 hook 에서 처리하도록 하였습니다.
질문 o / x before | 질문 o / x after |
before.mp4 |
after.mp4 |
---|---|
옵션 before | 옵션 after |
before.mp4 |
after.mp4 |
질문 선택 before | 질문 선택 after |
before.mp4 |
after.mp4 |
로그인, 회원가입 키보드 접근성 개선
- 기존에는 디자인 특성상 auth 페이지에서 엔터로 submit 을 할 수 없었지만, 이는 키보드 접근성이 낮은 것 같아 해당 기능을 추가했습니다.
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
모우다 서비스의 핵심 영역
해당 핵심 영역에서의 접근성 문제 정의 및 개선
실제 개선 과정과 결과(개선 후 재측정)1. 로그인_.mp43. 다락방 생성 및 참여_.mp44. 모임 생성_.1.mp45. 모임 목록 조회2024-10-24.4.mp46. 모임 상세 조회 및 참여New.Project.-.Clipchamp.19.mp4New.Project.-.Clipchamp.18.mp4 |
Beta Was this translation helpful? Give feedback.
-
🍑 모모해리👎 빙봉🔮 낙타🐫 우리 서비스의 핵심 영역
약속 입장 페이지를 지나, 약속 현황 조회 페이지가 사용자가 가장 많이 들어오는 페이지이며 굉장히 많은 정보를 담고 있다고 판단하여 서비스의 핵심 영역을 약속 현황 조회 페이지로 선정했습니다. 그 중에서 스크린리더 사용자는 "약속을 생성하기는 어려워도 조회할 수 있다"에 초점을 맞추어 웹 접근성 개선을 시도했습니다. 개선한 내용은 다음과 같습니다. 공통
약속 입장 페이지
약속 현황 조회 페이지
자세한 내용은 노션에 기록해두었으며, 링크를 함께 첨부합니다. 약속 현황 조회 페이지에서 시간 테이블을 조회하는 영역은 시간관계상 추후에 가장 먼저 개선해야할 사항으로 분류하여 보류해두었습니다.
|
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
All reactions