Skenarionya hampir selalu sama, yaitu tabel data di dalam container yang dapat di-scroll. Setiap baris memiliki menu tindakan, dropdown kecil dengan beberapa opsi, seperti Edit, Duplikat, dan Hapus. Anda membangunnya, tampaknya berfungsi dengan baik secara terpisah, dan kemudian seseorang memasukkannya ke dalam div yang dapat digulir dan semuanya berantakan. Saya telah melihat bug ini di tiga basis kode yang berbeda: wadah, tumpukan, dan kerangka kerja, semuanya berbeda. Namun, bugnya benar-benar identik. Dropdown terpotong di tepi wadah. Atau itu muncul di belakang konten yang secara logis seharusnya berada di bawahnya. Atau berfungsi dengan baik hingga pengguna menggulir, lalu melayang. Anda meraih z-index: 9999. Terkadang membantu, tetapi di lain waktu tidak menghasilkan apa-apa. Ketidakkonsistenan tersebut adalah petunjuk pertama bahwa sesuatu yang lebih dalam sedang terjadi. Alasan mengapa sistem ini terus muncul kembali adalah karena ada tiga sistem browser terpisah yang terlibat, dan sebagian besar pengembang memahami masing-masing sistem secara terpisah, namun tidak pernah memikirkan tentang apa yang terjadi jika ketiganya bertabrakan: overflow, penumpukan konteks, dan blok yang memuat.

Setelah Anda memahami bagaimana ketiganya berinteraksi, mode kegagalan tidak lagi terasa acak. Faktanya, hal tersebut mudah ditebak. Tiga Hal Sebenarnya yang Menyebabkan Hal Ini Mari kita lihat masing-masing item tersebut secara detail. Masalah Luapan Saat Anda menyetel overflow: tersembunyi, overflow: scroll, atau overflow: auto pada sebuah elemen, browser akan memotong apa pun yang melampaui batasnya, termasuk turunan yang diposisikan secara absolut. .scroll-container { meluap: otomatis; tinggi: 300 piksel; /* Ini akan memotong dropdown, titik */ }

.tarik-turun { posisi: mutlak; /* Tidak masalah -- masih terpotong oleh .scroll-container */ }

Itu mengejutkan saya saat pertama kali saya bertemu dengannya. Saya berasumsi position: absolute akan membiarkan elemen lolos dari kliping wadah. Tidak. Dalam praktiknya, hal ini berarti menu yang diposisikan secara mutlak dapat dipotong oleh leluhur mana pun yang memiliki nilai luapan yang tidak terlihat, bahkan jika leluhur tersebut bukan blok yang memuat menu tersebut. Kliping dan penentuan posisi adalah sistem yang terpisah. Mereka kebetulan bertabrakan dengan cara yang terlihat acak sampai Anda memahami keduanya.

Berikut ini contoh React menggunakan createPortal:

impor { createPortal } dari 'react-dom'; impor { useState, useEffect, useRef } dari 'react';

fungsi Dropdown({ jangkarRef, isOpen, anak }) { const [posisi, setPosition] = useState({ atas: 0, kiri: 0 });

gunakanEffect(() => { if (isOpen && jangkarRef.saat ini) { const rect = jangkarRef.current.getBoundingClientRect(); setPosisi({ atas: persegi.bawah + jendela.gulirY, kiri: persegi.kiri + window.scrollX, }); } }, [isOpen, jangkarRef]);

jika (!isOpen) mengembalikan nol;

kembalikan buatPortal(

{anak-anak}
, dokumen.body ); }

Dan tentu saja kita tidak bisa mengabaikan aksesibilitas. Memperbaiki elemen yang muncul di atas konten harus tetap dapat dijangkau dengan keyboard. Jika urutan fokus tidak berpindah secara alami ke dropdown tetap, Anda harus mengelolanya menggunakan kode. Penting juga untuk memeriksa apakah konten tersebut tidak berada di atas konten interaktif lainnya tanpa ada cara untuk mengabaikannya. Yang itu mengganggu Anda dalam pengujian keyboard. Pemosisian Jangkar CSS: Menurut Saya Ini Arahnya CSS Anchor Positioning adalah arah yang paling saya minati saat ini. Saya tidak yakin seberapa banyak spesifikasi yang benar-benar dapat digunakan saat pertama kali melihatnya. Ini memungkinkan Anda mendeklarasikan hubungan antara dropdown dan pemicunya secara langsung di CSS, dan browser menangani koordinatnya. .trigger { nama jangkar: --pemicu-saya; }

