Memecahkan masalah membuat jendela modal dapat diakses oleh penyandang disabilitas

Halo!



Pada artikel ini saya ingin memberi tahu Anda cara menerapkan modal yang dapat diakses tanpa menggunakan atribut "aria-modal" .



Sedikit teori!



"Aria-modal" adalah atribut yang digunakan untuk memberi tahu teknologi pendukung (seperti pembaca layar) bahwa konten web di bawah dialog saat ini tidak dapat dioperasikan (inert). Dengan kata lain, tidak ada elemen di bawah modal yang harus menerima fokus pada klik, navigasi TAB / SHIFT + TAB, atau gesek pada perangkat sensor.



Tapi mengapa kita tidak bisa menggunakan "aria-modal" untuk jendela modal?



Ada beberapa alasan:



  • hanya saja tidak didukung oleh pembaca layar
  • diabaikan oleh kelas semu ": before /: after"


Mari kita lanjutkan ke implementasinya.



Penerapan



Untuk memulai pengembangan, kita perlu memilih properti yang harus dimiliki jendela modal yang tersedia :



  • semua elemen interaktif, di luar jendela modal, harus diblokir untuk manipulasi pengguna: klik, fokus, dan seterusnya ...
  • navigasi harus tersedia hanya melalui komponen sistem browser dan melalui konten modal itu sendiri (semua konten di luar jendela modal harus diabaikan)


Kosong



Kami akan menggunakan blank agar tidak membuang waktu pada deskripsi langkah demi langkah untuk membuat jendela modal.



HTML:



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>
        <button type="button" id="infoBtn" class="btn"> Standart button </button>
        <button type="button" id="openBtn"> Open modal window</button>
        <div role="button" tabindex="0" id="infoBtn" class="btn"> Custom button </button>
    </div>
    <div>
        Lorem, ipsum dolor sit amet consectetur adipisicing elit. Deserunt maxime tenetur sint porro tempore aperiam! Eaque tempore repudiandae culpa omnis placeat, fugit nostrum quisquam in ipsa odit accusamus illum velit?
    </div>


    <div id="modalWindow" class="modal">
        <div>
            <button type="button" id="closeBtn" class="btn-close">Close</button>
            <h2>Modal window</h2>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita, doloribus.</p>
        </div>
    </div>
</body>
</html>


Gaya:



    .modal {
        position: fixed;
        font-family: Arial, Helvetica, sans-serif;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        background: rgba(0,0,0,0.8);
        z-index: 99999;
        transition: opacity 400ms ease-in;
        display: none;
        pointer-events: none;
    }
    
    .active{
        display: block;
        pointer-events: auto;
    }

    .modal > div {
        width: 400px;
        position: relative;
        margin: 10% auto;
        padding: 5px 20px 13px 20px;
        border-radius: 10px;
        background: #fff;
    }

    .btn-close {
        padding: 5px;
        position: absolute;
        right: 10px;
        border: none;
        background: red;
        color: #fff;
        box-shadow: 0 0 10px rgba(0,0,0,0.5);
    }

    .btn {
        display: inline-block;
        border: 1px solid #222;
        padding: 3px 10px;
        background: #ddd;
        box-sizing: border-box;
    }


JS:



    let modaWindow = document.getElementById('modalWindow');

    document.getElementById('openBtn').addEventListener('click', function() {
        modaWindow.classList.add('active');
    });

    document.getElementById('closeBtn').addEventListener('click', function() {
        modaWindow.classList.remove('active');
    });


Jika Anda membuka halaman dan mencoba menavigasi ke elemen di belakang jendela modal menggunakan tombol "TAB / SHIFT + TAB", maka elemen ini menerima fokus, seperti yang ditunjukkan pada gambar terlampir.



gambar



Untuk mengatasi masalah ini, kita perlu menetapkan semua elemen interaktif atribut 'tabindex' dengan nilai minus satu.



1. Untuk pekerjaan lebih lanjut, buat kelas "modalWindow" dengan properti dan metode berikut:



  • doc - dokumen halaman. di mana kita membangun jendela modal
  • modal - wadah untuk jendela modal
  • interactiveElementsList - larik elemen interaktif
  • blockElementsList - larik elemen blok halaman
  • konstruktor - konstruktor kelas
  • create - metode yang digunakan untuk membuat jendela modal
  • hapus - metode yang digunakan untuk menghapus modal


2. Mari mengimplementasikan konstruktor:



constructor(doc, modal) {
    this.doc = doc;
    this.modal = modal;
    this.interactiveElementsList = [];
    this.blockElementsList = [];
}


"InteractiveElementsList" dan "blockElementsList" diperlukan untuk memuat elemen halaman yang diubah saat modal dibuat.



3. Buat konstanta di mana kami akan menyimpan daftar semua elemen yang dapat memiliki fokus:



const INTERECTIVE_SELECTORS = ['a', 'button', 'input', 'textarea', '[tabindex]'];


