접근성이 있는 맞춤형 오디오 플레이어 구축

This article was originally posted in my personal blog.



a custom audio player 을 만든 것은 이번이 처음이 아닙니다.

내 사랑스러운 디자이너의 요구를 충족시키기 위해 맞춤형 오디오 플레이어를 만들어야 합니다. 사용자 지정 오디오 플레이어를 만드는 방법을 배우고HTML5 Audio attributes 더 많은 자습서를 본 후 대부분의 자습서에서 접근성에 대해 언급하지 않았습니다.

이번에는 오디오 플레이어에 React를 사용하지만 바닐라 JavaScript 버전에 대한 마지막 사용자 정의 오디오 플레이어를 항상 볼 수 있습니다(당시에는 접근성에 대해 크게 신경 쓰지 않았지만).

저는 접근성 전문가가 아닙니다. 여러분의 생각을 자유롭게 알려주세요!


플레이어의 마크업



먼저 오디오 플레이어의 외부 컨테이너에는 role="region"aria-label="Audio Player" 가 있어야 합니다. 역할은 스크린 리더에게 이것을 div 어떤 것을 나타내고 aria-label 에서 스크린 리더는 그것이 오디오 플레이어임을 알립니다.

외부 용기



<div className="c-audio" aria-label="Audio Player" role="region">
  // ...
</div>

재생 버튼



내부의 재생 버튼은 다음과 같습니다.

<button
  title={!isPlay || isPlay === null ? 'Play' : 'Pause'}
  className={
    !isPlay || isPlay === null
      ? 'c-audio u-btn l-play l-play__play'
      : 'c-audio u-btn l-play l-play__pause'
  }
  aria-controls="audio1"
  onClick={this.controlAudio}
  aria-label={!isPlay || isPlay === null ? 'Play' : 'Pause'}
/>
aria-controls는 하단에 있는 audio 태그의 id로 연결됩니다.

슬라이더



오디오 컨트롤의 경우 실제로 범위(예: <audio id="audio1" ... > )를 사용하고 싶지만 모든 브라우저에서 동일한 스타일을 유지하기가 어렵기 때문에 aria-label 와 함께 <input type="range" ...> , 아리아 레이블을 사용하기로 결정했습니다. 또한 키보드가 이 요소에 집중할 수 있도록 여기에서 div를 사용했습니다.

이 슬라이더에서 사용자는 다음을 수행할 수 있습니다.
  • 마우스 또는 키보드를 사용하여 오디오의 현재 시간 변경
  • 슬라이더에 초점을 맞출 수 있음
  • 마우스를 사용하여 위치를 변경할 수 있음
  • 키보드에서 왼쪽 또는 오른쪽 키를 사용하여 위치를 변경할 수 있습니다.

  • <div
    className="c-audio__slider"
    onKeyDown={this.onKeyDown}
    onClick={this.onClick}
    tabIndex="0"
    aria-valuetext="seek audio bar"
    aria-valuemax="100"
    aria-valuemin="0"
    aria-valuenow={Math.round(percentage)}
    role="slider"
    ref={this.audioSeekBar}
    >
    

    슬라이더를 재발명하려면 많은 작업이 필요하지만 그만한 가치가 있습니다. 이러한 구현 후에는 접근성과 함께 다양한 스타일의 슬라이더를 만들 수 있습니다! 예를 들어 WAI-ARIA Authoring Practices 에서 여기를 보십시오.

    슬라이더 조작



    클릭 또는 키 다운을 감지할 때 슬라이더의 비율을 변경하는 방법은 무엇입니까? svgtabIndex="0" 기능을 사용할 수 있습니다. 클릭 기능의 경우 클릭 위치의 백분율을 계산합니다. (참고: onClickonKeyDown 값을 지원하지 않으므로 IE11용입니다)

    onClick(e) {
        const seekBar = this.audioSeekBar.current;
        const audio = this.audioFile.current;
    
        const pos =
        (e.pageX -
            (seekBar.getBoundingClientRect().x ||
            seekBar.getBoundingClientRect().left)) /
            seekBar.getClientRects()[0].width;
    
            this.setState({
                percentage: pos * 100
            });
    
            audio.currentTime = audio.duration * pos;
    }
    

    키보드 버전의 경우 다른 키에 따라 백분율을 추가하거나 줄입니다.

    슬라이더용 키 바인딩:
  • 상단: ~ 100(최대)
  • 하단: 0(분)까지
  • 왼쪽: -1단계
  • 오른쪽: +1단계
  • 상단: +10단계
  • 하단: -10단계

  • onKeyDown(e) {
        // when user focus in audio slider and 
        // clicks keys inside key list, will change current time of audio
        const audio = this.audioFile.current;
        const isLeft = 37;
        const isRight = 39;
        const isTop = 38;
        const isBottom = 40;
        const isHome = 36;
        const isEnd = 35;
        const keyList = [isLeft,isRight,isTop,isBottom,isHome,isEnd];
    
        if (keyList.indexOf(e.keyCode) >= 0) {
            let percentage;
            switch(e.keyCode) {
                case isLeft:
                percentage = parseFloat(this.state.percentage) - 1
                break;
                case isRight:
                percentage = parseFloat(this.state.percentage) + 1
                break;
                case isTop:
                percentage = parseFloat(this.state.percentage) + 10
                break;
                case isBottom:
                percentage = parseFloat(this.state.percentage) - 10
                break;
                case isHome:
                percentage = 0
                break;
                case isEnd:
                percentage = 99.9 // 100 would trigger onEnd, so only 99.9
                break;
                default:
                break;
            }
    
            // add boundary for percentage, cannot be bigger than 100 or smaller than zero
            if(percentage > 100) {
                percentage = 100
            } else if(percentage < 0) {
                percentage = 0
            }
    
            this.setState({
                percentage
            });
    
            audio.currentTime = audio.duration * (percentage / 100);
        }
    }
    

    오디오 태그



    여기서 가장 중요한 것은 오디오 태그입니다. 오디오 태그에서 슬라이더를 제어하려면 seekBar.getBoundingClientRect().leftx/y를 사용해야 합니다. 오디오가 실행 중일 때 onTimeUpdate의 함수를 호출하고 슬라이더를 업데이트합니다.

    오디오가 끝나면 오디오의 현재 시간이 0으로 변경되고 슬라이더의 백분율도 0으로 변경됩니다. onEnded 의 경우 자막이 있는 오디오 또는 비디오용으로 여기에 자막이 없으므로 지금 바로 건너뜁니다.

    <audio
      className="c-audio__sound"
      id="audio1"
      src={path}
      onTimeUpdate={this.getCurrDuration}
      onEnded={() => {
        this.audioFile.current.currentTime = 0;
        this.setState({
          isPlay: false,
          currentTime: 0,
          percentage: 0
        });
      }}
      ref={this.audioFile}
    >
      <track kind="captions" />
    </audio>
    

    초점 스타일



    또한 재생 버튼과 슬라이더에 대한 사용자 정의 초점 스타일을 만드는 것을 잊지 마십시오!

    .l-play:focus {
      outline: none;
      box-shadow: 1px 1px 1px 0px rgba(25, 25, 25, 0.2);
    }
    

    결과



    다음에서 내 결과를 보거나 click here to view on Codepen !



    나에게 전화를 끊거나 당신의 생각을 알려주는 것을 환영합니다! :)


    더 읽기


  • A Sliding Nightmare: Understanding the Range Input
  • Dev.Opera - A More Accessible HTML5 video Player
  • WAI-ARIA Authoring Practices
  • 좋은 웹페이지 즐겨찾기