.menu tarik-turun { posisi: mutlak; jangkar posisi: --pemicu saya; atas: jangkar(bawah); kiri: jangkar(kiri); posisi-coba-fallback: flip-block, flip-inline; }

Properti position-try-fallbacks inilah yang membuatnya layak digunakan dibandingkan perhitungan manual. Browser mencoba penempatan alternatif sebelum menyerah, sehingga dropdown di bagian bawah viewport otomatis terbalik dan tidak terpotong. Dukungan browser solid di browser berbasis Chromium dan terus berkembang di Safari. Firefox membutuhkan polyfill. Paket @oddbird/css-anchor-positioning mencakup spesifikasi inti. Saya telah menemukan kasus-kasus tepi tata letak yang memerlukan fallback yang tidak saya perkirakan, jadi perlakukan ini sebagai penyempurnaan progresif atau pasangkan denganPenggantian JavaScript untuk Firefox. Singkatnya, menjanjikan namun belum universal. Uji di browser target Anda. Dan sejauh menyangkut aksesibilitas, mendeklarasikan hubungan visual dalam CSS tidak memberi tahu pohon aksesibilitas apa pun. aria-controls, aria-expanded, aria-haspopup — bagian itu masih ada pada Anda. Terkadang Perbaikannya Hanya Memindahkan Elemen Sebelum meraih portal atau membuat perhitungan koordinat, saya selalu menanyakan satu pertanyaan terlebih dahulu: Apakah dropdown ini benar-benar harus berada di dalam wadah gulir? Jika tidak, memindahkan markup ke tingkat pembungkus yang lebih tinggi akan menghilangkan masalah sepenuhnya, tanpa JavaScript dan tanpa penghitungan koordinat. Hal ini tidak selalu memungkinkan. Jika tombol dan dropdown dienkapsulasi dalam komponen yang sama, memindahkan satu tanpa yang lain berarti memikirkan ulang keseluruhan API. Namun jika Anda bisa melakukannya, tidak ada yang perlu di-debug. Masalahnya tidak ada. Apa yang Masih Belum Dipecahkan oleh CSS Modern CSS telah berkembang pesat dalam hal ini, namun masih ada beberapa hal yang mengecewakan Anda. Posisinya: masalah tetap dan transformasi masih ada. Itu sengaja ada dalam spesifikasi, yang berarti tidak ada solusi CSS. Jika Anda menggunakan pustaka animasi yang membungkus tata letak Anda dalam elemen yang diubah, Anda kembali memerlukan portal atau pemosisian jangkar. CSS Anchor Positioning menjanjikan, tapi baru. Seperti disebutkan sebelumnya, Firefox masih memerlukan polyfill pada saat saya menulis ini. Saya telah menemukan kasus tata letak tepi yang memerlukan fallback yang tidak saya perkirakan. Jika saat ini Anda memerlukan perilaku yang konsisten di semua browser, Anda masih menggunakan JavaScript untuk bagian yang rumit. Tambahan yang sebenarnya saya ubah alur kerjanya adalah HTML Popover API, sekarang tersedia di semua browser modern. Elemen dengan atribut popover dirender di lapisan atas browser, di atas segalanya, tanpa memerlukan pemosisian JavaScript.

