새소식

프론트엔드 공부/웹표준 & 웹접근성

접근성을 지키며 마크업하기

  • -

문제 1  :  Semantic HTML

예전에는 레이아웃에서 각 영역을 지정하는 태그는 <div>가 대단히 많이 쓰였고, 이 당시 박스 모델을 적용한 HTML 문서는 수십 개로 중첩된 복잡한 <div> 지옥(...)인 경우가 많았다. 그나마 id나 name 속성을 이용하여 이게 무슨 용도로 사용되는 블럭인지 명시해두는 기법도 있었지만, 닫는 태그쪽은 표시가 안 되기 때문에 역시 문제가 있었다.

HTML5에서는 시맨틱 웹을 중요시하여 여러가지 새로운 태그를 만들었다. 이러한 태그들을 시맨틱 태그라고 한다.

기존 HTML 표준에서도 각 태그는 대부분 의미를 가지고 있었지만, 의미가 불명확한 태그나 시대의 흐름에 뒤처진 태그가 있었다. 이에 시맨틱 웹이 중요시되면서 HTML은 문서 구조와 의미, CSS는 디자인으로 확연히 분리되고, 테이블 레이아웃은 박스 모델 레이아웃으로 변화되었다.

시맨틱 태그를 사용한 레이아웃은 검색 엔진이 컨텐츠를 구분할 수 있어 검색 노출을 용이하게 하고 시각장애인에게 사이트의 본문인지 아닌지 알려줄 수 있다는 장점이 있다.

<header> 일반적으로 페이지나 섹션의 상단에 위치하며, 사이트 제목을 포함시키고 선택적으로 상단바나 검색바를 넣을 수 있는 태그입니다. <head> 태그와 혼동하기 어렵습니다. 섹션, 아티클 등 그룹화된 섹션 내에서도 헤더로 사용할 수 있습니다.
<nav> 'navigation'의 약어로, 사이트를 이끄는 요소들(예: 상단바)에 대해 일반적으로 사용됩니다. 보통은 <ul>을 내부에 넣어 리스트 형태로 사용합니다.
<main> 문서의 주요 콘텐츠를 나타냅니다. 이 태그는 반드시 한번만 사용되어야 합니다. 만약 여러 개의 <main> 태그가 사용된다면, 나머지는 hidden 속성을 이용해 감춰져야 합니다. 시맨틱 태그 중에서 인터넷 익스플로러에서 지원되지 않는 유일한 태그입니다.
<article> 웹 페이지 콘텐츠에 사용되는 태그로, 독립적으로 배포되거나 재사용될 수 있는 문서, 페이지, 또는 사이트의 섹션에 대해 사용합니다.
<section> 웹 페이지의 섹션에 사용되는 태그로, 각각의 파트로 시맨틱하게 분류할 때 사용됩니다. 이 태그를 사용하면 검색엔진이 스크래핑하지 않는다는 소문이 있지만, 이는 루머입니다. HTML5 표준 문서를 보면 "태그의 내용을 함께 배급하는 것이 의미가 있다면, <section> 요소 대신 <article> 요소를 사용하는 것이 권장됩니다"라고 되어 있습니다.
<aside> 주요한 텍스트를 마크하고 나머지 부분을 설명하는 태그로, 사이드바나 광고창 등 중요하지 않은 부분에 사용됩니다.
<footer> 일반적으로 페이지나 파트의 하단에 위치하며, 사이트의 라이선스, 주소, 연락처 정보 등을 포함시킬 때 사용합니다.

page01에서는 div요소를 시맨틱요소로 바꾸어 주었고, class 속성을 없애주고, CSS 파일에서 class와 연결되어있던 스타일 속성들도 바뀐 요소에 맞춰 수정하였다. 

수정 전 Page01
const Page01 = () => {
    return (
        <div className="article">
            <div className="title1">문제 1 : Semantic HTML</div>
            <div className="p">div 요소와 span 요소로도 화면을 구성할 수 있지만, 이 둘은 의미를 담고있지 않은 요소이기 때문에 각 요소가 어떤 기능을 하는지 요소의 이름만 보고서는 판단할 수 없습니다. 가능하다면 시맨틱 요소를 사용하여 웹 표준도 충족하고 의미있는 HTML을 구성하세요.<br/>
                우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 각 요소들을 시맨틱한 요소로 변경하세요.</div>
            <ul>
                <li>개발자 콘솔의 Element 탭을 열고 요소들을 확인해보세요.</li>
                <li>시맨틱 요소가 아닌 div로 작성된 요소들을 확인하세요.</li>
                <li>우측 가이드를 참고하여 div 요소를 적합한 시맨틱 요소로 바꿔주세요.
                    <li>각 컴포넌트들, 메인 페이지, 현재 페이지를 수정해주시면 됩니다.</li>
                    <li>class 속성에 힌트가 있습니다.</li>
                    <li>class 이름이 container인 요소는 정렬을 위한 요소이므로 바꾸지 않아도 됩니다.</li>
                </li>
                <li>각 요소에 작성되어있던 class 속성을 없애주고, CSS 파일에서 class와 연결되어있던 스타일 속성들도 바뀐 요소에 맞춰 수정해주세요.
                    <li>이 단계를 제대로 진행하지 않으면 이후 문제들의 화면이 제대로 표시되지 않습니다. 꼭 잘 수정해주세요.</li>
                </li>
                <li>요소 종류를 바꾸기 이전과 똑같은 화면이 나오면 완료입니다!</li>
            </ul>
        </div>)
}

export default Page01
수정 후 Page01
const Page01 = () => {
    return (
        <article>
            <h1>문제 1 : Semantic HTML</h1>
            <p>div 요소와 span 요소로도 화면을 구성할 수 있지만, 이 둘은 의미를 담고있지 않은 요소이기 때문에 각 요소가 어떤 기능을 하는지 요소의 이름만 보고서는 판단할 수 없습니다. 가능하다면 시맨틱 요소를 사용하여 웹 표준도 충족하고 의미있는 HTML을 구성하세요.<br/>
                우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 각 요소들을 시맨틱한 요소로 변경하세요.</p>
            <ul>
                <li>개발자 콘솔의 Element 탭을 열고 요소들을 확인해보세요.</li>
                <li>시맨틱 요소가 아닌 div로 작성된 요소들을 확인하세요.</li>
                <li>우측 가이드를 참고하여 div 요소를 적합한 시맨틱 요소로 바꿔주세요.
                    <li>각 컴포넌트들, 메인 페이지, 현재 페이지를 수정해주시면 됩니다.</li>
                    <li>class 속성에 힌트가 있습니다.</li>
                    <li>class 이름이 container인 요소는 정렬을 위한 요소이므로 바꾸지 않아도 됩니다.</li>
                </li>
                <li>각 요소에 작성되어있던 class 속성을 없애주고, CSS 파일에서 class와 연결되어있던 스타일 속성들도 바뀐 요소에 맞춰 수정해주세요.
                    <li>이 단계를 제대로 진행하지 않으면 이후 문제들의 화면이 제대로 표시되지 않습니다. 꼭 잘 수정해주세요.</li>
                </li>
                <li>요소 종류를 바꾸기 이전과 똑같은 화면이 나오면 완료입니다!</li>
            </ul>
            </article>
    )       
}

export default Page01

문제 2 : 자주 틀리는 마크업

인라인 요소 안에 블록 요소 넣는 경우

  • HTML 요소는 표시 방법에 따라 인라인, 블록 요소로 나뉜다.
  • Inline 요소는 항상 Block 요소 안에 들어가야 하며, 반대의 경우는 있어서는 안 된다. 보통 특정 요소가 Inline 인지 Block 요소인지 정확하게 알지 못할 때 이런 실수를 한다.
Inline element: 콘텐츠가 차지하는 만큼 ex) `<span>`
Block element: 가로로 넓게 화면 영역을 차지 ex) `<div>`
// h1, div 요소는 블록 요소이고,
// a, span 요소는 인라인 요소입니다.
<a href=""><h1>틀린 예시 1</h1></a>
<span><div>틀린 예시 2</div></span>

<b> , <i> 요소 사용 

  • <b> 요소와 <i> 요소는 각각 글씨를 굵게 만들 때, 글씨를 기울일 때 사용하는 요소
  • 웹 표준을 준수하기 위해서는 이 요소들을 사용하지 않는 것이 좋다. 시맨틱 하지 않은 표현을 기준으로 이름이 지어진 요소이기 때문이다.
  • 대신 똑같은 스타일을 부여하면서 콘텐츠에 의미를 부여하는 <strong> 요소와 <em> 요소를 사용하는 것이 좋다.
