이번에는 앞서 배운 웹표준, 웹 접근성을 개선하는 방법을 가지고 페어분과 함께
스프린트 과제를 진행하였다.
page01에서는 div요소를 시맨틱요소로 바꾸어 주었고, class 속성을 없애주고, CSS 파일에서 class와 연결되어있던 스타일 속성들도 바뀐 요소에 맞춰 수정하였다.
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
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
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
const Page02 = () => {
return (
<article>
<h1>문제 2 : 자주 틀리는 마크업</h1>
<p>자주 틀리는 HTML 요소의 사용법들을 고쳐봅시다. 웹 표준을 저해하는 사용법이지만, 화면 상으로는 큰 문제가 없기 때문에 의외로 자주 발견할 수 있는 예시들 이기도 합니다.<br />
우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 웹 표준에 맞는 마크업으로 바꾸세요.</p>
<li>아래 자주 틀리는 마크업 예시들을 웹 표준에 맞게 수정하세요.</li>
<li>예시 외에도 애플리케이션 내에 틀리게 사용한 마크업이 있습니다. 찾아서 수정해보세요.</li>
<section>
<h2>틀린 마크업 예시</h2>
<section>
<h3>예시 1</h3>
<li>
<div><a>어떻게 틀렸을까요?</a></div>
</li>
<li>
<p><em>모두 같은 종류의 실수를 하고 있습니다.</em></p>
</li>
<li>
<h4><strong>틀린 이유를 찾아서 수정해보세요.</strong></h4>
</li>
</section>
<section>
<h3>예시 2</h3>
<li>
<strong>화면만 보면 틀렸다는 사실을 인지하기 어렵습니다.</strong>
</li>
<li>
<em>
Element탭이나 Visual Studio Code에서 소스 코드를 확인하세요.
</em>
</li>
</section>
<section>
<h3>예시 3</h3>
<li>
<div className="c1">글씨 크기를 조절하고 싶을 땐</div>
</li>
<li>
<div className="c2">요소 종류를 사용하는 것이 아니라</div>
</li>
<li>
<div className="c3">CSS를 이용해주세요.</div>
</li>
<li>
<div className="c4">요소의 의미와 맞지 않습니다.</div>
</li>
</section>
<section>
<h3>예시 4</h3>
<li className="d1">요소 사이에 간격을 주고 싶을 때에도</li>
<li className="d2">CSS를 이용해주세요.</li>
<li className="d3">태그의 존재 의의와 맞지 않습니다.</li>
<li className="d4">요소 사이의 간격을 조절할 때가 아니라 줄 바꿈을 할 때 사용해주세요.
이렇게 사용해주시면 됩니다.</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="l-style"><strong><a>위 예시를 종합적으로 섞어놓았습니다.</a></strong></li>
<div className="b-color"><strong>이 정도 되면 보기만해도 불편하실 것 같습니다.</strong></div>
<h1 className="h1-color" ><em>틀린 곳을 찾아서 수정해보세요.</em></h1>
</section>
</section>
</article>)
}
export default Page02
page03에서는 콘텐츠의 의미나 용도를 알 수있도록 alt속성을 사용하여 대체텍스트를 제공하였다.
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
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} 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} />
<p>래서 펜더가 대나무를 앞발로 잡고 혀를 내밀고 있다.</p>
</section>
</section>
</article>)
}
export default Page03
page04에서는 고칠 것 없이 구성이 순서대로 잘 짜여 있는지 확인을 해 보았다.
개인적으로는 예시2가 스크린 리더를 읽어 줄 때 순서대로 내용을 읽어 주어서 좋았다.
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
page05에서는 WAI-ARIA를 사용하여 상황에 맞게 사용해 보았다.
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
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
page06에서는 scope속성과 id,headers속성을 사용해서 표를 작성해 보았다.
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
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
page07에서는 input요소에 id를 설정하고 label요소의 for속성으로 연결해 주었다. 그리고 title 속성과 WAI-ARIA의 aria-label속성을 사용해 보았다.
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
const Page07 = () => {
return (
<article>
<h1>문제 7 : 레이블 제공</h1>
<p>사용자가 정보를 입력하는 상황에, 어떤 정보를 입력해야 하는지 정확하게 알 수 없으면 입력이 불가능합니다. 따라서 사용자 입력에 대응하는 레이블을 제공해야 합니다.<br/>
우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 레이블을 작성하세요.
</p>
<section>
<h2>예시 1</h2>
<li>{`<input>`}요소만 있으면 무엇을 입력하라는 의미인지 알 수 없습니다. 레이블을 꼭 작성해주세요.</li>
<div className="inputContainer">
<label for="id1">아이디1</label>
<input id="id1" 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