Penanganan escape, pemberhentian saat klik di luar, dan semantik aksesibilitas yang solid tersedia gratis untuk hal-hal seperti tooltip, widget pengungkapan, dan overlay sederhana. Ini adalah alat pertama yang saya gunakan saat ini. Meskipun demikian, ini tidak menyelesaikan penentuan posisi. Ini memecahkan pelapisan. Anda masih memerlukan pemosisian jangkar atau JavaScript untuk menyelaraskan popover dengan pemicunya. Popover API menangani pelapisan. Penempatan jangkar menangani penempatan. Jika digunakan bersama-sama, keduanya mencakup sebagian besar hal yang sebelumnya Anda perlukan untuk dilakukan oleh perpustakaan. Panduan Keputusan Untuk Situasi Anda Setelah melalui semua ini dengan susah payah, inilah cara saya memikirkan pilihan sekarang.

Gunakan portal. Saya akan menggunakan ini ketika pemicunya berada jauh di dalam wadah gulir yang bersarang. Saya menggunakan pola ini untuk menu tindakan tabel dan memasangkannya dengan pemulihan fokus dan pemeriksaan aksesibilitas. Ini adalah pilihan yang paling dapat diandalkan, tetapi anggarkan waktu untuk pemasangan kabel tambahan. Gunakan pemosisian tetap. Ini ketika Anda menggunakan JavaScript vanilla atau kerangka kerja ringan dan dapat memverifikasi bahwa tidak ada leluhur yang menerapkan transformasi atau filter. Pengaturannya mudah dan debugnya mudah, selama batasan tersebut berlaku. Gunakan CSS Anchor Positioning. Jangkau ini ketika dukungan browser Anda mengizinkannya. Jika dukungan Firefox diperlukan, pasangkan dengan polyfill @oddbird. Di sinilah tujuan platform ini dan pada akhirnya akan menjadi pendekatan pilihan Anda. Susun ulang DOM. Gunakan ini jika arsitektur mengizinkannya, dan Anda tidak menginginkan kompleksitas waktu proses. Saya yakin ini mungkin opsi yang paling diremehkan. Gabungkan pola. Lakukan ini bila Anda ingin penentuan posisi jangkar sebagai pendekatan utama, dipasangkan dengan pengganti JavaScript untuk browser yang tidak didukung. Atau portal untuk penempatan DOM yang dipasangkan dengan getBoundingClientRect() untuk akurasi koordinat.

Kesimpulan Saya biasa menganggap bug ini sebagai masalah yang terjadi satu kali saja — sesuatu yang perlu diperbaiki dan diatasi. Namun begitu saya menggunakannya cukup lama untuk memahami ketiga sistem yang terlibat — kliping luapan, konteks bertumpuk, dan blok yang memuatnya — rasanya tidak lagi acak. Saya dapat melihat dropdown yang rusak dan segera melacak leluhur mana yang bertanggung jawab. Pergeseran dalam cara saya membaca DOM adalah hal yang benar-benar menarik. Tidak ada satu pun jawaban yang benar. Apa yang saya capai bergantung pada apa yang dapat saya kendalikan dalam basis kode: portal ketika pohon leluhur tidak dapat diprediksi; pemosisian tetap saat bersih dan sederhana; memindahkan elemen ketika tidak ada yang menghentikan saya; dan posisi jangkar sekarang,dimana saya bisa. Apa pun pilihan Anda, jangan jadikan aksesibilitas sebagai langkah terakhir. Menurut pengalaman saya, saat itulah hal itu dilewati. Hubungan ARIA, manajemen fokus, perilaku keyboard — semuanya tidak sempurna. Mereka adalah bagian dari apa yang membuat hal tersebut benar-benar berhasil. Lihat kode sumber lengkap di repo GitHub saya. Bacaan Lebih Lanjut Ini adalah referensi yang terus saya baca saat mengerjakan ini:

Konteks Penumpukan (MDN) “Panduan Pemosisian Jangkar CSS”, Juan Diego Rodriguez “Memulai API Popover”, Godstime Aburu UI mengambang (floating-ui.com) CSS Meluap (MDN)

You May Also Like

Enjoyed This Article?

Get weekly tips on growing your audience and monetizing your content — straight to your inbox.

No spam. Join 138,000+ creators. Unsubscribe anytime.

Create Your Free Bio Page

Join 138,000+ creators on Seemless.

Get Started Free