<b>글씨를 두껍게</b> -- 대체하기 --> <strong>콘텐츠 매우 강조하기</strong>
<i>글씨 기울이기</i> -- 대체하기 --> <em>콘텐츠 강조하기</em>

<hgroup> 의미없이 사이즈용도로 사용

  • <hgroup> 요소들은 목차의 역할을 하면서 콘텐츠의 상하 관계를 표시하기 위해서 사용한다. 이를 시각적으로 나타내기 위해서 숫자가 작을수록 글자의 크기가 크고, 숫자가 작을 수록 크기가 작다. 그런데 이러한 특성 때문에 <hgroup> 의 시맨틱 요소로서의 역할을 간과한 채 글자에 스타일 속성을 적용하기 위한 목적으로 사용하는 경우가 종종 있다. 이럴 경우 화면은 보기 좋을지 몰라도, 사용자에게 완전히 잘못된 화면 구조 정보를 전달하게 된다.
  • <hgroup>: 제목 태그(<h1>~<h6>)를 그룹으로 묶기 위한 태그이다. 대체로 제목과 소제목을 묶는다. 이 태그는 W3C HTML 스펙에서 제외되었다. hgroup 태그는 현재 브라우저 상에서 아무런 역할을 하지 않고 단지 div 비슷하게 동작하기 때문에, 다른 태그로 대체하여도 크게 상관은 없다. W3C는 header 태그로 대체할 것을 권장하고 있다.
  • <h[1-6]>: 제목(heading)을 표시할 때 사용된다. <h1>이 가장 크고 <h6>이 가장 작다. 크기는 브라우저마다 표시하는 방법이 달라 다르게 나타날 수 있다. CSS를 쓰면 크기, 색상, 폰트 등을 변경할 수 있다. <h1>은 한 문서 안에 하나만 사용하는 것을 권장한다.
<h1>1단계</h1>
<h2>2단계</h2>
<h3>3단계</h3>
<h4>4단계</h4>
<h5>5단계</h5>
<h6>6단계</h6>

 <br /> 연속으로 사용하기

  • <br /> 은 쭉 이어지는 텍스트 흐름에 줄 바꿈을 해주기 위해서 사용하는 요소
  • 만들어진 목적과 다르게 요소 사이에 간격을 만들기 위한 목적으로 남발해서는 안 된다. 요소 사이에 간격이 필요한 경우에는 아예 별도의 단락으로 구별하거나 CSS 속성을 주어 여백을 조정해주는 것이 바람직하다.
// 잘못된 예시
요소 사이에 여백을 주고싶을 때
<br />
<br />
br태그로 하면 안 된다.

// 옳은 예시 1
<p>요소 사이에 여백을 주고싶을 땐</p>
<p>별도의 단락으로 구별해주거나.</p>

// 옳은 예시 2
//HTML
<p class="margin">요소 사이에 여백을 주고싶을 땐</p>
<p class="margin">CSS 속성으로 여백을 설정해줘야한다.</p>

//CSS
.margin { margin: 10px }

인라인 스타일링 사용하기

  • 웹 표준으로 HTML, CSS, JavaScript 등의 사용 방법을 정리하면서 각 영역이 분리되어 여러 이점을 얻을 수 있었다. 그런데 HTML 요소 안에 인라인으로 스타일링 속성을 설정하는 것은 기껏 분리한 영역을 다시 합치는 것과 같습니다. 웹 표준을 지키기 위해서는, HTML과 CSS 코드를 분리해서 작성하자.
/* HTML 파일입니다 */
<!DOCTYPE html>
<html>
<head>
  <title>제목</title>
  <style>
    h1 {
      color: red;
    }
  </style>
</head>
<body>
  <h1>스타일링 속성은 CSS로 작성해주세요.</h1>
  <h2>style 요소를 사용해도, CSS 파일을 따로 작성해도 괜찮습니다.</h2>
  <h3 style="color: blue">이렇게 인라인 스타일링으로는 사용하지 마세요.</h3>
</body>
</html>
/* CSS 파일입니다. */
h2 {
  color: yellow;
}
수정 전 Page02
const Page02 = () => {
    return (
        <article>
            <h1>문제 2 : 자주 틀리는 마크업</h1>
            <p>자주 틀리는 HTML 요소의 사용법들을 고쳐봅시다. 웹 표준을 저해하는 사용법이지만, 화면 상으로는 큰 문제가 없기 때문에 의외로 자주 발견할 수 있는 예시들 이기도 합니다.<br />
            우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 웹 표준에 맞는 마크업으로 바꾸세요.</p>
            <li>아래 자주 틀리는 마크업 예시들을 웹 표준에 맞게 수정하세요.</li>
            <li>예시 외에도 애플리케이션 내에 틀리게 사용한 마크업이 있습니다. 찾아서 수정해보세요.</li>
            <section>
                <h2>틀린 마크업 예시</h2>
                <section>
                    <h3>예시 1</h3>
                    <li>
                        <a>
                            <div>어떻게 틀렸을까요?</div>
                        </a>
                    </li>
                    <li>
                        <em>
                            <p>모두 같은 종류의 실수를 하고 있습니다.</p>
                        </em>
                    </li>
                    <li>
                        <strong>
                            <h4>틀린 이유를 찾아서 수정해보세요.</h4>
                        </strong>
                    </li>
                </section>
                <section>
                    <h3>예시 2</h3> 
                    <li>
                        <b>화면만 보면 틀렸다는 사실을 인지하기 어렵습니다.</b>
                    </li>
                    <li>
                        <i>
                            Element탭이나 Visual Studio Code에서 소스 코드를 확인하세요.
                        </i>
                    </li>
                </section>
                <section>
                    <h3>예시 3</h3>
                    <li>
                        <h1>글씨 크기를 조절하고 싶을 땐</h1>
                    </li>
                    <li>
                        <h6>요소 종류를 사용하는 것이 아니라</h6>
                    </li>
                    <li>
                        <h4>CSS를 이용해주세요.</h4>
                    </li>
                    <li>
                        <h3>요소의 의미와 맞지 않습니다.</h3>
                    </li>
                </section>
                <section>
                    <h3>예시 4</h3>
                    <li>요소 사이에 간격을 주고 싶을 때에도</li>
                    <br /><br />
                    <li>CSS를 이용해주세요.</li>
                    <br /><br /><br /><br />
                    <li>태그의 존재 의의와 맞지 않습니다.</li>
                    <br />
                    <li>요소 사이의 간격을 조절할 때가 아니라 줄 바꿈을 할 때 사용해주세요.<br />
                    이렇게 사용해주시면 됩니다.</li>
                </section>
                <section>
                    <h3>예시 5</h3>
                    <li style={{"color": "blue"}}>스타일 속성을 적용하고 싶을 때에는</li>
                    <li style={{"font-size": "2rem"}}>태그 안에 style 속성을 작성하는 방법인</li>
                    <li style={{"font-weight": "900"}}>인라인 스타일링을 사용하지 마세요.</li>
                    <li style={{"text-shadow":"3px 3px 3px yellow"}}>CSS 코드를 따로 작성하는 것이 웹 표준에 맞는 사용법입니다.</li>
                </section>
                <section>
                    <h3>종합 예시</h3> 
                    <a>
                        <li style={{"list-style":"circle"}} ><b>위 예시를 종합적으로 섞어놓았습니다.</b></li>
                        <br /><br />
                        <strong>
                            <div style={{"background-color":"rgba(120,0,250,0.2)"}}>이 정도 되면 보기만해도 불편하실 것 같습니다.</div>
                            <br /> 
                        </strong>
                        <i><h1 style={{"color":"gray"}}>틀린 곳을 찾아서 수정해보세요.</h1></i>
                    </a>
                </section>
            </section>
        </article>)
}

