audio 태그 자동 재생 해결 방안 및 크로스 브라우징

    반응형

    audio 자동재생

     

     

    청첩장을 만드는 도중 배경음악을 위한 <audio /> 태그 사용에 대한 문제가 발생해서 이 문제를 어떻게 해결했는지에 대한 정리 글을 남기며 다시 한번 공부하려고 한다.

     

    문제


    청첩장을 만드는 과정에서 청첩장이 렌더링 되었을 때 배경음악이 자동으로 재생될 수 있도록 만들고 싶었다. 당연하게도 <audio />에는 자동 재생을 지원하는 autoplay 속성이 있어 이를 사용하면 될 줄 알았다. 하지만 대부분의 최신 브라우저들이 더 나은 사용자 경험과 보안정책상 사용자의 인터랙션이 없는 상태에서는 자동 재생을 허용하지 않는다는 것을 알게 되었다. 

     

    해결


    가장 첫번 째로 생각한 방법은 스크롤 이벤트가 발생하면 자동으로 재생될 수 있도록 하는 것이었다. 그렇게 작성한 코드는 아래와 같다.

     

    import { useEffect, useRef, useState } from 'react'
    
    const Bgm = () => {
      const [playMusic, setPlayMusic] = useState<Boolean>(false)
    
      const ref = useRef<HTMLAudioElement>(null)
    
      const playBgm = () => {
        setPlayMusic(true)
        ref.current?.play()
      }
    
      const stopBgm = () => {
        setPlayMusic(false)
        ref.current?.pause()
      }
    
      useEffect(() => {
        const handleScroll = () => {
          if (ref.current && ref.current.paused) {
            ref.current.play()
            setPlayMusic(true)
    
            window.removeEventListener('scroll', handleScroll)
          }
        }
    
        window.addEventListener('scroll', handleScroll)
      }, [])
    
      return (
        <div className="bgm" onClick={playMusic ? stopBgm : playBgm}>
          <audio
            ref={ref}
            loop={true}
            autoPlay={true}
            src="./assets/background.mp3"
          />
          {playMusic ? (
            <StopMusic className="bgm__icon" />
          ) : (
            <PlayMusic className="bgm__icon" />
          )}
        </div>
      )
    }
    
    export default Bgm

     

    맨 처음 스크롤 이벤트가 발생하면 ref 로 지정해놓은 audio 태그에 play() 를 실행하도록 useEffect를 사용해 작성했는데 여러 문제가 있었다. 하나는 Chrome 에서는 동작하는데 Safari 에서는 동작하지 않는 문제가 있었고, 바로 스크롤을 내리면 사용자 인터랙션이 필요하다는 오류가 발생했다. 또한 카카오톡 공유를 통해 청첩장을 열게 되면 playMusic 상태 값과 관계없이 autoplay가 동작하면서 자동적으로 배경음악이 재생되는 문제가 발생했다.

     

    터치 혹은 클릭 이벤트와 같이 확실한 사용자의 인터랙션이 있어야 배경음악을 재생할 수 있었다. 모바일 청첩장이라는 확실한 웹페이지의 기능이 있기 때문에 사용자가 화면을 클릭할 수 있도록 유도하기 위해 많은 고민을 했는데 마침 여러 청첩장들을 둘러보던 중 좋은 아이디어를 발견해 같은 기능을 구현했다. 

     

    import { useEffect, useRef, useState } from 'react'
    
    const Bgm = () => {
      const [playMusic, setPlayMusic] = useState<Boolean>(false)
    
      const ref = useRef<HTMLAudioElement>(null)
    
      const playBgm = () => {
        setPlayMusic(true)
        ref.current?.play()
      }
    
      const stopBgm = () => {
        setPlayMusic(false)
        ref.current?.pause()
      }
    
      useEffect(() => {
        const handleScroll = () => {
          if (ref.current && ref.current.paused) {
            ref.current.play()
            setPlayMusic(true)
    
            window.removeEventListener('scroll', handleScroll)
            window.removeEventListener('touchstart', handleScroll)
            window.removeEventListener('click', handleScroll)
          }
        }
    
        window.addEventListener('scroll', handleScroll)
        window.addEventListener('touchstart', handleScroll)
        window.addEventListener('click', handleScroll)
      }, [])
    
      return (
        <div className="bgm" onClick={playMusic ? stopBgm : playBgm}>
          <audio ref={ref} loop={true} autoPlay={playMusic ? true : false}>
            <source src="./assets/bgm.webm" type="audio/webm" />
          </audio>
          {playMusic ? (
            <StopMusic className="bgm__icon" />
          ) : (
            <PlayMusic className="bgm__icon" />
          )}
        </div>
      )
    }
    
    export default Bgm

     

    수정한 코드는 scroll, touchstart, click 이벤트를 모두 등록하고 어떠한 인터랙션이든 발생하면 배경음악을 재생할 수 있도록 했다. 모바일에서는 주로 touchstart 이벤트, 데스크탑에서는 클릭 이벤트를 발생하도록 유도했다. 그리고 카카오톡 공유하기를 통해 배포된 페이지에서 자동 재생되던 문제를 autoplay의 값을 playMusic에 따라 다르게 설정되도록 하여 배경음악을 사파리, 크롬, 카카오톡 공유하기 웹페이지에서 모두 원하던 대로 동작하는 것을 확인할 수 있었다.

     

    같은 기능을 구현하더라도 많은 브라우저에서 서로 다르게 동작하는 것을 크게 느낄 수 있었고, 크로스 브라우징에 대한 중요성을 느낄 수 있었다. 주로 크롬가 편해 크롬 브라우저에만 맞추다 보니 크로스 브라우징에 대한 중요성을 놓칠 뻔하였다. 하지만 이번 배경음악을 넣은 기능으로 다시 한번 크로스 브라우징에 대한 중요성을 깨달았다.

    반응형

    댓글