🚨 해당 issue는 구현에 실패했으며, 해당 PR은 실패 사유에 대해 공유하는 글입니다.
구현 목적
회원 탈퇴 기능을 왜 구현해야 하죠?
행동대장 서비스는 카카오로 회원가입 및 로그인이 도입되면서, 회원 탈퇴에 대한 기능이 필수적으로 필요하게 되었습니다(개인정보보호법). 따라서 회원 탈퇴 기능을 구현하게 되었습니다. 그리고 이전 이슈에서 언급한 것처럼 회원가입을 진행한 유저가 탈퇴를 하는 사유에 대해 트래킹을 해야 한다고 생각했습니다. 탈퇴 사유를 수집함으로 우리 서비스의 문제를 보완해 나갈 수 있기 때문입니다.
구글 스프레드시트를 데이터베이스로 사용한 이유
탈퇴 사유를 백엔드의 api를 통해 저장할 수 있지만, 저희에게는 현재 서버 비용에 한계가 존재합니다. 서비스를 통해 금전적인 이득을 취하는 상황이 아니기 때문이죠. 그렇기에 회원 탈퇴 이용에 큰 영향을 끼치지 않는 선에서 서비 비용을 줄여야 한다고 생각했습니다. 이렇게 생각하여 찾은 방법이 구글의 스프레드시트 api를 활용하는 것이었습니다.
구글 스프레드시트를 데이터베이스로 활용하여 회원 사용자의 탈퇴 사유를 저장합니다. 구글 스프레드시트는 잘 만들어진 서비스로 우리가 추후 탈퇴 사유에 대한 데이터를 분석하고 싶을 때 쉽게 확인할 수 있을 것입니다.
구현 방법
해당 파트는 이런 프로세스로 구글 스프레드시트를 활용할 수 있음을 정리한 것입니다. 아래 설명 할 방법처럼 구현을 하려고 했으나 제 판단으로는 프론트엔드만으로는 구현이 불가능하였다는 점..
구글 spreadsheet api 사용을 위한 단계
구글 클라우드 프로젝트 생성 및 서비스 계정 생성
스프레드 시트에 접근할 수 있도록 구글 계정 인증
http 요청
1. 구글 클라우드 프로젝트 생성
구글 클라우드에서 프로젝트를 생성합니다.
해당 프로젝트의 API에 Google Sheets를 추가합니다.
서비스 계정을 생성합니다.
계정 생성으로 얻게된 credential 파일을 클라이언트 폴더에 추가합니다.
해당 파일에는 구글 스프레드시트에 접근하고 편집 가능할 수 있도록 하는 다양한 인증 id, key 등이 존재합니다.
구글 스프레드시트에서 연결하고자 하는 시트를 생성합니다.
해당 시트에 편집자로 서비스 계정 생성을 통해 얻은 이메일을 등록하고 편집자 권한을 부여합니다.
해당 시트의 url에서 sheet id를 가져와 클라이언트 파일에서 사용할 수 있도록 저장해둡니다.
2. 스프레드 시트에 접근 | 두가지 방법 (근데 에러를 곁들인..)
스프레드 시트에 접근하기 위해서 다음 범위(scope) 중 하나가 필요합니다.
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/spreadsheets
우리는 위에 언급한 범위를 승인 받기 위해서 아까 위에서 생성된 서비스 계정의 이메일로 접근해야 합니다. 이때 우리는 이 승인을 각각 다른 라이브러리를 활용하여 진행할 수 있습니다.
때는 이번주 월요일. 행동대장 프로젝트에서 버그를 발견했다.
버그는 카카오 프로필 이미지를 연동하지 않았을 경우 회원 프로필 이미지가 alt로 출력되는 버그였다. 이 버그의 원인은 null 병합 연산자 ??의 사용이었다. 나도 이전까지는 모르고 사용했던 연산자였다. 최근에 자바스크립트 딥 다이브를 읽고 정확한 개념을 알게 되었다.
나와 같이 null 병합 연산자가 삼항 연산자와 유사하게 동작할 것이라고 혼동했던 사람들이 존재할 것이라고 생각 된다. 그래서 이번에 null 병합 연산자가 무엇인지 정확히 알아보겠다!
null 병합 연산자
null 병합 연산자 (nullish coalescing) ??는 좌항의 피연산자가 nullish 값일 경우 우항의 피연산자를 반환한다. nullish 값이 아닐 경우에는 좌항의 피연산자를 반환한다.
지난 11월 29일 금요일, 나는 10개월의 길고도 짧은 우아한테크코스라는 교육을 수료하게 되었다. 수료식을 마치고 한달이 지나서야 회고를 작성하지만, 늦던 빠르던 속도에 집중하지 않고 작성했다는 것에 의의를 두기로 했다.
아쉬웠던 Level5 한달
level5는 자유의 시간이었다. 필수적으로 캠퍼스에 등교해야 하는 3-4일 정도를 제외하고는 10시부터 18시까지의 시간과 장소를 자유롭게 선택할 수 있었다. 이는 이번 6기에서 처음 도입된 방식이었다.
개인적으로 level5의 이런 방식은 장단점이 확실했다고 본다. 캠퍼스와의 거리가 멀었던 나에게는 등하교 시간 3시간을 아낄 수 있다는 장점이 존재했다. 이는 9개월간 부족했던 수면시간을 보충하고 본래의 컨디션을 되찾는 것에 굉장히 많은 도움이 되었다. 그러나 이것은 단점도 존재했다. 아무래도 너무 자유성이 보장되다 보니 캠퍼스에 있을 때와는 달리 시간을 효율적으로 사용하는 것이 많이 줄어들었다. 물론 하루를 의미없이 보내지 않기 위해서 ‘난 꾸준해’ 스터디를 운영하였다. 준과 왼손에게 스터디 운영 방식에 대한 의견을 듣고 스터디원과 공유하고 논의를 통해 안정적인 스터디 운영 방식이 자리잡혔다. 덕분에 나를 포함한 총 8명의 스터디원들이 조금은 시간을 허투로 사용하지만은 않았을 것이라고 생각한다.
그렇지만, 캠퍼스에 등하교를 했을 때 보다는 공부 시간이 많이 줄어들었다고 나는 느꼈다. 오전에 최소 한 시간은 의미있는 시간을 보내긴 했지만, 오후를 제대로 보내지 못한 하루도 많았다. 이런 하루가 존재했던 이유는 level4에 들어서며 몸과 마음이 많이 지쳐, 이를 회복하기 위한 시간을 가졌기 때문도 있다.
회복의 시간
11월은 내 짧고도 긴 인생에서 가장 힘들었던 순간 Top2에 들어갈 한달이었다. 내 자신에 대한 실망과 무기력함, 모든 일들에 대한 의욕 저하, 나의 능력에 대한 의구심과 자책 등.. 부정적인 감정이란 감정들을 정말 많이 느끼며 힘들어 했던 것 같다.
지금와서 왜 그런 감정이 들었을까 생각을 해보자면.. 취업을 위해 이력서를 작성하면서 그간 해왔던 것들에 대해 난 뭘 했던 걸까? 하는 자괴감이 들어서도 있고.. 열심히 했었던 일임에도 결국은 사라지고 남는게 없어져 버렸다는 상실의 감정도 있고. 무의식적으로 계속해서 남들과 비교를 통해 자신감을 많이 잃어버렸기 때문도 있는 것 같다.
Level4가 끝나갈 즈음 현재 나의 감정 상태를 어느정도 파악했고, level5에 개인 시간을 많이 가지며 이런 감정들이 빵!하고 터졌다. 그래서 이런 감정을 회복하고자 하루 하루를 천천히. 잔잔하게 보내고자 노력했다. 나는 나 자신이 자가 회복력이 좀 있다고 평가하고, 믿기 때문에..! 그리고 주변에서 이런 나의 상태를 알고 계속해서 용기를 주었기 때문에 9개월간 쌓았던 것들을 한달이라는 시간동안 꽤 많이 회복할 수 있었다.
회복을 위해 어떤 하루는 의미없이 누워서 시간을 보내기도 했고, 어떤 하루는 나가서 새하얀 눈을 밟으며 힐링하기도 했다. 또, 어떤 하루는 책을 읽으며 많은 위안과 도움을 받았다. 그렇게 하루 하루를 천천히 보내며 나의 페이스를 점차 찾으며 보냈다. 그렇게 11월을 보낸 것 같다.
이렇게 11월을 보낸 것에 대해서 많이 아쉬움이 남고 아깝다는 생각도 들었다. 누군가는 내가 이렇게 시간을 보내는 동안 열심히 하며 한발짝 더 나아가고 있을 텐데.. 라는 생각이 들었다. 그러나, 지금의 이런 회복 기간을 갖지 않고 또 뛰려고 한다면 금세 넘어질 것이라는 확신이 들었다. 그래서 11월에는 캠퍼스에 거의 등교하지도 않았고, 사람들도 잘 만나려고 하지 않았던 것 같다. 같은 업계의 사람들을 만나고 개발 이야기를 하는 것 자체가 당시의 나에게는 정신적으로 힘든 일이었기 때문이다. (사실 지금도 조금은 남아있긴 하지만, 정말 많이 극복한 상태이다.)
level5때 캠퍼스를 거의 나가지 않아, 크루들과의 마지막을 즐겁게 보내지 못한 것 같아 굉장히 아쉽다. 그 전까지는 아쉬움이 남지 않았는데, 수료식을 진행하고 구왼조 사람들과 뒷풀이를 마치고 집 오는 길에 너무나도 아쉬운 감정이 많이 들더라.. 하지만 지나간 시간을 어찌하겠는가.. 내가 선택한 일이니 감수해야지 뭐.
그렇게 level5인 11월을 회복 기간으로 잡으며 천천히 재활을 해 나갔다. 그 덕분에 12월에는 조금씩 조금씩.. 해야 할 일들을 11월보다는 진행할 수 있었다.
수료식
수료식은 사실 크게 진행된 일은 없었다.
오랜만에 사람들을 만나 이야기하고.. 놀고.. 점심 먹고, 회고하고.. 수료증 받고 사진찍고 사진찍고 단체사진 찍고 또 사진 찍고의 반복이었다. 그래서 사실 수료식을 진행하면서는 우테코가 끝났다는 실감은 나지 않았다. 그냥 평소처럼 캠퍼스 나온 느낌?
아, 그리고 수료식이 난 졸업식 같다고 생각이 들어서, 그래도 졸업식 같은 건데 다들 꽃 하나 정도는 받으면 기분 좋지 않을까~? 싶어서 구왼조 사람들과 행동대장 프론트엔드 팀원들에게 비누꽃 한송이를 나눠줬다. (백엔드도 같이 수료식하는 줄 모르고.. 행동대장 프론트엔드만 꽃 챙겨줬는데.. 미안합니다 백엔드 팀원들…🥲) 꽃 주는데 웨디가 울어줘서 기분 좋았다(?) ㅎ.. 약간 뭐라 해야 할까.. 내가 준비한 것으로 인해 감동받아서 훌찌럭 해줘서 뿌듯했달까. (웨디 미안.)
수료식 끝나고 구왼조와 월하 집에서 수료 파티를 했다. level2 종료하고 이번에 2번째로 오는데 기분이 참 묘~ 했다. 여길 이제 끝나고 오다니.. 라는 감정도 들고.. 그럼에도 그때랑 똑같이 철없이 노는게 행복하기도 했다.
우테코를 수료했다는 실감은 혼자 집가는 버스에서 많이 들었던 것 같다. 노래 들으면서 창 밖을 보며 집을 가는데, 더이상 이 사람들과 다같이 모여서 보기 힘들겠구나..라는 생각도 들고. 이렇게 학생처럼 지내는 날도 이게 마지막이겠지 싶은 생각도 들었다. 그래서 조금 쿨찌럭 하면서ㅋㅎ 집에 갔다.
우테코를 수료하며
2024년 한 해를 표현하자면 우아한테크코스이다. 그만큼, 우테코는 내 그간의 삶에서 짧지만 가장 행복하고 즐겁고 힘들고 아프고 기뻤던. 긍정과 부정의 양가 감정을 모두 극단적으로 느끼게 해주었으며, 개발적인 성장 뿐만 아니라 내면적인 성장을 정말 많이 하게 해준 교육이다. 대학교 5년의 시간보다 우테코 10개월동안의 성장이 더 많았던 것 같다.
우테코가 10개월이라는 타 교육보다는 길지만, 교육을 하기에는 짧은 시간이었다고 생각한다. 그렇기에 너무나도 빠른 10개월을 보냈기에 내 페이스를 유지할 수 없어서 굉장히 많이 지쳤었던 것 같다. 그렇지만 중간 중간에 너무나도 좋은 사람들을 한번에 많이 만나서 이 힘들었던 시간을 버티며 마칠 수 있었다.
우테코가 무엇을 위한 것이었는지 이제야 조금 알겠다. (feat. 몰입, 도둑맞은 집중력)
요즘 ‘도둑맞은 집중력’이라는 책을 읽고 있다. 이 책을 읽으며 그간의 삶. 그리고 24년을 너무나도 빠르게 흘러 보냈다는 생각이 든다. 그래서 요즘 다시 독서를 진행하면서 나의 망가진 집중력을 많이 느낀다. 예전에는 안 이랬던 것 같은데, 책을 읽으며 집중력이 다른 곳으로 새는 것을 정말 많이 느낀다. 이런 이유가 지속적으로 집중력을 방해받는 생활과 빠르게 해야 한다는 것에 집착했던 감정들 때문이었구나를 책을 읽으며 알게 되었다.
그러면서 우테코의 10개월의 의미를 다시 되돌아 보게 되었다. 이 10개월이 이전에는 짧은 시간 안에 여러 지식들을 욱여넣어야 하는 시간이라고 생각했다. 그렇지만 지금와서 되돌아보니 그런게 아니었던 것 같다. 10개월동안 다른 것에 방해받지 않으면서 개발에 몰입해보고 집중해보는 시간을 갖기 위한 수련의 시간이었다. 그런데 나는 그걸 이제야 깨달았고 지난 10개월을 그저 빠르게 지식을 욱여넣고 개발을 쳐내기 위한 시간으로만 사용했다. 그래서 위에서 한탄했던.. 수료 할 즈음.. 지쳐버렸던 것이다.
2025년은!
그래서 2025년은 빠르게, 급하게 생각하지 않고! 내가 몰입하고자 하는 것, 단 하나만 집중하고 몰입하며 보내 보고자 한다. 그렇게 보내다보면 내가 몰입할 수 있으면서 수익도 발생하는 환경을 찾을 수 있지 않을까?
그간 급하게만 살아왔던 삶. 앞으로 조금 천천히 몰입하며 집중력을 찾아보자. 그리고 이 시간동안 그때는 하지 못했던 우테코에서 배웠던 학습과 몰입의 방법들을 적용해보고자 한다.
안녕, 우테코
작년 프리코스 기간부터 올해 2월부터 11월, 그리고 수료를 마친 지금 12월까지 나에게 여전히 영향력을 미치고 있는 우테코.
우테코를 다니는 10개월이 나 자신에 대한 벽에 처음 부딪히고 이 벽을 부수며 나아가는 것이 힘든 과정이었다. 그리고 수료한 앞으로도 벽을 부수는 건 힘든 과정이겠지만. 우테코를 다니며 개발만 배운게 아니라, 나 자신을 되돌아보고 알아가는 방법을 배우며 내면을 단단하게 만드는 방법을 터득할 수 있게 해주었기에. 넘어지고 부딪히더라도 주저앉아 포기하지 않도록 성장시켜준 이 우테코를 기회가 된다면 꼭 다른 사람도 경험했으면 좋겠다.
해당 글은 우아한테크코스에서 진행한 테크니컬 라이팅을 위해 작성한 글입니다. 본문의 글에 추가적인 내용들을 추가하여 업로드 합니다.
💡 읽기 전! 이런 분들에게 추천해요.
웹 접근성에 대해 들어본 적이 있으나 잘 모르시는 분
스크린리더에 대해 들어본 적이 있으나 잘 모르시는 분
WAI-ARIA에 대해 기초적인 지식이 필요하신 분
본격적으로 글을 시작하기에 앞서 내가 왜 스크린 리더를 주제로 글을 작성하게 되었는지 설명하고 한다.
스크린 리더를 주제로 글을 작성하게 된 이유
우테코에서 테크니컬 라이팅 작성을 위해 주제를 오래 고민하고 있었다. 그러던 중 한 영상을 보게 되었다.
직접 시각 장애인분이 어떻게 스마트폰을 사용하는지 iOS의 voice over를 사용하시는 모습이 담긴 영상이었다. 이 영상을 보면서 나에게는 새로운 시각이 트이게 되었다. 그동안에는 시각 장애를 가졌다면 스마트 기기를 원활하게 사용하지 못할 것이라고 생각하고 있었다. 그러나 오히려 반대였다. 스마트폰에서는 장애를 가졌던 가지지 않았던 모두가 평등했다. 이는 기기가 이런 차별을 없애기 위해 노력해서 만든 결과물이었다.
스마트 기기들은 장애를 차별하지 않기 위해 정말 정교한 부분들을 배려하며 만들어져있었다. 내가 그간 겪은 적이 없기 때문에 몰랐던 것이다. 그런데 기기가 차별하지 않는데 웹 서비스들이 사람을 차별한다면? 결국은 해당 서비스는 사용되지 못할 것이다.
이것은 사용자를 놓친다는 개념보다는 개발자가 서비스를 만들 때, 의도하지 않게 사람을 차별할 수도 있다고 느꼈다. 나도 모르게 시각 장애인들을 차별해왔던 것이다.
그래서 행동대장 서비스를 voice over를 활용하여 사용해봤다. 내가 개발한 목적대로 절대 사용할 수가 없었다. 그래서 나는 내가 만든 서비스라도 모두가 평등할 수 있도록 하고 싶다.
웹 접근성에는 스크린 리더 뿐 만 아니라 정말 다양한 요소를 고려해야 하지만, 차근 차근 일단은 스크린 리더에 관한 것 부터 개선해 보자는 생각이 들었다. 그래서 이번 테크니컬 라이팅의 주제로 웹 접근성 중 스크린 리더를 개선하기 위해 사용되는 WAI-ARIA를 중점으로 내용을 작성했다.
웹 접근성 - 스크린 리더: 모든 사용자를 위한 평등한 디지털 환경
지난 2021년 코로나19의 장기화로 인해 온라인 쇼핑이 트렌드가 되었다. 그러나 시각장애인 A씨는 온라인 쇼핑을 사용할 수 없었다. ‘스크린 리더’ 를 사용하여 온라인 쇼핑을 진행하려 했으나 대체 텍스트가 제대로 입력되어 있지 않았다. 스크린 리더는 그저 ‘이미지’라는 말만 반복했다.
시각장애인 B씨 또한 비슷한 불편함을 겪었다. 국세청 홈택스를 통해 집에서 편하게 납세하고 싶었다. 그러나 ‘스크린 리더’를 사용했을 때, 정확한 명칭이 아닌 엉뚱한 설명이 나왔다. 이로 인해 B씨는 홈택스를 통한 납세가 어려웠다.
이렇게 시각장애인 A와 B씨는 온라인 서비스를 제대로 이용할 수 없었다. 왜 이런 일이 발생한 걸까?
웹 접근성이란
A와 B씨가 서비스를 제대로 이용할 수 없었던 이유는 바로, ‘웹 접근성’ 이 제대로 지켜지지 않았기 때문이다. ‘웹 접근성(Web Accessibility)’ 은 장애를 가진 사람들이 비장애인과 동등한 웹 서비스를 사용할 수 있도록 설계 및 개발된 것이다. 또한 웹 접근성은 「국가정보화기본법」과 「장애인차별금지 및 권리구제 등에 관한 법률(이하 “장애인차별금지법”)」등 법률에 명시된 의무사항이다.
웹 접근성을 지켜야 하는 이유
웹은 하드웨어, 소프트웨어, 언어, 장소, 능력에 제약없이 모든 사람들이 사용할 수 있도록 설계되었다. 웹이 위와 같은 목표를 달성했을 때, 다양한 청력, 움직임, 시력, 인지 능력을 가진 사람들이 웹에 접근할 수 있게 된다.
이처럼 웹은 물리적 세상에서의 한계를 없애주는 역할을 한다. 웹에서는 시간과 물리적 한계가 존재하지 않는다. 또한, 장애인, 비장애인, 성별, 연령 간의 차별도 존재하지 않는다. 우리는 웹 세상에서 모두 동등해진다.
만약 웹 사이트, 애플리케이션, 기술, 도구가 공평하지 않고 불충분하게 설계된다면 그것은 보이지 않은 장벽을 만드는 것이다. 그렇기에 개발자는 제품 및 서비스에서 차별을 만들지 않기 위해 웹 접근성을 지켜야 한다.
웹 접근성의 종류
웹 접근성을 지키기 위해 할 수 있는 것들의 종류는 굉장히 많다. 이는 한국웹접근성인증평가원에서 발표한 ‘한국형 웹 컨텐츠 접근성 지침 2.1’에 자세히 설명되어있다.
한국형 웹 컨텐츠 접근성 지침 2.1은 W3C(World Wide Web Consortium)가 장애인 등이 웹 사이트에 접근하는 것을 보장하기 위해 만든 ‘웹 컨텐츠 접근성 지침 2.0(WCAG 2.0)’을 참고했다. 해당 지침은 WCAG 2.0의 12개 지침과 성공 기준의 중요도 A 항목을 중심으로 국내에 맞게 고려되어 개발되었다.
아래 표는 한국형 웹 컨텐츠 접근성 지침 2.1에서 말하는 웹 접근성 지침이다.
웹 접근성 지침
구분
항목
세부항목
관련 WCAG 2.0 기준
1. 인식의 용이성
1.1. 대체 텍스트 제공
1.1.1 적절한 대체 텍스트 제공
1.1.1 Non-text Content
1.2. 멀티미디어 대체 수단 제공
1.2.1 자막 제공
1.2.1 Audio-only and Video-only (Prerecorded), 1.2.2 Captions (Prerecorded), 1.2.3 Audio Description or Media Alternative
1.3. 명료성
1.3.1 색에 무관한 컨텐츠 인식
1.3.1 Info and Relationships, 1.4.1 Use of Color
1.3.2 명확한 지시 사항 제공
1.3.3 Sensory Characteristics
1.3.3 텍스트 컨텐츠의 명도 대비
1.4.3 Contrast (중요도 AA 항목)
1.3.4 자동 재생 금지
1.4.2 Audio Control
1.3.5 컨텐츠 간의 구분
1.4.8 Visual Presentation (중요도 AAA 항목)
2. 운용의 용이성
2.1. 입력장치 접근성
2.1.1 키보드 사용 보장
2.1.1 Keyboard
2.1.2 초점 이동
2.1.2 No Keyboard Trap, 2.4.2 Focus Order
2.1.3 조작 가능 추가
-
2.2. 충분한 시간 제공
2.2.1 응답시간 조절
2.2.1 Timing Adjustable
2.2.2 정지 기능 제공
2.2.2 Pause, Stop, Hide
2.3 깜빡임 및 번쩍임 사용 제한
2.3.1 깜빡임과 번쩍임 사용 제한
2.3.1 Three Flashes or Below
2.4 쉬운 내비게이션
2.4.1 반복 영역 건너뛰기
2.4.1 Bypass Blocks
2.4.2 제목 제공
2.4.2 Page Titled
2.4.3 적절한 링크 텍스트
2.4.4 Link Purpose
3. 이해의 용이성
3.1 가독성
3.1.1 기본 언어 표시
3.1.1 Language of Page
3.2 예측 가능성
3.2.1 사용자 요구에 따른 실행
3.2.1 On Focus, 3.2.2 On Input
3.3 컨텐츠의 논리성
3.3.1 컨텐츠의 선형 구조
1.3.2 Meaningful Sequence
3.3.2 표의 구성
1.3.1 Info and Relationships
3.4 입력의 도움
3.4.1 레이블 제공
3.3.2 Labels or Instructions
3.4.2 오류 정정
3.3.1 Error Identification
4. 견고성
4.1 문법 준수
4.1.1 마크업 오류 방지
4.1.1 Parsing
4.2 웹 애플리케이션 접근성
4.2.1 웹 애플리케이션 접근성 준수
4.1.2 Name, Role, Value
위 표에서의 웹 접근성은 크게 인식의 용이성, 운용의 용이성, 이해의 용이성, 견고성 4가지로 나눌 수 있다. 다만, 해당 글에서는 모두 다루기는 양이 방대하다. 그래서 스크린 리더와 밀접한 관계가 있는 항목만을 다루려고 한다.
스크린 리더
스크린 리더(Screen Reader) 는 디스플레이 화면에 표시된 내용과 사용자가 입력한 키보드 정보, 마우스 좌표 등을 비시각적인 방식으로 전달해주는 소프트웨어 애플리케이션이다. 이때, 비시각적인 방식으로는 텍스트 음성 변환, 점자 또는 사운드 아이콘 등이 있다. 따라서 스크린 리더는 시각 장애, 문맹, 학습 장애가 있는 사람들에게 필수적이다.
스크린 리더는 비시각적인 방식으로 정보를 전달하여, 시각 장애인이나 다른 접근성 요구가 있는 사용자들이 웹 콘텐츠를 원활하게 이용할 수 있도록 돕는다. 이러한 접근성을 더욱 향상시키기 위해 WAI-ARIA 가 도입되었다.
WAI-ARIA?
먼저 WAI-ARIA에 대해 살펴 보기 전에 RIA에 대해 알아보자.
웹의 빠른 발전으로 인해, 웹은 더이상 문서의 개념이 아닌 애플리케이션처럼 사용되면서 사용자 경험(User eXperience, UX)을 중시하게 되었다. 이런 요구를 해결하기 위해 등장한 것이 리치 인터넷 애플리케이션(Rich Internet Applications)이다. RIA는 정적인 HTML과 단순한 자바스크립트를 넘어 보다 동적인 자바스크립트와 Ajax(Asyncronous Javascript and XML) 등의 기술을 활용한다. 이로 인해 향상된 UX를 사용자에게 제공할 수 있다.
그러나, 모든 사용자가 동등하게 접근할 수 없다는 문제가 존재했다. 스크린 리더 등의 보조기술을 사용하는 사용자는 RIA 기술를 활용한 웹 애플리케이션을 제대로 사용할 수 없었다. 이로 인해 등장한 것이 바로 WAI-ARIA(Web Accessibility
Initiative - Web Accessible Rich Internet Applications) 이다. WAI-ARIA는 W3C에서 웹 컨텐츠 및 웹 애플리케이션의 접근성과 상호 운용성을 개선하기 위해 발표한 기술 명세이다. 역할(Role), 속성(Property), 상태(State) 정보를 추가하여 스크린 리더 및 보조기기 등에서 접근성 및 상호 운용성을 향상시킨다.
WAI-ARIA의 3가지 기능
역할(Role)
유저 인터페이스(User Interface, UI)에 포함된 특정 컴포넌트의 역할을 정의한다.
페이지의 검색 영역인지, 네비게이션 요소인지, 제목 인지 등의 명확한 기능을 부여한다.
속성(Property)
컴포넌트의 특징이나 상황을 정의한다.
폼의 입력 필드가 필수 항목인지, 팝업이 뜨는지, 업데이트 된 정보가 있는지 등의 상황을 사용자가 인지할 수 있도록 한다. 속성명으로 aria-\*라는 접두사를 사용한다.
상태(State)
컴포넌트의 상태 정보를 정의한다.
메뉴가 펼쳐진 상태인지, 적절한 값이 입력되었는지, 컨텐츠가 숨김 상태인지 등을 나타낸다.
WAI-ARIA 작성 방법
다음은 어떻게 WAI-ARIA를 작성하면 좋을지 알아보자.
랜드마크
랜드마크(Landmark Role)는 웹 페이지의 특정 컨텐츠가 어떤 역할을 하는지 쉽게 식별할 수 있도록 도와주는 역할을 한다. 이는 웹 접근성을 높이기 위한 기능으로, 기존의 건너뛰기 링크(스크린 리더 사용자를 위해 페이지의 특정 부분으로 바로 이동할 수 있는 링크)보다 발전된 형태이다. 랜드마크는 HTML 요소에 role 속성을 사용하여 컨텐츠 역할을 지정하면 사용할 수 있다.
랜드마크를 사용하면 컨텐츠 블록의 제목을 제공하는 것보다 더 명확하게 영역을 구분할 수 있다. 예를 들어, 네비게이션 바, 주 컨텐츠 영역, 푸터 등을 쉽게 구분할 수 있다.
<!-- 컨텐츠 블록의 제목을 제공하는 형태 --><section><h2>소개</h2><p>해당 글에 대한 소개입니다.</p></section><!-- 랜드마크를 사용한 형태 --><mainrole="main"><h1>주요 콘텐츠</h1><p>여기에 주요 콘텐츠가 들어갑니다.</p></main>
랜드마크 종류
랜드마크는 다음 표와 같이 8가지의 기능을 제공한다.
역할(Role)
설명
HTML5 요소
application
웹 애플리케이션 영역을 선언. 스크린 리더가 웹 브라우저 탐색 키를 애플리케이션에게 돌려줌.
N/A
banner
사이트의 로고나 제목 등을 포함하는 헤더 정보 영역. 사이트 아이덴티티 정보를 포함.
<header>
navigation
웹 사이트의 내비게이션 영역. 링크 모음을 포함.
<nav>
main
메인 콘텐츠 영역. 웹 페이지 내에서 한 번만 선언 가능.
<main>
complementary
메인 콘텐츠를 보충하는 부가적인 내용의 영역. 메인 콘텐츠에서 분리되어도 의미가 있음.
<aside>
form
사용자가 입력 가능한 폼 영역. 검색 폼은 제외.
<form>
search
검색을 위한 입력 폼 영역.
N/A
contentinfo
문서의 메타데이터 영역. 저작권 정보, 주소, 연락처, 개인정보 정책 등을 포함.
<footer>
HTML5의 섹션 관련 요소와 WAI-ARIA를 같이 사용할 경우 해당 기능이 무효화 되거나 충돌이 발생할 수 있다. 따라서, 중복해서 사용하지 않도록 해야 한다.
HTML요소의 역할 변경 제한
ARIA를 이용하여 요소의 역할을 변경하는 것을 제한한다.
아래 코드를 예시로 들어보자.
<h1role="“button”">버튼</h1>
위 코드는 h1 요소에 button 역할을 부여했다. h1은 heading의 역할을 가지는데 ARIA를 사용하여 heading의 역할이 아닌 button의 역할을 하도록 강제했다. 이렇게 ARIA를 사용하여 본질적인 역할을 변경하는 것은 좋지 않다. h1 요소에 button 역할을 주고 싶다면 다음과 같이 사용한다.
<!-- h1 하위 요소로 button 사용 --><h1><button>버튼</button></h1><!-- h1 하위 요소로 span을 사용하여 role="button" 부여 --><h1><spanrole="button"tabindex="“0”">>버튼</span></h1>
위와 같은 방법으로 h1의 본질적인 역할은 해치지 않으면서 button을 사용할 수 있게 되었다.
키보드 사용 보장
탭, 드래그 앤 드롭, 슬라이드, 스크롤 등과 같이 사용자와 상호작용이 필요한 대화형 UI의 경우 키보드로도 접근과 사용이 가능해야 한다. 키보드 포커스를 받지 못하는 요소의 경우 tabindex 속성을 사용하여 키보드 포커스를 받을 수 있도록 한다.
이때 tabindex 속성에 0을 지정하면 화면에 표시된 순서대로 키보드 포커스가 된다. 만약, 0보다 작은 값을 지정할 경우 키보드 포커스를 받을 수 없게 된다.
<!-- 키보드 포커스 X --><spanrole="“button”"tabindex="“-1”">버튼</span><!-- 키보드 포커스 O --><spanrole="“button”"tabindex="“0”">버튼</span>
그렇다면, tabindex에 0보다 큰 양수의 값이 들어오면 어떻게 동작할까?
해당 요소는 지정한 순서대로 키보드 포커스를 받게 된다. 즉, tabindex 값이 낮을수록 먼저 포커스를 받게 된다. 이 방법을 통해 특정 요소들이 키보드 포커스를 받을 순서를 지정할 수 있다. 아래 0보다 큰 양수 값이 들어 왔을 경우에 대한 예시 코드를 살펴보자.
<!-- tabindex 순서를 지정 --><divtabindex="3">세 번째로 포커스</div><divtabindex="0">화면 표시 순서(네 번째)대로 포커스</div><divtabindex="1">첫 번째로 포커스</div><divtabindex="2">두 번째로 포커스</div><divtabindex="0">화면 표시 순서(다섯 번째)대로 포커스</div>
tabindex="1"을 가진 요소가 가장 먼저 포커스를 받고, tabindex="2"를 가진 요소가 그 다음, 그리고 tabindex="3"을 가진 요소가 그 다음으로 포커스를 받는다. 이러한 방식은 화면에 표시된 순서와는 무관하게 포커스 순서를 지정할 수 있다.
다만, 이런 방식은 너무 많은 요소에 tabindex를 설정하거나 높은 값을 사용하면 관리가 어려워질 수 있으므로 주의해서 사용해야 한다.
숨김 요소
스크린 리더 사용자를 위한 정보를 제공하지만, 단순히 화면에 보이지 않게만 하려는 경우에는 aria-hidden="true"를 사용하면 안된다. aria-hidden="true"로 지정된 요소는 스크린 리더에서 완전히 무시되기 때문에 스크린 리더는 이 요소가 아예 없다고 생각하게 된다.
<!-- 잘못된 aria-hidden 사용 예시: 중요한 버튼이 스크린 리더에서 무시됨 --><buttonaria-hidden="true">제출하기</button>
만약, aria-hidden=“true"를 사용하여 숨김 요소에 대해 접근을 차단하고 싶다면, CSS를 활용한다. CSS의 display 속성에 none 값을 지정하여 스크린 리더에서 접근할 수 없도록 하고 aria-hidden="true"를 명시한다.
중요한 정보를 전달하거나 버튼, 링크 같은 역할을 하는 요소에 role="presentation" 속성을 부여해서는 안 된다. 이 속성은 스크린 리더에게 해당 요소가 단순히 화면에 보이기 위한 것일 뿐이라고 인식하게 해서, 역할이 제대로 전달되지 않는다.
<!-- 잘못된 role="presentation" 사용 예시: 스크린 리더가 버튼 역할을 인식하지 못함 --><buttonrole="presentation">다음 페이지로 이동</button>
레이블 제공
모든 대화형 UI 요소에는 반드시 레이블을 제공해야 한다. 레이블은 사용자가 해당 요소의 용도를 이해하는 데 도움을 준다. HTML의 <label> 요소를 사용하여 레이블을 제공하는 것이 가장 좋지만, aria-label이나 aria-labelledby와 같은 WAI-ARIA 속성을 사용해서도 레이블을 제공할 수 있다.
<!-- HTML <label> 요소를 사용한 예시 --><divclass="container"><labelfor="user-name">이름</label><inputtype="text"id="user-name"/></div><!-- aria-label 속성을 사용한 예시 --><buttonaria-label="닫기"onclick="myDialog.close()">X</button><!-- aria-labelledby 속성을 사용한 예시 --><div><divid="name-label">이름</div><inputtype="text"aria-labelledby="name-label"/></div>
그렇다면, HTML의 <label>과 aria-label, aria-labelledby는 무슨 차이점이 있을까? <label> 요소는 주로 입력 필드(input)와 함께 사용되며, 화면에 텍스트로 레이블이 표시되어 시각적으로 명확하게 한다. aria-label 속성은 화면에 텍스트 레이블을 표시할 필요가 없는 경우에 유용하며, 보조 기술을 위해 텍스트 레이블을 제공한다. aria-labelledby 속성은 다른 요소의 텍스트를 사용하여 레이블을 제공하며, 복잡한 레이블을 만들 때 유용하다.
Live Region
Live Region은 웹 문서나 위젯, 웹 애플리케이션의 일부가 동적으로 변경될 때, 사용자가 조작하지 않아도 변경된 내용과 진행 상태를 알릴 수 있도록 도와주는 속성이다. 이 속성은 모든 HTML 요소에 적용할 수 있다.
aria-live
aria-live은 Live Region의 업데이트 내용을 사용자에게 알리는 방법을 설정한다. 기본값은 “off”이며, “polite”로 설정하면 사용자의 입력이 끝난 후 업데이트 내용을 알리고, “assertive”로 설정하면 즉시 알린다.
<divaria-live="polite">사용자 입력 후 이 내용이 업데이트됩니다.</div>
aria-atomic
aria-atomic은 Live Region의 내용이 업데이트될 때, 업데이트된 부분만 알릴 것인지 전체 내용을 알릴 것인지 설정한다. 기본값은 “false”이며, “true”로 설정하면 업데이트된 내용만 전달한다.
<divaria-live="polite"aria-atomic="true">이 내용이 업데이트되면 전체를 알리지 않고 변경된 부분만 알립니다.</div>
aria-busy
aria-busy은 Live Region이 업데이트 중인지 여부를 나타낸다. 기본값은 “false”이며, “true”로 설정하면 업데이트 중임을 알리고 이후 내용은 안내하지 않는다.
aria-relevant은 Live Region의 업데이트 시 어떤 종류의 변화에 대해 알릴지 설정한다. 기본값은 “additions text”이며, “additions”, “removals”, “text” 및 “all” 값으로 설정할 수 있다.
<divaria-live="polite"aria-relevant="all">모든 변화가 이곳에 알림됩니다.</div>
마무리 말
웹 접근성은 단순히 법적 의무를 넘어, 모든 사람이 정보와 서비스를 동등하게 누릴 수 있도록 하는 기본적인 인권의 문제이다. 장애인뿐만 아니라 비장애인도 다양한 상황에서 웹 접근성의 혜택을 받을 수 있다. 웹의 창시자 팀 버너스리가 말한 것처럼, 웹의 힘은 보편성에 있다. 모든 사람이 장애에 상관없이 웹에 접근할 수 있는 환경을 만드는 것이야말로 우리 개발자가 추구해야 할 목표이다.
웹 접근성을 고려한 웹사이트는 더 많은 사용자에게 다가갈 수 있고, 이는 결국 더 나은 사용자 경험을 제공한다. 개발자는 이러한 접근성을 통해 정보의 격차를 줄이고, 모두가 평등하게 웹을 사용할 수 있는 환경을 만들어야 한다. 이를 통해 더 포용적이고 공정한 디지털 세상을 만들어 나가는 것이 우리의 책임이다.
https://soi-ha.github.io/ url과 그 하위 url까지 모두 정상적으로 변경한 OG가 잘 반영된 것을 확인할 수 있다!
틈새 학습: OG (Open Graph)란?
Open Graph란, SNS로 웹 페이지를 공유할 때 해당 페이지를 미리 볼 수 있도록 해주는 것이다.
Open Graph 설정을 통해 페이지의 이미지, 내용, 제목이 미리보기 형식으로 확인할 수 있다.
OG 왜 사용함?
Open Graph 사용을 통해 사용자의 클릭률을 높일 수 있기 때문이다. 미리보기를 통해 웹 페이지의 내용을 추측하여 사용자가 원하는 글에 접근할 확률을 높여준다. 만약 OG가 없는 상황에서 사용자가 url을 클릭했는데 원했던 내용이 아니라면? 사용자는 더이상 공유된 url을 클릭할 확률이 줄어든다. 그렇기에 OG로 사용자의 클릭률을 높일 수 있다.
또한, 미리보기를 통해 url만 존재할 때 보다 사용자의 눈길을 끌기 쉽다. 미리보기 이미지가 같이 제공되기 때문에 사용자의 눈길을 잡기 수월할 것이다.