오늘은 웹 표준과 웹 접근성에 관한 연습문제를 풀어보았다.
아무래도 HTML을 처음 배울 때
" 내가 어떤 요소가 있는 줄 알고 갖다 쓰지 🤨? " 라는 생각을 했었는데
이번 챕터에서 많이 배워가는 거 같아서 정말 좋았다.
더불어 과거 과제를 했었을 때 <br /> 과 <div> 랑 <span> 만을 고집했었는데 그러면 안되겠구나 싶었다.
먼저 과제를 clone 해 주고, npm run start 로 웹을 켜준다.
( 웹이 켜지지 않는다면 http://localhost:3000/ 로 직접 들어가 줘도 좋다 : ) )
다음과 같이 문제와 문제 힌트가 나온다.
* HTML 요소들은 전 블로그에서도 다뤘었고,,, 하나하나 다 무슨 요소인지 나열하면 너무 길어질 거 같아서 생략하겠다! *
HTML 요소들을 찾아보고 싶다면 아래 링크 (mdn web docs) 를 참고하자.
https://developer.mozilla.org/ko/docs/Web/HTML/Element
HTML 요소 참고서 - HTML: Hypertext Markup Language | MDN
메타데이터는 스타일, 스크립트, 각종 소프트웨어(검색 엔진 (en-US), 브라우저 등)의 탐색 및 렌더링을 도와줄 데이터 등 페이지에 대한 정보를 가집니다. 스타일과 스크립트 메타데이터는 페이
developer.mozilla.org
문제 1. <div> 와 <span> 으로 남발된 HTML을 시맨틱한 요소들로 바꾸시오~
힌트 : <header> , <nav>, <main>, <aside>, <footer>, <section>, <article>, <hgroup>, <p>
수정 전 모습을 보면, 내가 옛날에 뭣모르고 했던 방식이랑 너무 유사하다 ㅎㅎ...
주구 장창 <div> 에 그저 className으로 구분하는 방식!! 이 방식은 시맨틱하지 못하다...!!!
className 기준으로 각 다른 HTML 요소들로 대체 해 주었다.
// Page1 수정 후
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
각 요소들을 시맨틱하게만 바꿔준 거라 화면에 어떤 변화가 일어나지 않아야 한다.
< 주의점 >
className이 title1인 것.. 이전에 배웠던 <title> 요소로 바꿔주고 싶지 않은가???
하지만 <title> 요소로 바꿔주게 되면 제목이 나타나지 않는다..!
<title> 요소는 <header> 요소의 자식이어야 함을 기억하자!
문제 2. 다음 예시에서 어떤 부분이 문법이 틀렸는지 찾아내 보아라~
힌트 : 다음과 같은 행동을 하면 안됨.
- 인라인 요소 안에 블록 요소 넣기
- <b>, <i> 요소 사용하기
- <hgroup> 마구잡이로 사용하기
- <br /> 연속으로 사용하기
- 인라인 스타일링 사용하기
const Page02 = () => {
return (
<article>
<h1>문제 2 : 자주 틀리는 마크업</h1>
<p>자주 틀리는 HTML 요소의 사용법들을 고쳐봅시다. 웹 표준을 저해하는 사용법이지만, 화면 상으로는 큰 문제가 없기 때문에 의외로 자주 발견할 수 있는 예시들 이기도 합니다.<br />
우측 문제 가이드와 유어클래스 콘텐츠를 참고하여 웹 표준에 맞는 마크업으로 바꾸세요.</p>
<li>아래 자주 틀리는 마크업 예시들을 웹 표준에 맞게 수정하세요.</li>
<li>예시 외에도 애플리케이션 내에 틀리게 사용한 마크업이 있습니다. 찾아서 수정해보세요.</li>
<section>
<h2>틀린 마크업 예시</h2>
<section>
<h3>예시 1</h3>
<li>
<div>
<label>어떻게 틀렸을까요?</label>
</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="c1">요소 종류를 사용하는 것이 아니라</div>
</li>
<li>
<div className="c1">CSS를 이용해주세요.</div>
</li>
<li>
<div className="c1">요소의 의미와 맞지 않습니다.</div>
</li>
</section>
<section>
<h3>예시 4</h3>
<li className="d1">요소 사이에 간격을 주고 싶을 때에도</li>
<li className="d1">CSS를 이용해주세요.</li>
<li className="d1">태그의 존재 의의와 맞지 않습니다.</li>
<li className="d1">요소 사이의 간격을 조절할 때가 아니라 줄 바꿈을 할 때 사용해주세요.<br />
이렇게 사용해주시면 됩니다.</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>
<label>
<li className="l-style"><strong><a>위 예시를 종합적으로 섞어놓았습니다.</a></strong></li>
<div className="b-color">이 정도 되면 보기만해도 불편하실 것 같습니다.</div>
<h1 className="h1-color" ><em>틀린 곳을 찾아서 수정해보세요.</em></h1>
</label>
</section>
</section>
</article>)
}
export default Page02
-> 각 className으로 지정 해 준 곳은 당연하게도 CSS 가서 따로 작업을 해줘야 하는 부분이다.
-> 인라인 요소 안에 블럭요소를 넣으면 안된다..! <div> 요소가 안에 들어가 있을 때 부터 눈치를 채야 함.. ㅋㅋ
다른 요소들은 하나하나 찾아봤었는데.. 의외로 요소의 기능만 나오지, 블록요소인지 인라인 요소인지 알기 어려웠다.
개인적으로 다음 링크를 참고했다.
https://jsunnylab.tistory.com/19
블록 요소와 인라인요소
1) 블록 레벨 요소(block-level elements) 한 개의 독립된 덩어리라는 의미. 일반적으로 그 앞 뒤로는 줄바꾸기가 됨 address blockquote center dir div dl fieldset form h1~h6 hr isindex menu noframes ol p pre table ul *범용 블
jsunnylab.tistory.com
-> <b> 나 <i> 요소는 디자인 표현을 기준으로 만들어진 요소라 시맨틱 하지 않다.
각 <strong>, <em> 요소로 바꿔 줄 수 있다.
-> h 태그는 단순 디자인을 위한 요소가 아닌, 상하 관계를 나타내는 요소이다.!
저렇게 사용하면,,, 요소간 관계가 꼬일 수 있다.. CSS를 이용해서 글자 크기를 조정해 주는 방식으로 하자.
-> <br /> 은 텍스트 흐름에 줄바꿈을 위해 사용하는 요소다.
CSS 속성으로 여백을 주는 방식으로 하자.
문제 3. alt 속성을 사용해 대체 텍스트를 작성해 보아라!
힌트 :
- 배경 같이 정보를 인식할 필요가 없는 경우에는 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} 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
->Screen Reader 프로그램으로 이미지를 눌러보면 alt 속성의 내용을 읽어줌!
간단히 alt 속성을 사용하여 이미지 대체 텍스트 생성.
예시 5에서는 이미 <p> 로 이미지 내용을 설명 해 주고 있으므로 alt를 사용하지 않아도 된다.
문제 4. 콘텐츠를 선형 구조로 배치 해 보자!
힌트 :
- 콘텐츠는 논리적인 순서로 제공해야 함.
- 글은 제목, 내용 순서로 제공돼야 함.
- 탭에 해당하는 내용이 있는 경우, 탭 제목 다음에 탭 내용이 오도록 마크업을 구성.
- 스크린 리더는 마크업 순서대로 내용을 읽어준다는 것을 고려.
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
-> 스크린 리더로 들으면서 힌트 토대로 논리적인 HTML 구조를 파악해 보기.
문제 5. WAI-ARIA 를 사용해 보자!
힌트 :
역할 (role) 속성과 속성(property) 값을 주어 설명 할 수 있다.
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 className="button">요소는 h3</h3>
</li>
<h3>예시 1 - 문제</h3>
<li>아래 예시는 문제 4에서 보았던 탭 컴포넌트입니다. 각 컴포넌트에 맞는 역할을 WAI-ARIA로 작성해보세요.</li>
<li>WAI-ARIA 작성 전후로 개별 요소를 지정했을 때 스크린 리더가 읽어주는 내용의 차이를 확인해보세요.</li>
<div class="tabContainer">
<div 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
-> HTML 요소 종류와 역할이 매칭이 안될 때, 어떤 역할인지 명시할 때 사용하는 role 속성과,
요소에 대한 정보를 얻을 수 없을 때 ( 이미지 요소 등 ) 속성으로 라벨을 붙여주는 aria-label 속성을 이용함.
문제 6. 표를 들으면서도 파악할 수 있도록 표의 구조를 잘 짜보자!
힌트 :
- 테이블 요소 안에 <caption> 요소를 사용해서 표에 제목을 제공.
- 표의 셀은 제목 셀과 데이터 셀이 구분되도록 구성해야 함.
- 제목 셀은 <th>, 데이터 셀은 <td> 를 사용.
- 표의 구조가 복잡할 경우, 최대한 간소화하거나 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>
<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
-> 각 scope와 id,header 속성을 이용해서 같은 표 2개를 만들어 주었다.
방식의 차이는 다음과 같다.
< scope > 속성을 사용한 표
<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>
< id >, <headers > 를 사용한
<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>
문제 7. 레이블을 짜보자!
힌트 :
- <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">
<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