export default Page02
수정 후 Page02
const Page02 = () => {
    return (
        <article>
            <h1>문제 2 : 자주 틀리는 마크업</h1>
            <p>자주 틀리는 HTML 요소의 사용법들을 고쳐봅시다. 웹 표준을 저해하는 사용법이지만, 화면 상으로는 큰 문제가 없기 때문에 의외로 자주 발견할 수 있는 예시들 이기도 합니다.<br />
            우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 웹 표준에 맞는 마크업으로 바꾸세요.</p>
            <li>아래 자주 틀리는 마크업 예시들을 웹 표준에 맞게 수정하세요.</li>
            <li>예시 외에도 애플리케이션 내에 틀리게 사용한 마크업이 있습니다. 찾아서 수정해보세요.</li>
            <section>
                <h2>틀린 마크업 예시</h2>
                <section>
                    <h3>예시 1</h3>
                    <li>
                        <a>어떻게 틀렸을까요?</a>
                    </li>
                    <li>
                        <em>
                            모두 같은 종류의 실수를 하고 있습니다.
                        </em>
                    </li>
                    <li>
                        <strong>
                            틀린 이유를 찾아서 수정해보세요.
                        </strong>
                    </li>
                </section>
                <section>
                    <h3>예시 2</h3> 
                    <li>
                        <strong>화면만 보면 틀렸다는 사실을 인지하기 어렵습니다.</strong>
                    </li>
                    <li>
                        <em>
                            Element탭이나 Visual Studio Code에서 소스 코드를 확인하세요.
                        </em>
                    </li>
                </section>
                <section>
                    <h3>예시 3</h3>
                    <li className="c1">
                        <span >글씨 크기를 조절하고 싶을 땐</span>
                    </li>
                    <li>
                        <span className="c2">요소 종류를 사용하는 것이 아니라</span>
                    </li>
                    <li>
                        <span className="c3">CSS를 이용해주세요.</span>
                    </li>
                    <li>
                        <span className="c4">요소의 의미와 맞지 않습니다.</span>
                    </li>
                </section>
                <section>
                    <h3>예시 4</h3>
                    <li className="lh1">요소 사이에 간격을 주고 싶을 때에도</li>
                    <li className="lh2">CSS를 이용해주세요.</li>
                    <li className="lh3">태그의 존재 의의와 맞지 않습니다.</li>
                    <li className="lh4">요소 사이의 간격을 조절할 때가 아니라 줄 바꿈을 할 때 사용해주세요.이렇게 사용해주시면 됩니다.</li>
                </section>
                <section>
                    <h3>예시 5</h3>
                    <li className="__color">스타일 속성을 적용하고 싶을 때에는</li>
                    <li className="__size">태그 안에 style 속성을 작성하는 방법인</li>
                    <li className="__weight">인라인 스타일링을 사용하지 마세요.</li>
                    <li className="__shadow">CSS 코드를 따로 작성하는 것이 웹 표준에 맞는 사용법입니다.</li>
                </section>
                <section>
                    <h3>종합 예시</h3> 
                        <li className="__listStyle lh2"><strong><a>위 예시를 종합적으로 섞어놓았습니다.</a></strong></li>
                            <div className="__bg__purple"><strong>이 정도 되면 보기만해도 불편하실 것 같습니다.</strong></div>
                        <h1 className="__color__grey"><em>틀린 곳을 찾아서 수정해보세요.</em></h1>
                </section>
            </section>
        </article>)
}

export default Page02

문제 3 : 대체 텍스트

이미지를 볼 수 없는 경우 (이미지의 링크가 깨졌을 때, 텍스트 전용 브라우저(Lynx 등)로 페이지를 열람할 때, 시각장애로 인해 TTS나 점자 등 비시각적인 요소에 의존하여야 할 때, 검색 엔진에서 크롤링할 때 등)에 이미지에 대한 설명을 제공한다.

  • 배경 이미지와 같이 정보를 인식할 필요가 없는 경우에는 alt 값으로 빈 문자열을 주어 스크린 리더가 인식하지 않게 한다.
  • 정보 전달이 필요한 콘텐츠에 빈 문자열을 입력할 경우 해당 콘텐츠의 존재 자체도 인식하지 못하게 되므로 주의해야 한다.
  • 인접 요소의 내용에서 이미지의 정보를 충분히 인지할 수 있는 경우에는 빈 문자열로 작성하는 것이 좋다.

수정 전 Page03
import catImage from '../static/images/cat.png'
import dogImage from '../static/images/dog.png'
import rabbitImage from '../static/images/rabbit.png'
import otterImage from '../static/images/otter.png'
import redPandaImage from '../static/images/red_panda.png'


const Page03 = () => {
    return (
        <article>
            <h1>문제 3 : 대체 텍스트</h1>
            <p>시각적 요소를 인지하지 못하는 사용자를 위해서 텍스트가 아닌 콘텐츠를 제공할 땐 해당 콘텐츠가 어떤 콘텐츠인지 설명하는 대체 텍스트를 작성해주어야 합니다.<br/>
                우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 아래 이미지들의 웹 접근성을 개선해보세요.</p>
            <li>리팩토링 하기 전, 스크린 리더를 사용하여 아래 이미지들을 어떻게 인식하는지 확인해보세요.</li>
            <li>리팩토링 후에 다시 한 번 스크린 리더를 사용하여 개선된 웹 접근성을 확인해보세요.</li>
            <section>
                <h2>귀여운 동물 사진들</h2>
                <section>
                    <h3>예시 1</h3>
                    <li>적절한 대체 텍스트를 alt 속성을 사용해 작성해주세요.</li>
                    <img src={catImage} />
                </section>
                <section>
                    <h3>예시 2</h3> 
                    <li>alt 속성으로 빈 문자열을 입력하면 요소를 인식하지 않습니다.</li>
                    <img src={dogImage} alt="" />
                </section>
                <section>
                    <h3>예시 3</h3>
                    <li>너무 광범위하지 않은 설명을 입력해주세요.</li>
                    <img src={rabbitImage} alt="동물"/>
                </section>
                <section>
                    <h3>예시 4</h3>
                    <li>지나치게 자세한 설명도 좋지 않습니다.</li>
                    <img src={otterImage} alt="바위 위에서 우수에 찬 눈빛으로 입을 앙 다문 채 좌측을 응시하고있는 발가락이 귀엽고 수염이 풍성한 수달" />
                </section>
                <section>
                    <h3>예시 5</h3>
                    <li>이미지를 충분히 설명해주는 인접 요소가 있다면 대체 텍스트를 작성하지 않아도 됩니다.
                        <li>내용이 중복된다면 오히려 작성하지 않는 것이 좋습니다.</li>
                    </li>
                    <img src={redPandaImage} alt="혀를 내밀고 있는 레서 팬더" />
                    <p>래서 펜더가 대나무를 앞발로 잡고 혀를 내밀고 있다.</p>
                </section>
            </section>
        </article>)
}

export default Page03
수정 후 Page03
import catImage from '../static/images/cat.png'
import dogImage from '../static/images/dog.png'
import rabbitImage from '../static/images/rabbit.png'
import otterImage from '../static/images/otter.png'
import redPandaImage from '../static/images/red_panda.png'


const Page03 = () => {
    return (
        <article>
            <h1>문제 3 : 대체 텍스트</h1>
            <p>시각적 요소를 인지하지 못하는 사용자를 위해서 텍스트가 아닌 콘텐츠를 제공할 땐 해당 콘텐츠가 어떤 콘텐츠인지 설명하는 대체 텍스트를 작성해주어야 합니다.<br/>
                우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 아래 이미지들의 웹 접근성을 개선해보세요.</p>
            <li>리팩토링 하기 전, 스크린 리더를 사용하여 아래 이미지들을 어떻게 인식하는지 확인해보세요.</li>
            <li>리팩토링 후에 다시 한 번 스크린 리더를 사용하여 개선된 웹 접근성을 확인해보세요.</li>
            <section>
                <ul>
                    
                </ul>
                <h2>귀여운 동물 사진들</h2>
                <section>
                    <h3>예시 1</h3>
                    <li>적절한 대체 텍스트를 alt 속성을 사용해 작성해주세요.</li>
                    <img src={catImage} alt="갈색 고양이가 왼쪽눈을 윙크하고 있다"/>
                </section>
                <section>
                    <h3>예시 2</h3> 
                    <li>alt 속성으로 빈 문자열을 입력하면 요소를 인식하지 않습니다.</li>
                    <img src={dogImage} alt="들판에 앉아서 정면을 바라보는 웰시코기" />
                </section>
                <section>
                    <h3>예시 3</h3>
                    <li>너무 광범위하지 않은 설명을 입력해주세요.</li>
                    <img src={rabbitImage} alt="하늘색 배경에 양모 위에 앉아있는 갈색 토끼"/>
                </section>
                <section>
                    <h3>예시 4</h3>
                    <li>지나치게 자세한 설명도 좋지 않습니다.</li>
                    <img src={otterImage} alt="바위 위에서 좌측을 응시하고있는 수달" />
                </section>
                <section>
                    <h3>예시 5</h3>
                    <li>이미지를 충분히 설명해주는 인접 요소가 있다면 대체 텍스트로 빈 문자열을 작성하는 것이 좋습니다.
                        <li>내용을 중복해서 전달할 필요가 없기 때문입니다.</li>
                    </li>
                    <img src={redPandaImage} alt="" />
                    <p>래서 펜더가 대나무를 앞발로 잡고 혀를 내밀고 있다.</p>
                </section>
            </section>
        </article>)
}

