• [Tabtrap] Modal에서 focus 다루기 :: 마이구미
    HTML, CSS 2020. 5. 30. 18:21
    반응형
    이 글은 Tabtrap 이라는 테크닉을 다룬다.
    정해진 용어는 딱히 없는 것 같지만 Tabtrap 이라고도 불린다.
    크게는 모달에서 사용할 수 있고,  다른 요소의 영역에서도 충분히 활용할 수 있다.
    사용자 경험 측면에서도 향상될 수 있는 테크닉이다.

     

    웹 개발에 있어서, 모달(Modal) 여부는 대부분 존재한다.

     

     

    그렇다면, 모달의 무엇인가?

    모달은 팝업과 비교하면 쉽게 이해할 수 있다.

    모달은 어느 시점에 사용자가 특정 컨텐츠에 집중해야할 경우에 필요로한다.

    즉, 모달은 사라질 때까지 사용자는 그 영역에만 집중할 수 있어야한다.

    마치 window 객체에서 제공해주는 alert, confirm 메소드처럼 완료 처리를 하기 전까지는 아무것도 할 수 없는 것처럼말이다.

    반대로 팝업은 존재하더라도, 사용자는 다른 행위를 할 수 있다.

     

    See the Pen Modal vs Popup by leejunghyun (@mygumi) on CodePen.

     

     

     

    위 예제처럼 모달이 존재하면 모달이 사라질 때까지 모달 영역이 아닌 곳에서의 행위는 할 수 없다.

    반면 팝업은 존재하더라도, input 영역에 타이핑을 하고, 스크롤을 하고, 다른 버튼을 클릭할 수 있다.

    사용자는 모달에 집중해야하는데 다른 영역의 행위 또는 스크롤이 발생하면 집중력을 흐트릴 수 있기 때문이다.

    이와 같은 맥락으로 Tab 키도 마찬가지이다.

    위 예제에서 모달을 열고 Tab 키를 누르면 모달이 아닌 영역에서 포커스를 하는 모습을 볼 수 있다.

    이렇게 Tab 키로 인해 모달 밖에 있는 영역에 포커스가 간다면, 모달의 목적을 흐트러트릴 수 있다.

    결과적으로 Tab 키로 인한 포커스의 대상은 모달 안의 요소들로만 원할 수 있다.

     

    이를 구현하기 위해서는 크게 어려울 것이 없다.

     

    • HTMLElement 에서 제공해주는 focus()
    • HTML 에서 제공해주는 tabindex

     

    위 두가지만 이해하면 충분히 구현할 수 있다.

     

    focus() 는 특정 엘리먼트에 포커스를 할 수 있게 해주는 메소드이다.

    참고로 다른 얘기지만, 부끄럽지만 본인도 몰랐던 사실로 focus 메소드의 인자의 존재이다.

     

    element.focus(options);
    element.focus({preventScroll:true});

     

    focus 메소드의 인자의 옵션으로 preventScroll 이 존재한다. (default 값은 false 이다.)

    이 속성은 포커스가 이동했을 경우, 스크롤 이동의 여부를 나타낸다.

     

    tabindex 는 포커스를 할 수 있게 해주는 HTML 의 글로벌 속성이다. 

    tabindex 에 대해 오래된 글이지만, 어려운 내용이 아니라 쉽게 이해할 수 있다.

    관련 글을 참고해서 어떤 흐름인지 파악할 수 있다. https://mygumi.tistory.com/53

     

    구현 방식은 간단하다.

    탭을 가두는 영역 사이에 tabindex 를 부여받은 요소를 배치하면 된다.

     

    <div tabindex=0 />
    <div id="modal">
        <h2>Modal</h2>
        <input />
        <button>Yes</button>
        <button>No</button>
    </div>
    <div tabindex=0 />

     

    상단에 배치된 tabindex=0 인 div 에 포커스가 오면 내부에 존재하는 포커스가 가능한 다음 요소에 이동한다.

    그리고 하단에 배치된 tabindex=0 인 div포커스가 오면 내부에 존재하는 포커스가 가능한 첫번째 요소로 이동한다.

    구현 방식은 조금씩 달라질 수 있으나, 사실 의도 그대로 모달을 외부에서 가두면 된다.

    특별한 건 없기 때문에, 자세한 코드는 JetBrain 에서 만든 코드를 참고하는 것으로 하겠다.

    https://github.com/JetBrains/ring-ui/blob/master/components/tab-trap/tab-trap.js

     

    사실 JetBrain 코드에는 또 하나 새롭게 알게 된 것이 있어서 언급했다. (그 외에도 유용한 정보가 존재)

    JetBrain 에서 구현한 방식은 기본적으로 모달이 열리면, 포커스는 첫번째로 이동하게 된다.

    그리고 기본적으로 포커스가 모달이 아닌 상황에는 탭을 클릭 했을 경우는 모달의 마지막 요소로 포커스로 이동하게 된다.
    이러한 이유는 숙련된 사용자(advanced user) 를 위한 UX 기법으로 볼 수 있다.

    마지막 요소로 바로 포커스하여 일일이 끝까지 가기 위한 행위를 건너뜀으로써, 보다 빨리 원하는 행위를 마칠 수 있게 된다.

    이렇게 탭을 특정 영역에 가둠으로써, 다른 측면에서의 효율성도 높일 수 있게 된다.

     

    tabindex - https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex

    focus() - https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus

    반응형

    댓글

Designed by Tistory.