#작성중....
#기존 코드 문제점
라디오버튼의 디자인 변경을 위해서 <input type=“radio”> 요소는 CSS의 opacity 속성으로 화면에서 보이지 않도록 처리한후 배경이미지를 활용하여 원하는 라디오버튼의 디자인을 적용하는 방법이 있고, 또 하나는 <input> 요소을 사용하지 않고 <span>이나 <div> 요소, 또는 <ul>, <li> 요소를 사용하여 마크업하고 이를 CSS로 디자인 하는 경우를 들 수 있다.
이렇게 제작된 코드는 기본 라디오버튼과 동일하게 키보드 인터랙션이 보장되어야 한다.
예를 들면, 라디오 버튼임을 인식할 수 있어야 하고, 선택과 해제된 상태를 구분할 수 있어야 한다. 또한 키보드의 스페이스바로 선택이 가능해야 하지만 이런 부분을 간과하고 제작하는 경우가 많다.
role=“radiogroup”은 그룹이므로 그룹의 제목을 함께 제공해야 한다. 주로 제목으로 마크업되어 있는 헤딩 요소에 id 값을 지정하여, aria-labelledby 속성으로 연결한다. 이때 스크린리더로 들어보면 헤딩 텍스트를 그룹의 제목으로 인식하는 것을 알수 있다.
#WAI-ARIA를 사용해야 하는 이유
WAI-ARIA를 사용하면 키보드 사용 보장도 가능하고 스크린리더 사용자도 사용할 수 있는 디자인된 라디오버튼을 사용할 수 있다.
라디오버튼은 일반적으로 YES or NO와 같이 두 개 이상이 항상 존재한다.
라디오버튼을 role=“radiogroup” 또는 role=“group”을 사용하여 그룹화하고 aria-label 또는 aria-labelledby 속성을 사용하여 그룹의 제목을 스크린리더 사용자들에게 알려줄 수 있다. 이때 radio 역할이 스크린리더 사용자에게 라디오버튼임을 인식할 수 있도록 해준다.
또한, 스크린리더가 라디오버튼이 현재 선택되어 있는지, 선택되지 않았는지의 상태정보를 인식할 수 있게 aria-checked 속성을 사용할 수 있다.
#WAI-ARIA 전체적인 그림과 설명
라디오버튼 그룹을 마크업할 때는 스크린리더에서 전체의 목록 개수를 읽어줄 수 있도록 <ul>, <li> 요소로 제작하는 것을 권장한다.
전체를 감싸고 있는 컨테이너인 <ul> 요소에 role=“radiogroup”을 지정하고. 각 <li> 요소에는 각각
role=“radio”를 삽입 하여 라디오 버튼의 역할을 정의한다. 단, role=“radiogroup”은 하위 요소가 role=“radio”일 경우에 사용하며, <input type=“radio”> 요소를 라디오 그룹으로 묶을 경우는 role=“group”을 사용한다.
요소 |
역할 |
속성/상태 |
설명 |
<ul> |
radiogroup |
|
라디오버튼 그룹의 역할 정의 |
|
|
aria-labelledby="" |
라디오버튼 그룹의 제목으로 주로 헤딩의 id와 연결. (연결할 수 있는 제목이 없을 경우 aria-label 속성을 사용하여 제목 제공) |
<li> |
radio |
|
라디오버튼 역할 정의 |
|
|
aria-checked="true | false" |
라디오버튼이 선택되어 있는지, 선택되지 않았는지 상태 정보 제공 |
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> radio button </title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
<h1 id="rg1_label">WAI-ARIA Group</h1>
<ul role="radiogroup" aria-labelledby="rg1_label" class="radiogroup" id="rg1">
<li id="r1" aria-checked="true" role="radio" tabindex="0">tab 1</li>
<li id="r2" aria-checked="false" role="radio" tabindex="-1">dialog 2</li>
<li id="r3" aria-checked="false" role="radio" tabindex="-1">carousel 3</li>
</ul>
<script>
// role="radio" 를 갖고 있는 <li> 요소와 aria-checked="true" 인 것을 참조
function radioGroup(id){
this.$buttons = this.$id.find( 'li' ).filter( '[role=radio]' );
this.$checked = this.$buttons.filter( '[aria-checked=true]' );
}
radioGroup.prototype.selectButton = function( $id ){
//버튼이 선택이 되면 aria-checked="true"가 되고, tabindex="0"을 삽입
//선택되지 않은 라디오버튼은 tabindex="-1"로 변경
if( this.checkButton == true ){
this.$checked.attr( 'aria-checked', 'false' );
$id.attr( 'aria-checked', 'true' );
if( this.$checked.length == 0 ){
this.$buttons.first().attr( 'tabindex', '-1' );
this.$buttons.last().attr( 'tabindex', '-1' );
} else {
this.$checked.attr( 'tabindex', '-1' );
}
$id.attr( 'tabindex', '0' );
this.$checked = $id;
}
};
radioGroup.prototype.handleKeyDown = function( e, $id ){
if( e.altkey ){
return true;
}
// 위쪽 방향키와 왼쪽 방향키를 누르면 이전 라디오버튼으로 이동하고
// 처음 라디오 버튼일 경우 마지막으로 이동한다.
switch( e.keyCode ){
case this.keys.left:
case this.keys.up:
{
var $prev = $id.prev();
if( e.shiftKey ){
$prev = this.$buttons.last();
}
if( e.ctrlKey ){
this.checkButton = false;
}
$prev[0].focus();
e.stopPropagation();
return false;
}
// 아래쪽 방향키와 오른쪽 방향키를 누르면 다음 라디오 버튼으로 이동하고
// 마지막 라디오 버튼일 경우 처음으로 이동한다.
case this.keys.right:
case this.keys.down:
{
var $next = $id.next();
if( e.shiftKey ){
return true;
}
if( $id.index() == this.$buttons.length - 1 ){
$next = this.$buttons.first();
}
if( e.ctrlKey ){
this.checkButton = false;
}
$next[0].focus();
e.stopPropagation();
return false;
}
}
return true;
};
</script>
</body>
</html>
댓글