export default Page03

문제 4 : 콘텐츠 선형 구조

자료구조는 크게 3가지 선형 구조, 비선형 구조, 파일 구조로 분류할 수 있다.

선형 자료구조 (Linear)

  • 선형 자료구조란 하나의 자료 뒤에 하나의 자료가 존재하는 것이다.
  • 자료들 간의 앞뒤 관계가 1:1의 선형관계
  • 배열과 리스트가 대표적이고 더 나아가서 스택, 큐도 이에 해당된다.

비선형 자료구조 (NonLinear)

  • 비선형 자료구조란 하나의 자료 뒤에 여러개의 자료가 존재할 수 있는 것이다.
  • 자료들 간의 앞뒤 관계가 1:n, 또는 n:n 의 관계
  • 트리와 그래프가 대표적이며 계층적 구조를 나타내기에 적절하다.

page04에서는 따로 고칠 것 없이 구성이 순서대로 잘 짜여 있는지 예시1, 예시2를 비교 해 보았다.
구조적으로 짜인 예시2가 스크린 리더를 읽어 줄 때 순서대로 내용을 읽어주는것 같다.

Page04
import { useState } from "react"
import data from "../static/staticData"

const Page04 = () => {
    const [currentTab1, setCurrentTab1] = useState(0)
    const [currentTab2, setCurrentTab2] = useState(0)
    const { tab } = data
    
    return (
        <article>
            <h1>문제 4 : 콘텐츠 선형 구조</h1>
            <p>스크린 리더 사용자는 스크린 리더가 읽어주는대로 화면의 정보를 파악할 수 밖에 없습니다. 따라서 듣기만 해도 정보를 이해하기 좋은 구조로 마크업을 구성하는 것이 좋습니다. HTML 코드를 짤 때 어떻게 하면 더 논리적인 구조로 마크업을 구성할 수 있을지 고민해보세요.</p>
            <li>이번 문제에서는 수정할 코드는 없습니다.</li>
            <li>아래 예시들을 스크린 리더로 확인해보고 어떤 구조가 정보를 파악하기 더 좋은지 확인해보세요.</li>
            <li>두 예시에서 콘텐츠를 배치한 HTML 구조가 어떻게 다른지 코드를 직접 확인해보세요.</li>
            <section>
                <h2>예시 1</h2>
                <div class="tabContainer">
                    <div className="tabList">
                        <div className={currentTab1 === 0 ? "tab selected" : "tab"} onClick={()=>setCurrentTab1(0)}>{tab.tab1.title}</div>
                        <div className={currentTab1 === 1 ? "tab selected" : "tab"} onClick={()=>setCurrentTab1(1)}>{tab.tab2.title}</div>
                        <div className={currentTab1 === 2 ? "tab selected" : "tab"} onClick={()=>setCurrentTab1(2)}>{tab.tab3.title}</div>
                    </div>
                    <div className={currentTab1 === 0 ? "block" : "none"}>{tab.tab1.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                    <div className={currentTab1 === 1 ? "block" : "none"}>{tab.tab2.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                    <div className={currentTab1 === 2 ? "block" : "none"}>{tab.tab3.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                </div>
            </section>
            <section>
                <h2>예시 2</h2>
                <div class="tabContainer">
                    <div className="tabList">
                        <div>
                            <div className={currentTab2 === 0 ? "tab selected" : "tab"} onClick={()=>setCurrentTab2(0)}>{tab.tab1.title}</div>
                            <div className={`tabPanel${currentTab2 === 0 ? " block" : " none"}`}>{tab.tab1.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                        </div>
                        <div>
                            <div className={currentTab2 === 1 ? "tab selected" : "tab"}  onClick={()=>setCurrentTab2(1)}>{tab.tab2.title}</div>
                            <div className={`tabPanel${currentTab2 === 1 ? " block one" : " none"}`}>{tab.tab2.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                        </div>
                        <div>
                            <div className={currentTab2 === 2 ? "tab selected" : "tab"}  onClick={()=>setCurrentTab2(2)}>{tab.tab3.title}</div>
                            <div className={`tabPanel${currentTab2 === 2 ? " block two" : " none"}`}>{tab.tab3.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                        </div>
                    </div>
                </div>
            </section>
            <li>여기에 나온 예시가 정답은 아니며, 스타일링 할 때 비효율적이라는 단점도 있습니다. HTML 구조의 차이가 정보 전달에 있어서 어떤 차이를 가져오는지만 확인해주세요.</li>
            <li>웹 접근성을 고려해서 만큼 컴포넌트의 예시는 정말 많습니다. 궁금하시다면 구글링을 통해 컴포넌트 예시를 찾아보고 분석해보세요.</li>
        </article>
    )
}

export default Page04

문제 5 : WAI-ARIA

WAI-ARIA는 HTML 요소에 보조적으로 추가적인 의미를 부여할 수 있도록 해주는 기술이다. 이는 시맨틱 요소만으로는 충분히 의미를 부여하기 어려운 상황에서 사용할 수 있다. 하지만 WAI-ARIA를 남용하면 안 되며, 최우선적으로는 시맨틱한 HTML을 작성해야 한다.

WAI-ARIA 사용법

1. 역할(Role)

  • HTML 요소의 역할을 정의하는 속성
  • HTML의 요소 종류와 역할이 서로 맞지 않을 때, 어떤 역할을 하는 요소인지 명시해줄 때 사용할 수 있는 속성(attribute)
<div role="button">div이지만 button으로 사용되는 요소</div>

※ 주의할 점, HTML 요소로 충분히 파악할 수 있는 내용을 WAI-ARIA로 또 설명해줄 필요는 없다.

// WAI-ARIA의 잘못된 사용 예시
<button role="button">button인 요소</button>

 시맨틱 요소 본연의 의미를 임의로 바꾸지 않아야 한다.

// WAI-ARIA의 잘못된 사용 예시
<h1 role="button">h1인 요소</h1>

2. 상태(State)

  • 요소의 현재 상태를 나타내는 속성

aria-selected : 여러 개의 선택 가능한 요소중에서 선택 상태인 요소를 표시할 수 있는 속성

<div role="tabList">
  <li role="tab" aria-selected="true">Tab1</li>
  <li role="tab" aria-selected="false">Tab2</li>
  <li role="tab" aria-selected="false">Tab3</li>
</div>
// 3개의 탭 중에서 첫 번째 탭이 선택된 상태임을 알 수 있다. 
// 이 외에도 아코디언 UI가 펼쳐진 상태인지 표시해주는 aria-expanded, 
// 요소가 숨김 상태인지를 표시하는 aria-hidden 등의 속성이 있다.

<div role="tabpanel">Tab menu ONE</div>
<div role="tabpanel">Tab menu TWO</div>
<div role="tabpanel">Tab menu THREE</div>

3. 속성(Property)

  • 요소의 특징을 정의하는 속성(attribute)

aria-label : 요소에 대한 정보를 전혀 얻을 수 없는 경우가 발생하기도 한다. 텍스트 콘텐츠 없이 이미지로만 만들어진 버튼이 대표적인 예시이다. 이미지만 들어있는 버튼의 경우, HTML 요소의 구조만으로 어떤 역할을 하는 버튼인지 파악하기 어렵다.

<button> <img src="X.png" /> </button>
<button> <img src="돋보기.png" /> </button>

물론 버튼 요소에 숨겨진 자식 요소를 추가해서 어떤 역할을 하는지 설명하는 내용을 추가해줄 수 도 있지만, 이럴 때 사용할 수 있는 WAI-ARIA 속성이 바로 aria-label 이다. 요소에 라벨을 붙여주는 기능을 가진다. 해당 요소를 사용하면 다음과 같이 의미를 부여해줄 수 있다.

<button aria-label="닫기"/> <img src="X.png" /> </button>
<button aria-label="검색"/> <img src="돋보기.png" /> </button>

aria-live : 해당 요소가 실시간으로 내용을 갱신하는 영역인지 표시한다. 즉, 브라우징 도중에 내용을 띄우는 alert, modal, dialog 와 같은 역할을 하는 요소이거나, AJAX 기술을 사용하여 실시간으로 내용을 갱신하는 영역에 사용하는 속성이다. 시각 장애인들은 화면의 동적인 요소를 알아채기 어렵기 때문에, 이 속성을 사용해서 실시간으로 갱신되는 내용을 알려주면 큰 도움이 된다. 속성 값으로는 polite, assertive, off(default)가 있다.

polite : 스크린 리더가 현재 읽고있는 내용을 모두 읽고나서 갱신된 내용을 사용자에게 전달
assertive : 스크린 리더가 현재 읽고있는 내용을 중단하고 갱신된 내용을 바로 사용자에게 전달

수정 전 Page05
import { useState } from "react"
import data from "../static/staticData"
import home from "../static/images/icon-home.png"
import web from "../static/images/icon-web.png"
import mail from "../static/images/icon-mail.png"

const Page05 = () => {
    const [currentTab, setCurrentTab] = useState(0)
    const { tab } = data

    return (
        <article>
            <h1>문제 5 : WAI-ARIA</h1>
            <p>시맨틱 요소만으로 의미를 충분히 부여할 수 없는 상황에 WAI-ARIA를 사용하면 HTML 요소에 추가적인 의미를 부여하여 더 원활하게 페이지를 탐색 할 수 있게 도와줍니다. <br />
            ‘시맨틱 요소만으로 의미를 충분히 부여할 수 없는 상황’이라는 것은 <strong>시맨틱 요소만으로 충분한 상황에서는 WAI-ARIA를 사용하지 않아야 한다</strong>는 의미입니다. WAI-ARIA는 보조적인 역할로만 사용해야 합니다. WAI-ARIA를 남용해선 안 되며, 시맨틱한 HTML을 작성하는 것이 최우선입니다.<br />
            우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 WAI-ARIA를 사용해보세요.</p>
            <section>
                <h2>WAI-ARIA 사용하기</h2>
                <section>
                    <h3>예시 1 : 역할(Role)</h3>
                    <li>요소의 이름이 요소의 역할을 충분히 설명하지 못할 때 사용할 수 있습니다.
                        <div className="button">요소는 div</div>
                    </li>
                    <li>요소의 이름으로 요소의 역할을 파악할 수 있을 때는 사용하지 마세요.
                        <button role="button">요소는 button</button>
                    </li>
                    <li>요소 본연의 역할을 바꾸지 마세요.
                        <h3 role="button" className="button">요소는 h3</h3>
                    </li>
                    <h3>예시 1 - 문제</h3>
                    <li>아래 예시는 문제 4에서 보았던 탭 컴포넌트입니다. 각 컴포넌트에 맞는 역할을 WAI-ARIA로 작성해보세요.</li>
                    <li>WAI-ARIA 작성 전후로 개별 요소를 지정했을 때 스크린 리더가 읽어주는 내용의 차이를 확인해보세요.</li>
                    <div class="tabContainer">
                        <div className="tabList">
                            <div className={currentTab === 0 ? "tab selected" : "tab"} onClick={()=>setCurrentTab(0)}>{tab.tab1.title}</div>
                            <div className={currentTab === 1 ? "tab selected" : "tab"} onClick={()=>setCurrentTab(1)}>{tab.tab2.title}</div>
                            <div className={currentTab === 2 ? "tab selected" : "tab"} onClick={()=>setCurrentTab(2)}>{tab.tab3.title}</div>
                        </div>
                        <div className={currentTab === 0 ? "block" : "none"}>{tab.tab1.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                        <div className={currentTab === 1 ? "block" : "none"}>{tab.tab2.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                        <div className={currentTab === 2 ? "block" : "none"}>{tab.tab3.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                    </div>
                </section>
                <section>
                    <h3>예시 2 : 속성(property)</h3> 
                    <li>시맨틱 요소를 사용했음에도 요소의 역할에 대한 설명이 충분하지 않은 경우가 있습니다. 이럴 때 보조적 역할로 WAI-ARIA를 사용할 수 있습니다.</li>
                    <li>WAI-ARIA 작성 전후로 개별 요소를 지정했을 때 스크린 리더가 읽어주는 내용의 차이를 확인해보세요.</li>
                    <div className="iconButtonContainer">
                        <button className="iconButton"><img src={home} /></button>
                        <button className="iconButton"><img src={web} /></button>
                        <button className="iconButton"><img src={mail} /></button>
                    </div>
                </section>
                <li>WAI-ARIA에는 정말 많은 속성들이 있지만, role, aria-label 정도만 사용해도 HTML에 추가적인 의미를 부여할 수 있기 때문에 웹 접근성을 어느정도 향상시킬 수 있습니다. 하지만 웹 접근성을 확보할 때 가장 중요한 것은 시맨틱한 HTML을 작성하는 것임을 항상 기억하세요. 앞서 말했듯, WAI-ARIA는 보조적인 역할로만 사용해야 합니다.</li>
            </section>
        </article>
    )
}

export default Page05
수정 후 Page05
import { useState } from "react"
import data from "../static/staticData"
import home from "../static/images/icon-home.png"
import web from "../static/images/icon-web.png"
import mail from "../static/images/icon-mail.png"

const Page05 = () => {
    const [currentTab, setCurrentTab] = useState(0)
    const { tab } = data

    return (
        <article>
            <h1>문제 5 : WAI-ARIA</h1>
            <p>시맨틱 요소만으로 의미를 충분히 부여할 수 없는 상황에 WAI-ARIA를 사용하면 HTML 요소에 추가적인 의미를 부여하여 더 원활하게 페이지를 탐색 할 수 있게 도와줍니다. <br />
            ‘시맨틱 요소만으로 의미를 충분히 부여할 수 없는 상황’이라는 것은 <strong>시맨틱 요소만으로 충분한 상황에서는 WAI-ARIA를 사용하지 않아야 한다</strong>는 의미입니다. WAI-ARIA는 보조적인 역할로만 사용해야 합니다. WAI-ARIA를 남용해선 안 되며, 시맨틱한 HTML을 작성하는 것이 최우선입니다.<br />
            우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 WAI-ARIA를 사용해보세요.</p>
            <section>
                <h2>WAI-ARIA 사용하기</h2>
                <section>
                    <h3>예시 1 : 역할(Role)</h3>
                    <li>요소의 이름이 요소의 역할을 충분히 설명하지 못할 때 사용할 수 있습니다.
                        <div role="button" className="button">요소는 div</div>
                    </li>
                    <li>요소의 이름으로 요소의 역할을 파악할 수 있을 때는 사용하지 마세요.
                        <button>요소는 button</button>
                    </li>
                    <li>요소 본연의 역할을 바꾸지 마세요.
                        <h3 role="h3" className="button">요소는 h3</h3>
                    </li>
                    <h3>예시 1 - 문제</h3>
                    <li>아래 예시는 문제 4에서 보았던 탭 컴포넌트입니다. 각 컴포넌트에 맞는 역할을 WAI-ARIA로 작성해보세요.</li>
                    <li>WAI-ARIA 작성 전후로 개별 요소를 지정했을 때 스크린 리더가 읽어주는 내용의 차이를 확인해보세요.</li>
                    <div class="tabContainer">
                        <div role ="tabList" className="tabList">
                            <div role="tab"
                            className={currentTab === 0 ? "tab selected" : "tab"} onClick={()=>setCurrentTab(0)}>{tab.tab1.title}</div>
                            <div role="tab"
                            className={currentTab === 1 ? "tab selected" : "tab"} onClick={()=>setCurrentTab(1)}>{tab.tab2.title}</div>
                            <div role="tab"
                            className={currentTab === 2 ? "tab selected" : "tab"} onClick={()=>setCurrentTab(2)}>{tab.tab3.title}</div>
                        </div>
                        <div role="tabPanel"
                        className={currentTab === 0 ? "block" : "none"}>{tab.tab1.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                        <div role="tabPanel"
                        className={currentTab === 1 ? "block" : "none"}>{tab.tab2.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                        <div role="tabPanel"
                        className={currentTab === 2 ? "block" : "none"}>{tab.tab3.content.map((el,idx)=> <li key={idx}>{el}</li>)}</div>
                    </div>
                </section>
                <section>
                    <h3>예시 2 : 속성(property)</h3> 
                    <li>시맨틱 요소를 사용했음에도 요소의 역할에 대한 설명이 충분하지 않은 경우가 있습니다. 이럴 때 보조적 역할로 WAI-ARIA를 사용할 수 있습니다.</li>
                    <li>WAI-ARIA 작성 전후로 개별 요소를 지정했을 때 스크린 리더가 읽어주는 내용의 차이를 확인해보세요.</li>
                    <div className="iconButtonContainer">
                        <button  
                        aria-label="홈"
                        className="iconButton"><img src={home} /></button>
                        <button 
                        aria-label="웹"
                        className="iconButton"><img src={web} /></button>
                        <button 
                        aria-label="이메일"
                        className="iconButton"><img src={mail} /></button>
                    </div>
                </section>
                <li>WAI-ARIA에는 정말 많은 속성들이 있지만, role, aria-label 정도만 사용해도 HTML에 추가적인 의미를 부여할 수 있기 때문에 웹 접근성을 어느정도 향상시킬 수 있습니다. 하지만 웹 접근성을 확보할 때 가장 중요한 것은 시맨틱한 HTML을 작성하는 것임을 항상 기억하세요. 앞서 말했듯, WAI-ARIA는 보조적인 역할로만 사용해야 합니다.</li>
            </section>
        </article>
    )
}

export default Page05

문제 6 : 표의 구성

비장애인은 표를 보면 그 구조를 인식할 수 있지만, 시각 장애가 있는 경우에는 내용을 들으면서 그 구조를 파악해야만 합한다. 따라서 듣기만해도 표의 구조, 내용을 이해하기 쉽게 구성해야 한다.

  • 테이블 요소 안에 <caption> 요소를 사용해서 표에 제목을 제공해준다.
  • 표의 셀은 제목 셀과 데이터 셀이 구분되도록 구성해야 한다. 제목 셀은 <th>, 데이터 셀은 <td> 를 사용하면 된다.
  • 표의 구조가 복잡할 경우, 최대한 간소화하거나 scope, id, headers 속성을 사용하여 작성한다.

테이블 태그 요소

  • <table>: 테이블을 만드는 태그.
  • <tr>: 행(table row)을 시작한다.
  • <td>: 표의 내용(table data), 셀을 표현한다.
  • <th>: 테이블의 행, 열의 머리말(table heading)을 나타낸다. 기본적으로 가운데로 정렬되고 굵은 글씨로 표시된다.
  • colspan, rowspan속성으로 셀을 병합할 수 있다. colspan은 열 병합, rowspan은 행을 병합한다. 둘 다 써서 행과 열을 함께 병합할 수도 있다.
  • <caption>: 테이블의 제목을 기술한다.
  • <colgroup>, <col>: 테이블 상단에 넣어 테이블의 열 정보를 기술한다. 주로 일괄적으로 셀의 너비를 지정할 때 쓰인다.
  • <thead>, <tbody>, <tfoot>: 테이블의 세부 구조를 기술한다. 각각 표의 상단, 본문, 하단 부분에 대응한다.
<table>
  <tr>
    <th> </th>
    <th>월</th>
    <th>수</th>
    <th>금</th>
  </tr>
  <tr>
    <th>1교시</th>
    <td rowspan="2">국어</td>
    <td>수학</td>
    <td>영어</td>
  </tr>
  <tr>
    <th>2교시</th>
    <!-- 병합되었으므로 쓰지 않습니다. -->
    <td>과학</td>
    <td>사회</td>
  </tr>
</table>

수정 전 Page06
import tableExample from "../static/images/table_example.png"

const Page06 = () => {
    return (
        <article>
            <h1>문제 6 : 표의 구성</h1>
            <p>비장애인은 표를 보면 그 구조를 인식할 수 있지만, 시각 장애가 있는 경우에는 내용을 들으면서 그 구조를 파악해야만 합니다. 따라서 듣기만해도 표의 구조, 내용을 이해하기 쉽게 구성해야 합니다.</p>
            <section>
                <h2>좋은 예시 1</h2>
                <li>표의 제목을 제공하고, 테이블 요소도 올바르게 사용했습니다. HTML 요소 구성을 직접 확인해보세요.</li>
                <table>
                    <caption>테이블 요소의 종류</caption>
                    <thead>
                        <tr>
                            <th>요소</th>
                            <th>역할</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>{`<table>`}</td>
                            <td>표를 생성</td>
                        </tr>
                        <tr>
                            <td>{`<caption>`}</td>
                            <td>표의 제목</td>
                        </tr>
                        <tr>
                            <td>{`<thead>`}</td>
                            <td>(optional) 열의 제목을 묶음</td>
                        </tr>
                        <tr>
                            <td>{`<tbody>`}</td>
                            <td>(optional) 표의 내용을 묶음</td>
                        </tr>
                        <tr>
                            <td>{`<th>`}</td>
                            <td>열의 제목</td>
                        </tr>
                        <tr>
                            <td>{`<tr>`}</td>
                            <td>table row의 약자. 열을 생성</td>
                        </tr>
                        <tr>
                            <td>{`<td>`}</td>
                            <td>table data의 약자. 행을 생성</td>
                        </tr>
                    </tbody>
                </table>
            </section>
            <section>
                <h2>좋은 예시 2-1</h2>
                <li>비교적 복잡한 구성의 표에서 scope 속성을 사용하여 행과 열의 제목이 무엇인지 표시해주었습니다.</li>
                <table>
                    <caption>Cmarket 판매총액</caption>
                    <thead>
                        <tr>
                            <th scope="col">(col)<br/>상품명</th>
                            <th scope="col">(col)<br/>판매가</th>
                            <th scope="col">(col)<br/>판매량</th>
                            <th scope="col">(col)<br/>판매총액</th>
                        </tr>
                        </thead>
                    <tbody>
                        <tr>
                            <td scope="row">(row)<br/>2020년 달력</td>
                            <td>12,000원</td>
                            <td>6개</td>
                            <td>72,000원</td>
                        </tr>
                        <tr>
                            <td scope="row">(row)<br/>개구리 안대</td>
                            <td>2,900원</td>
                            <td>4개</td>
                            <td>11,600원</td>
                        </tr>
                        <tr>
                            <td scope="row">(row)<br/>잉어 슈즈</td>
                            <td>3,900원</td>
                            <td>7개</td>
                            <td>27,300원</td>
                        </tr>
                        <tr>
                            <td scope="row">(row)<br/>노른자 분리기</td>
                            <td>9,900원</td>
                            <td>5개</td>
                            <td>49,500원</td>
                        </tr>
                    </tbody>
                </table>
            </section>
            <section>
                <h2>좋은 예시 2-2</h2>
                <li>비교적 복잡한 구성의 표에서 id와 headers를 사용해 데이터 구조를 표시해주었습니다.</li>
                <table>
                    <caption>Cmarket 판매총액</caption>
                    <thead>
                        <tr>
                            <th id="A">상품명<br/>(A)</th>
                            <th id="B">판매가<br/>(B)</th>
                            <th id="C">판매량<br/>(C)</th>
                            <th id="D">판매총액<br/>(D)</th>
                        </tr>
                        </thead>
                    <tbody>
                        <tr>
                            <td id="a">2020년 달력<br/>(a)</td>
                            <td headers="B a">12,000원<br/>(B a)</td>
                            <td headers="C a">6개<br/>(C a)</td>
                            <td headers="D a">72,000원<br/>(D a)</td>
                        </tr>
                        <tr>
                            <td id="b">개구리 안대<br/>(b)</td>
                            <td headers="B b">2,900원<br/>(B b)</td>
                            <td headers="C b">4개<br/>(C b)</td>
                            <td headers="D b">11,600원<br/>(D b)</td>
                        </tr>
                        <tr>
                            <td id="c">잉어 슈즈<br/>(c)</td>
                            <td headers="B c">3,900원<br/>(B c)</td>
                            <td headers="C c">7개<br/>(C c)</td>
                            <td headers="D c">27,300원<br/>(D c)</td>
                        </tr>
                        <tr>
                            <td id="d">노른자 분리기<br/>(d)</td>
                            <td headers="B d">9,900원<br/>(B d)</td>
                            <td headers="C d">5개<br/>(C d)</td>
                            <td headers="D d">49,500원<br/>(D d)</td>
                        </tr>
                    </tbody>
                </table>
                <li>예시 2-1, 예시 2-2처럼 테이블을 작성하면, 표 구성을 파악하기 더 쉬워집니다.</li>
                <li>이번 과제에서 사용해보는 무료 스크린리더는 속성 작성 전과 차이 없이 표를 읽지만, 일부 유료 스크린 리더는 표를 다음과 같이 읽게 됩니다.
                    <li><strong>속성 작성 전 :</strong> 상품명 → 판매가 → 판매량 → 판매총액 → 2020년 달력 → 12,000원 → 6개 → 72,000원 → 개구리 안대 → ...</li>
                    <li><strong>속성 작성 후 :</strong> 상품명 → 2020년 달력 → 판매가 → 12,000원 → 판매량 → 6개 → 판매총액 → 72,000원 → 상품명 → 개구리 안대 → ...</li>
                </li>
            </section>
            <section>
                <h2>실습</h2>
                <li>아래 이미지를 HTML 표로 바꿔서 작성해보세요.
                    <li>scope 속성을 사용해서 한 번, id, headers 속성을 사용해서 한 번 작성해보세요.</li>
                    <li>보고 이해하는 것을 넘어 직접 작성 해보면 사용법을 제대로 파악할 수 있습니다.</li>
                    <img src={tableExample} />
                </li>
                <li>
                    scope 속성 사용
                    <table></table>
                </li>
                <li>
                    id, headers 속성 사용
                    <table></table>
                </li>
            </section>
        </article>
    )
}

export default Page06
수정 후 Page06
import tableExample from "../static/images/table_example.png"

const Page06 = () => {
    return (
        <article>
            <h1>문제 6 : 표의 구성</h1>
            <p>비장애인은 표를 보면 그 구조를 인식할 수 있지만, 시각 장애가 있는 경우에는 내용을 들으면서 그 구조를 파악해야만 합니다. 따라서 듣기만해도 표의 구조, 내용을 이해하기 쉽게 구성해야 합니다.</p>
            <section>
                <h2>좋은 예시 1</h2>
                <li>표의 제목을 제공하고, 테이블 요소도 올바르게 사용했습니다. HTML 요소 구성을 직접 확인해보세요.</li>
                <table>
                    <caption>테이블 요소의 종류</caption>
                    <thead>
                        <tr>
                            <th>요소</th>
                            <th>역할</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>{`<table>`}</td>
                            <td>표를 생성</td>
                        </tr>
                        <tr>
                            <td>{`<caption>`}</td>
                            <td>표의 제목</td>
                        </tr>
                        <tr>
                            <td>{`<thead>`}</td>
                            <td>(optional) 열의 제목을 묶음</td>
                        </tr>
                        <tr>
                            <td>{`<tbody>`}</td>
                            <td>(optional) 표의 내용을 묶음</td>
                        </tr>
                        <tr>
                            <td>{`<th>`}</td>
                            <td>열의 제목</td>
                        </tr>
                        <tr>
                            <td>{`<tr>`}</td>
                            <td>table row의 약자. 열을 생성</td>
                        </tr>
                        <tr>
                            <td>{`<td>`}</td>
                            <td>table data의 약자. 행을 생성</td>
                        </tr>
                    </tbody>
                </table>
            </section>
            <section>
                <h2>좋은 예시 2-1</h2>
                <li>비교적 복잡한 구성의 표에서 scope 속성을 사용하여 행과 열의 제목이 무엇인지 표시해주었습니다.</li>
                <table>
                    <caption>Cmarket 판매총액</caption>
                    <thead>
                        <tr>
                            <th scope="col">(col)<br/>상품명</th>
                            <th scope="col">(col)<br/>판매가</th>
                            <th scope="col">(col)<br/>판매량</th>
                            <th scope="col">(col)<br/>판매총액</th>
                        </tr>
                        </thead>
                    <tbody>
                        <tr>
                            <td scope="row">(row)<br/>2020년 달력</td>
                            <td>12,000원</td>
                            <td>6개</td>
                            <td>72,000원</td>
                        </tr>
                        <tr>
                            <td scope="row">(row)<br/>개구리 안대</td>
                            <td>2,900원</td>
                            <td>4개</td>
                            <td>11,600원</td>
                        </tr>
                        <tr>
                            <td scope="row">(row)<br/>잉어 슈즈</td>
                            <td>3,900원</td>
                            <td>7개</td>
                            <td>27,300원</td>
                        </tr>
                        <tr>
                            <td scope="row">(row)<br/>노른자 분리기</td>
                            <td>9,900원</td>
                            <td>5개</td>
                            <td>49,500원</td>
                        </tr>
                    </tbody>
                </table>
            </section>
            <section>
                <h2>좋은 예시 2-2</h2>
                <li>비교적 복잡한 구성의 표에서 id와 headers를 사용해 데이터 구조를 표시해주었습니다.</li>
                <table>
                    <caption>Cmarket 판매총액</caption>
                    <thead>
                        <tr>
                            <th id="A">상품명<br/>(A)</th>
                            <th id="B">판매가<br/>(B)</th>
                            <th id="C">판매량<br/>(C)</th>
                            <th id="D">판매총액<br/>(D)</th>
                        </tr>
                        </thead>
                    <tbody>
                        <tr>
                            <td id="a">2020년 달력<br/>(a)</td>
                            <td headers="B a">12,000원<br/>(B a)</td>
                            <td headers="C a">6개<br/>(C a)</td>
                            <td headers="D a">72,000원<br/>(D a)</td>
                        </tr>
                        <tr>
                            <td id="b">개구리 안대<br/>(b)</td>
                            <td headers="B b">2,900원<br/>(B b)</td>
                            <td headers="C b">4개<br/>(C b)</td>
                            <td headers="D b">11,600원<br/>(D b)</td>
                        </tr>
                        <tr>
                            <td id="c">잉어 슈즈<br/>(c)</td>
                            <td headers="B c">3,900원<br/>(B c)</td>
                            <td headers="C c">7개<br/>(C c)</td>
                            <td headers="D c">27,300원<br/>(D c)</td>
                        </tr>
                        <tr>
                            <td id="d">노른자 분리기<br/>(d)</td>
                            <td headers="B d">9,900원<br/>(B d)</td>
                            <td headers="C d">5개<br/>(C d)</td>
                            <td headers="D d">49,500원<br/>(D d)</td>
                        </tr>
                    </tbody>
                </table>
                <li>예시 2-1, 예시 2-2처럼 테이블을 작성하면, 표 구성을 파악하기 더 쉬워집니다.</li>
                <li>이번 과제에서 사용해보는 무료 스크린리더는 속성 작성 전과 차이 없이 표를 읽지만, 일부 유료 스크린 리더는 표를 다음과 같이 읽게 됩니다.
                    <li><strong>속성 작성 전 :</strong> 상품명 → 판매가 → 판매량 → 판매총액 → 2020년 달력 → 12,000원 → 6개 → 72,000원 → 개구리 안대 → ...</li>
                    <li><strong>속성 작성 후 :</strong> 상품명 → 2020년 달력 → 판매가 → 12,000원 → 판매량 → 6개 → 판매총액 → 72,000원 → 상품명 → 개구리 안대 → ...</li>
                </li>
            </section>
            <section>
                <h2>실습</h2>
                <li>아래 이미지를 HTML 표로 바꿔서 작성해보세요.
                    <li>scope 속성을 사용해서 한 번, id, headers 속성을 사용해서 한 번 작성해보세요.</li>
                    <li>보고 이해하는 것을 넘어 직접 작성 해보면 사용법을 제대로 파악할 수 있습니다.</li>
                    <img src={tableExample} />
                </li>
                <li>
                    scope 속성 사용
                    <table>
                        <caption>바밤바 시리즈 정리</caption>
                        <thead>
                        <tr>
                            <th scope="col">이름</th>
                            <th scope="col">당류</th>
                            <th scope="col">내용량</th>
                            <th scope="col">칼로리</th>
                        </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td scope="row">바밤바</td>
                                <td scope="row">13g</td>
                                <td scope="row">70ml</td>
                                <td scope="row">100kcal</td>
                            </tr>
                            <tr>
                                <td scope="row">배뱀배</td>
                                <td scope="row">14g</td>
                                <td scope="row">70ml</td>
                                <td scope="row">75kcal</td>
                            </tr>
                            <tr>
                                <td scope="row">바밤바샌드</td>
                                <td scope="row">24g</td>
                                <td scope="row">180ml</td>
                                <td scope="row">240kcal</td>
                            </tr>
                        </tbody>
                    </table>
                </li>
                <li>
                    id, headers 속성 사용
                    <table>
                        <caption>바밤바 시리즈 정리</caption>
                        <thead>
                        <tr>
                            <th id="A">이름</th>
                            <th id="B">당류</th>
                            <th id="C">내용량</th>
                            <th id="D">칼로리</th>
                        </tr>
                        </thead>
                        <tbody>
                        <tr>
                            <td id="a">바밤바</td>
                            <td headers="B a">13g</td>
                            <td headers="C a">70ml</td>
                            <td headers="D a">100kcal</td>
                        </tr>
                        <tr>
                            <td id="b">배뱀배</td>
                            <td headers="B b">14g</td>
                            <td headers="C b">70ml</td>
                            <td headers="D b">75kcal</td>
                        </tr>
                        <tr>
                            <td id="c">바밤바샌드</td>
                            <td headers="B c">24g</td>
                            <td headers="C c">180ml</td>
                            <td headers="D c">240kcal</td>
                        </tr>
                        </tbody>
                        
                    </table>
                </li>
            </section>
        </article>
    )
}

export default Page06

문제 7 : 레이블 제공

레이블을 붙이는 이유는 웹 접근성을 높이기 위해서이다. 스크린 리더 등 보조 기술을 사용하는 사용자는 라벨을 통해 input 요소의 목적을 이해할 수 있다. 라벨을 붙이지 않으면, 화면에 표시되는 레이블만으로는 목적을 파악하는 것이 어렵기 때문에, 사용자 경험이 떨어질 수 있다. 따라서 라벨을 붙여 웹 접근성을 높이는 것이 좋다.

input 태그에 라벨을 붙이는 방법은 두 가지가 있다.

  • 라벨 태그와 for 속성 사용하기 input 태그에 해당하는 라벨 태그를 작성하고, 라벨 태그에 for 속성을 이용해 input 태그의 id 값을 연결해준다.
<label for="user-name">사용자 이름:</label>
<input type="text" id="user-name" name="user-name">
  • input 태그 안에 직접 라벨을 작성하기 input 태그 안에 직접 라벨을 작성해준다.
<input type="text" id="user-name" name="user-name" aria-label="사용자 이름">
  • placeholder를 사용하더라도 레이블을 작성하기. placeholder는 레이블을 대체할 수 없다.placeholder는 내용을 입력하는 순간 사라지기 때문에 일부 스크린 리더는 읽지 못하게 된다.
<label for="username">아이디:</label>
<input type="text" id="username" name="username" placeholder="아이디를 입력하세요">

<label for="password">비밀번호:</label>
<input type="password" id="password" name="password" placeholder="비밀번호를 입력하세요">

<input type="submit" value="로그인">
수정 전 Page07
const Page07 = () => {
    return (
        <article>
            <h1>문제 7 : 레이블 제공</h1>
            <p>사용자가 정보를 입력하는 상황에, 어떤 정보를 입력해야 하는지 정확하게 알 수 없으면 입력이 불가능합니다. 따라서 사용자 입력에 대응하는 레이블을 제공해야 합니다.<br/>
            우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 레이블을 작성하세요.
            </p>
            <section>
                <h2>예시 1</h2>
                <li>{`<input>`}요소만 있으면 무엇을 입력하라는 의미인지 알 수 없습니다. 레이블을 꼭 작성해주세요.</li>
                <div className="inputContainer">
                    <input type="text"/>
                </div>
            </section>
            <section>
                <h2>예시 2</h2>
                <li>{`<input>`}요소에 placeholder를 사용하더라도 레이블을 작성해주세요. placeholder는 레이블을 대체할 수 없습니다.
                    <li>placeholder는 내용을 입력하는 순간 사라지기 때문에 일부 스크린 리더는 읽지 못하게 됩니다.</li>
                </li>
                <div className="inputContainer">
                    <input type="text" placeholder="아이디" />
                    <input type="text" placeholder="비밀번호" />
                </div>
            </section>
            <section>
            <h2>예시 3</h2>
                <li>{`<input>`}요소 밖에 무엇을 입력해야하는지 알려주는 요소가 있더라도, {`<label>`}요소로 레이블을 작성해 {`<input>`}요소와 연결해주세요.
                    <li>{`<input>`}요소에서 id를 작성하고,{`<label>`}요소의 for 속성으로 연결할 {`<input>`}요소의 id를 작성합니다.</li>
                    <li>작성 후 {`<label>`}요소를 클릭하면 어떻게 되는지 확인해보세요.</li>
                </li>
                <div className="inputContainer">
                        <span>아이디</span>
                        <input id="아이디" type="text" />
                        <span>비밀번호</span>
                        <input id="비밀번호" type="text" />
                </div>
            </section>
            <section>
                <h2>예시 4</h2>
                <li>WAI-ARIA의 aria-label 속성을 사용할 수도 있습니다.
                    <li>단, WAI-ARIA의 경우 꼭 필요한 경우가 아니라면 사용하지 않는 것이 좋습니다. 다른 HTML 속성이나 요소로 대체 가능한 경우에는 해당 속성이나 요소를 우선적으로 사용해주세요.</li>
                </li>
                <div className="inputContainer">
                        <input type="text" />
                </div>
            </section>
        </article>
    )
}

export default Page07
수정 후 Page07
const Page07 = () => {
    return (
        <article>
            <h1>문제 7 : 레이블 제공</h1>
            <p>사용자가 정보를 입력하는 상황에, 어떤 정보를 입력해야 하는지 정확하게 알 수 없으면 입력이 불가능합니다. 따라서 사용자 입력에 대응하는 레이블을 제공해야 합니다.<br />
                우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 레이블을 작성하세요.
            </p>
            <section>
                <h2>예시 1</h2>
                <li>{`<input>`}요소만 있으면 무엇을 입력하라는 의미인지 알 수 없습니다. 레이블을 꼭 작성해주세요.</li>
                <div className="inputContainer">
                    <label for="foo">foo</label>
                    <input id="foo" type="text" />
                </div>
            </section>
            <section>
                <h2>예시 2</h2>
                <li>{`<input>`}요소에 placeholder를 사용하더라도 레이블을 작성해주세요. placeholder는 레이블을 대체할 수 없습니다.
                    <li>placeholder는 내용을 입력하는 순간 사라지기 때문에 일부 스크린 리더는 읽지 못하게 됩니다.</li>
                </li>
                <div className="inputContainer">
                    <label for="id">아이디</label>
                    <input id="id" type="text" placeholder="아이디" />

                    <label for="password">비밀번호</label>
                    <input id="password" type="text" placeholder="비밀번호" />
                </div>
            </section>
            <section>
                <h2>예시 3</h2>
                <li>{`<input>`}요소 밖에 무엇을 입력해야하는지 알려주는 요소가 있더라도, {`<label>`}요소로 레이블을 작성해 {`<input>`}요소와 연결해주세요.
                    <li>{`<input>`}요소에서 id를 작성하고,{`<label>`}요소의 for 속성으로 연결할 {`<input>`}요소의 id를 작성합니다.</li>
                    <li>작성 후 {`<label>`}요소를 클릭하면 어떻게 되는지 확인해보세요.</li>
                </li>
                <div className="inputContainer">
                    <label for="아이디">
                        <span>아이디</span>
                    </label>
                    <input id="아이디" type="text" />

                    <label for="비밀번호">
                        <span>비밀번호</span>
                    </label>
                    <input id="비밀번호" type="text" />
                </div>
            </section>
            <section>
                <h2>예시 4</h2>
                <li>WAI-ARIA의 aria-label 속성을 사용할 수도 있습니다.
                    <li>단, WAI-ARIA의 경우 꼭 필요한 경우가 아니라면 사용하지 않는 것이 좋습니다. 다른 HTML 속성이나 요소로 대체 가능한 경우에는 해당 속성이나 요소를 우선적으로 사용해주세요.</li>
                </li>
                <div className="inputContainer">
                    <input type="text" aria-label="텍스트" />
                </div>
            </section>
        </article>
    )
}

export default Page07

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.