dialog ; modal popup, 웹접근성

2022. 3. 28. 18:13WEB/jQuery

 

웹접근성을 준수한 모달 레이어 창을 만들어 봤다. 특이점은 모달 레이어 창이 열린 상태에서 포커스 이동을 요소를 추가해서 제어했다. esc 키를 누르면 모달 에이어 창이 닫힌다. 요소를 추가 해서 포커스를 제어 하는 것이 좋은 작동인지는 잘 모르겠다. 아래 참고 사이트를 보고 좀더 보완해야겠다.

<!DOCTYPE html>
<html lang="ko-KR">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>modal popUp</title>
    <style>
        html, body {font-size:62.5%;}
        *, *::before, *::after {box-sizing:border-box; margin:0; padding:0;}
        ul, ol {list-style:none;}
        button {border:0; background:inherit; cursor:pointer;}
        .offscreen {overflow:hidden; position:absolute; width:1px; height:1px; margin:-1px; clip-path:polygon(0 0, 0 0, 0 0);}
        .has_modal {overflow:hidden;}

        header {width:100%; padding:2rem 0; background:orange; font-size:2rem; font-weight:bold; text-align:center;}

        main {max-width:100rem; margin:10rem auto 0;}

        h1 {font-size:10rem;}
        .dummy {margin-top:2rem; font-size:5rem;}

        button {margin-top:2rem; padding:1rem; background:greenyellow; font-size:2rem; border:1px solid #999; border-radius:1rem;}
        button:focus {outline:2px dotted red}
        [class*=close] {margin:0;}

        .modal-layer {display:none; position:fixed; top:0; right:0; bottom:0; left:0; z-index:100;}
        .modal-layer.active {display:block;}
        .modal-layer .modal-dim {position:absolute; top:0; right:0; bottom:0; left:0; background:rgba(0, 0, 0, 0.5);}
        .modal-layer .modal {display:flex; position:absolute; top:50%; left:50%; padding:2rem; background:rgba(255, 255, 255, 1); transform:translate(-50%, -50%); flex-direction:column;}
        .modal-layer .modal:focus {outline:2px dotted red;}
        .modal-layer .modal h2 {font-size:2rem;}
        .modal-layer .modal label {display:flex; margin-top:3rem; padding:0.5rem 0; font-size:2rem; align-items:center;}
        .modal-layer .modal label + label {margin-top:1.5rem;}
        .modal-layer .modal label input {height:3rem; margin-left:0.5rem; padding:0.5rem; border:1px solid #ddd;}
        .modal-layer .modal .btn_close-modal {position:absolute; top:1rem; right:1rem; padding:1.5rem; background:orangered;}
        .modal-layer .modal .btn_close-modal .ico_close {display:flex; overflow:hidden; position:absolute; top:50%; left:50%; width:2rem; height:2rem; padding-top:1.2rem; color:#fff; font-size:3rem; line-height:0; transform:translate(-50%, -50%); justify-content:center; align-items:center;}
        
    </style>
    <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
</head>
<body>
    <header>header</header>
    <main>
        <h1>modal pop</h1>
        <p class="dummy">Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus dignissimos hic non, vero praesentium asperiores excepturi modi distinctio nostrum voluptates officia et sint, repellendus vitae exercitationem eos nobis eum deserunt!</p>

        <button type="button" aria-controls="openModal1" class="btn_open-modal">openModal1</button>

        <p class="dummy">Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus dignissimos hic non, vero praesentium asperiores excepturi modi distinctio nostrum voluptates officia et sint, repellendus vitae exercitationem eos nobis eum deserunt!</p>
        <p class="dummy">Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus dignissimos hic non, vero praesentium asperiores excepturi modi distinctio nostrum voluptates officia et sint, repellendus vitae exercitationem eos nobis eum deserunt!</p>

        <button type="button" aria-controls="openModal2" class="btn_open-modal">openModal2</button>

        <p class="dummy">Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus dignissimos hic non, vero praesentium asperiores excepturi modi distinctio nostrum voluptates officia et sint, repellendus vitae exercitationem eos nobis eum deserunt!</p>
    </main>
    <div id="openModal1" class="modal-layer">
        <div class="modal-dim"></div>
        <div role="dialog" aria-modal="true" aria-labelledby="modal-label1" class="modal">
            <h2 id="modal-label1">dialog label1</h2>
            <label><span>이름</span> <input type="text" placeholder="한글로 적으세요"></label>
            <label><span>나이</span> <input type="text" placeholder="숫자로 적으세요"></label>
            <button type="button" class="btn_close-modal"><span class="offscreen">팝업닫기</span><span class="ico_close">&#x2df;</span></button>
        </div>
    </div>
    <div id="openModal2" class="modal-layer">
        <div class="modal-dim"></div>
        <div role="dialog" aria-modal="true" aria-labelledby="modal-label2" class="modal">
            <h2 id="modal-label2">dialog label2</h2>
            <label><span>이름</span> <input type="text" placeholder="한글로 적으세요"></label>
            <label><span>나이</span> <input type="text" placeholder="숫자로 적으세요"></label>
            <button type="button" class="btn_close-modal"><span class="offscreen">팝업닫기</span><span class="ico_close">&#x2df;</span></button>
        </div>
    </div>
    
</body>
<script>
    $(function(){

        var modalDialog = function(){

            var openModalBtn = $('.btn_open-modal'),
                modalLayer = $('.modal-layer');
            
            modalLayer.attr('aria-hidden', true);
            // 포커스 요소 추가
            modalLayer.prepend($('<div data-focus="focusStart" tabindex="0"></div>'));
            modalLayer.find('[role=dialog]').append($('<div data-focus="focusEnd" tabindex="0"></div>'));

            openModalBtn.on('click', function(){
                var $this = $(this),
                    openModal = $('#' + $this.attr('aria-controls')),
                    modalDim = openModal.find('.modal-dim'),
                    modal = openModal.find('.modal'),
                    closeModal = openModal.find('.btn_close-modal');

                console.log(openModal.attr('id'));

                $('body').addClass('has_modal');
                openModal.addClass('active').attr('aria-hidden', false);

                // 포커스 이동 함수
                function modalFocus(modalId) {
                    // 팝업 버튼 클릭하면 dialog에 포커스
                    $(modalId).find('[role=dialog]').attr('tabindex', 0).focus(); 
                    
                    // 닫기 버튼에서 tab을 눌렀을 때 role=dialog로 포커스 이동
                    $(modalId).find('[data-focus=focusEnd]').on('focus', function(){
                        $(modalId).find('[role=dialog]').focus();
                    });

                    // role=dialog에서 shift + tab을 눌렀을 때 닫기 버튼으로 포커스 이동
                    $(modalId).find('[data-focus=focusStart]').on('focus', function(){
                        $(modalId).find('.btn_close-modal').focus();
                    });
                }
                modalFocus(openModal);

                // 닫기 버튼 함수
                function modlaClose() {
                    $('body').removeClass('has_modal');
                    openModal.removeClass('active').removeAttr('aria-hidden', true);
                    $this.focus(); // 팝업 닫으면 열었던 버튼으로 포커스 이동
                    $(document).off('keyup.closeModal')
                }

                // 닫기 버튼 클릭 시 팝업차 닫기
                closeModal.on('click', modlaClose)

                // modalDim을 클릭해도 팝업창 닫기
                modalDim.on('click', function(e){
                    if(e.target === e.currentTarget){
                        modlaClose();
                    }
                });

                // 팝업창이 열렸을 때 esc 키를 누르면 닫기
                $(document).on('keyup.closeModal', function(e){
                    var keycode = e.keycode || e.which;
                    if(keycode == 27 && openModal.hasClass('active')){
                        modlaClose();
                    }
                })
            });
        }
        modalDialog();
    })
</script>
</html>

 


https://w3c.github.io/aria-practices/examples/dialog-modal/dialog.html

 

Modal Dialog Example | WAI-ARIA Authoring Practices 1.2

Address Added The address you provided has been added to your list of delivery addresses. It is ready for immediate use. If you wish to remove it, you can do so from your profile. OK

w3c.github.io

https://selosele.github.io/2020/01/29/layer-popup/

 

레이어팝업에 웹 접근성을 불어넣다

웹 접근성이 충분히 보장된 레이어팝업

selosele.github.io

 

*위 사이트를 참고하여 공부했습니다.