이 글은 https://medium.com/@seanmcp/%EF%B8%8F-how-to-use-emojis-in-react-d23bbf608bf7 의 포스트를 토대로 작성했습니다!
프로젝트 개발을 하다 보면 이모티콘(이모지)를 사용하는 경우가 종종 있습니다.
이전에는 일반적으로 게시물을 작성하거나 문자를 보낼 때 처럼 인라인으로 이모지를 삽입해 왔습니다.
이번에 과제 수행을 하며 이모티콘을 활용할 일이 생겼고 문득 '이렇게 사용해도 되나?' 라는 의문이 들어 검색해 보니 이 방법은 접근성에 좋지 않다고 합니다...🙅 (스크린리더가 이모티콘에 대한 정보를 파악할 수 없기 때문에 이상한 문자로 읽는다고 합니다)
<h1 className='section__title'>맹수의 왕, 김방울😺</h1>
<p className='section__desc'>5살 코숏 고양이 김방울을 소개합니다.🙋</p>
html의 role
속성과aria-label
속성을 이용하면 접근성을 보완해줄 수 있습니다.
ARIA role은 콘텐츠에 의미론적 의미를 제공하여 화면 판독기 및 기타 도구가 해당 유형의 개체에 대한 사용자 기대치와 일치하는 방식으로 개체와의 상호 작용을 표시하고 지원할 수 있도록 합니다. ARIA role은 HTML에 원래 존재하지 않거나 존재하지만 아직 완전한 브라우저 지원이 없는 요소를 설명하는 데 사용할 수 있습니다. -mdn web docs의 WAI-ARIA 설명
role='img' 속성은 단일 이미지로 간주되어야 하는 페이지 콘텐츠 내의 여러 요소를 식별하는 데 사용할 수 있습니다. 이러한 요소는 이미지, 코드 스니펫, 텍스트, 이모티콘 또는 시각적 방식으로 정보를 전달하기 위해 결합할 수 있는 기타 콘텐츠가 될 수 있습니다. -mdn web docs의 img role 설명
<div role="img" aria-label="Description of the overall image">
<img src="graphic1.png" alt="" />
<img src="graphic2.png" />
</div>
한마디로 element 요소가 담당하는 역할을 정의해주는 것입니다.
보통 탭 메뉴를 구성할 경우<ul>
과 <li>
태그 또는 <div>
와 <button>
태그를 이용해 탭 메뉴를 구성할 텐데요, <div>
와 <button>
태그로 탭을 구성할 경우 시각적 정보를 통해 웹 컨텐츠를 받아들일 수 있는 사람은 탭 메뉴라는 것을 인식할 수 있지만 브라우저나 스크린 리더기는 이 요소가 탭메뉴라는 것을 알 수가 없습니다.😭
role='tab'
, role='tablist'
등을 사용하면 이 요소가 탭 메뉴의 역할을 담당한다고 알릴 수 있습니다.
styled-component
의 as
는 스타일 속성을 유지하면서 태그를 바꿔주고 싶을 때 사용하는 속성이죠. 이와 비슷한 역할을 해 주는 html 상의 속성...! 이라고 생각이 들었습니다.😎
물론, 굳이 role
을 사용하지 않고 시맨틱하게 코드를 짠 뒤, 꼭 필요한 곳에만 role
속성을 써 주는 것이 가장 바람직하다고 합니다.
aria-label은 레이블로 참조되어질 수 있는 DOM 안에 표시가능한 적당한 텍스트가 없을 때, 상호작용을 하는 요소들 또는 다른 ARIA 선언들을 통해 상호작용하도록 만들어진 요소에 사용하기 위한 것입니다. -mdn web docs의 aria-label 설명
설명을 읽어도 감이 안 와서 더 찾아보니🤔
화면에 현재 요소가 무엇인지 설명할 텍스트가 없을 경우에 img
의 alt
, input
태그와 함께하는 label
속성처럼 요소가 무엇인지 설명해 주는 속성이라고 합니다.
예시를 들기 위해 현재 사이드 프로젝트로 제작중인 블로그를 가져와봤습니다.. 👽
이 화면에서도 붉은 사각형 박스로 표시한 부분들은, 단순히 장식용! 이 아닌 클릭 등의 접근이 가능한 요소들입니다.
<Button className='Header__button-darkmode' onClick={onChangeDarkMode}>
<SUN_24 /> // svg 파일입니다!
</Button>
상단 우측에 위치한 다크모드 전환 버튼은 다음과 같은 구조를 갖고 있었는데, 스크린 리더 이용자들을 위해 접근성을 고려하려면 aria-label
을 사용해 다음과 같이 바꿔주어야겠죠.
<Button
className='Header__button-darkmode'
onClick={onChangeDarkMode}
aria-label='다크모드 전환'
>
<SUN_24 />
</Button>
이 같이 이모티콘도 태그로 감싼 뒤, aria-label
속성으로 설명을 해 주면 스크린리더가 태그 내의 진짜 컨텐츠(이모티콘)는 읽지 않고 aria-label
에 적힌 속성을 읽습니다.
<div role="img" aria-label="Table flip"> // aria-label의 내용을 스크린 리더기에서 읽습니다.
<p>(╯°□°)╯︵ ┻━┻</p> // 이 이모티콘은 스크린 리더기에서 읽지 않습니다!
</div>
저는🙋 이렇게 글의 장식용📄으로만 이모티콘을 사용할 예정❗이어서 스크린 리더기에 읽히는 것을 원하지 않아요. 🙅
하지만 단순히 렌더링 목적, 즉 장식용으로만 이모티콘을 사용하고 싶은데 스크린 리더기에 읽힌다면 오히려 접근성이 떨어지고 콘텐츠 본래 내용도 파악하기 매우 어려워질 것입니다. 위의 예시만 해도, 이모티콘을 사용할 예정느낌표이어서
라고 읽어버린다면 내용이 매우 부자연스러워집니다...💦
요소에 장식용으로 간주될 수 있는 콘텐츠가 포함되어 있거나 페이지에 렌더링 된 동등하게 액세스 가능한 콘텐츠에 중복되는 요소를 보조기술 사용자에게 노출되지 않도록 설정할 수 있습니다. 이를테면, 시각적으로 렌더링 된 텍스트와 함께 SVG 또는 글꼴 아이콘을 포함하는 링크입니다. 이 상황에서 아이콘은 링크 텍스트와 중복될 수 있으므로 보조기술 사용자에게 아이콘 정보를 숨김으로써 콘텐츠 탐색을 용이하게 할 수 있습니다.
aria-hidden='true'
속성으로 스크린 리더기에서 읽히지 않을 요소를 설정할 수 있다는 내용입니다!
<span role="img" aria-label="sheep">🐑</span>
위의 내용을 종합하면, 이모지를 사용할 때는 다음과 같은 형식으로 사용이 권장됩니다. 스크린 리더기는 '양'이라는 단어로 레이블을 지정할 수 있는 이미지로 위 요소를 이해합니다.
<p>
방울이는 <span role="img" aria-label="cat">😺</span><span role="img" aria-hidden="true">💗</span>
</p>
그런데 이 마크업... 간단한 문장을 표현하는데도 길이가 훨씬 길어져서 보기 불편합니다. 게다가 이모티콘을 이런 형식으로 적재적소에 사용하려면 정말 엄청나게 귀찮습니다.
개인적으로 리액트의 꽃🌸은 재사용이 가능한 컴포넌트 라고 생각합니다.
const Emoji = (props) => {
return (
<span
className='Emoji'
role='img'
aria-label={props.label ? props.label : ''}
aria-hidden={props.label ? 'false' : 'true '}
>
{props.symbol}
</span>
);
};
export default Emoji;
import Emoji from 'components/common/Emoji';
...
<Emoji symbol='🎨' />
...
<p>
방울이는 <Emoji label='cat' symbol='😺' /><Emoji symbol='💗' />
</p>
다음과 같이 간단하게 컴포넌트화해주면 매우 편하게 이모티콘을 사용할 수 있습니다!
타입스크립트 사용 시에는 label
과 symbol
속성 모두 string
타입이 되겠네요🌞
import Link from 'next/link';
import Emoji from './Emoji';
const LinkEmoji = (props) => {
return (
<Link
className='LinkEmoji'
href={props.href}
target='_blank'
style={{ display: 'inline-block' }}
>
<Emoji symbol='🔗' />
</Link>
);
};
export default LinkEmoji;
링크 갖다 붙이는 것도 귀찮았던 저는 한술 더 떠서 링크용 이모지 컴포넌트도 만들었습니다..
😅
간단하게 공부하고자 글을 적으려 했는데 문서를 읽다 보니 생각보다 많이 길어졌습니다.🤔 항상 느끼는 거지만 html은 입문할 때만 쉬운 것 같아요. 그래도 이번 포스트를 적으면서 알고 있던 지식들도 복기하고, 모호하게만 알고 있던 개념들도 꽤나 이해하게 되었습니다😄