4. Dalam metode 'buat', pilih semua elemen yang cocok dengan pemilih kami dan setel semua 'tabindex = -1' (abaikan elemen yang sudah memiliki nilai ini)



 let elements = this.doc.querySelectorAll(INTERECTIVE_SELECTORS.toString());
 let element;
 for (let i = 0; i < elements.length; i++) {
     element = elements[i];
     if (!this.modal.contains(element)) {
         if (element.getAttribute('tabindex') !== '-1') {
               element.setAttribute('tabindex', '-1');
               this.interactiveElementsList.push(element);
         }
     }
 }


Masalah serupa muncul ketika kita menggunakan tombol atau gerakan khusus (dalam program seluler) untuk navigasi, dalam hal ini kita dapat menavigasi tidak hanya melalui elemen interaktif, tetapi juga melalui teks. Untuk memperbaikinya kita perlu menambahkan



5. Kita tidak perlu membuat array untuk menampung penyeleksi di sini, kita hanya mengambil semua anak dari node 'body'



let children = this.doc.body.children;


6. Langkah keempat mirip dengan langkah 2, hanya menggunakan 'aria-hidden'



for (let i = 0; i < children.length; i++) {
   element = children[i];
   if (!this.modal.contains(element)) {
      if (element.getAttribute('aria-hidden') !== 'true') {
          element.setAttribute('aria-hidden', 'true');
          this.blockElementsList.push(element);
       }
    }
}


Metode "buat" yang diselesaikan:



create() {
    let elements = this.doc.querySelectorAll(INTERECTIVE_SELECTORS.toString());
    let element;
    for (let i = 0; i < elements.length; i++) {
        element = elements[i];
        if (!this.modal.contains(element)) {
            if (element.getAttribute('tabindex') !== '-1') {
                element.setAttribute('tabindex', '-1');
                this.interactiveElementsList.push(element);
            }
        }
    }

    let children = this.doc.body.children;
    for (let i = 0; i < children.length; i++) {
        element = children[i];
        if (!this.modal.contains(element)) {
            if (element.getAttribute('aria-hidden') !== 'true') {
                element.setAttribute('aria-hidden', 'true');
                this.blockElementsList.push(element);
            }
        }
    }
}


7. Pada langkah keenam, kami menerapkan metode kebalikan 'create':



 remove() {
            let element;
            while(this.interactiveElementsList.length !== 0) {
                element = this.interactiveElementsList.pop();
                element.setAttribute('tabindex', '0');
            }

            while(this.interactiveElementsList.length !== 0) {
                element = this.interactiveElementsList.pop();
                element.setAttribute('aria-gidden', 'false');
            }
}


8. Untuk membuat semuanya bekerja, kita perlu membuat turunan dari kelas "modalWindow" dan memanggil metode "create" dan "remove":



    let modaWindow = document.getElementById('modalWindow');
    const modal = new modalWindow(document, modaWindow);

    document.getElementById('openBtn').addEventListener('click', function() {
        modaWindow.classList.add('active');
       // modal.create();
    });

    document.getElementById('closeBtn').addEventListener('click', function() {
        modaWindow.classList.remove('active');
       // modal.remove();
    });


Kode kelas lengkap:



class modalWindow{
    constructor(doc, modal) {
        this.doc = doc;
        this.modal = modal;
        this.interactiveElementsList = [];
        this.blockElementsList = [];
    }

    create() {
        let elements = this.doc.querySelectorAll(INTERECTIVE_SELECTORS.toString());
        let element;
        for (let i = 0; i < elements.length; i++) {
            element = elements[i];
            if (!this.modal.contains(element)) {
                if (element.getAttribute('tabindex') !== '-1') {
                    element.setAttribute('tabindex', '-1');
                    this.interactiveElementsList.push(element);
                }
            }
        }

        let children = this.doc.body.children;
        for (let i = 0; i < children.length; i++) {
            element = children[i];
            if (!this.modal.contains(element)) {
                if (element.getAttribute('aria-hidden') !== 'true') {
                    element.setAttribute('aria-hidden', 'true');
                    this.blockElementsList.push(element);
                }
            }
        }
    }

    remove() {
        let element;
        while(this.interactiveElementsList.length !== 0) {
            element = this.interactiveElementsList.pop();
            element.setAttribute('tabindex', '0');
        }

        while(this.interactiveElementsList.length !== 0) {
            element = this.interactiveElementsList.pop();
            element.setAttribute('aria-gidden', 'false');
        }
    }


PS



Jika masalah navigasi pada elemen teks tidak diselesaikan pada perangkat seluler, maka pilihan berikut dapat digunakan:



  const BLOCKS_SELECTORS = ['div', 'header', 'main', 'section', 'footer'];
  let children = this.doc.querySelectorAll(BLOCKS_SELECTORS .toString());


Tautan ke sumber daya yang berguna






All Articles