Skenaario on lähes aina sama, joka on vieritettävän säilön sisällä oleva tietotaulukko. Jokaisella rivillä on toimintovalikko, pieni pudotusvalikko, jossa on vaihtoehtoja, kuten Muokkaa, Kopioi ja Poista. Rakennat sen, se näyttää toimivan täydellisesti erillään, ja sitten joku laittaa sen vieritettävään diviin ja asiat hajoavat. Olen nähnyt tämän tarkan virheen kolmessa eri koodikannassa: säiliössä, pinossa ja kehyksessä, kaikki erilaisia. Vika on kuitenkin täysin identtinen. Pudotusvalikko leikataan säiliön reunasta. Tai se näkyy sisällön takana, jonka pitäisi loogisesti olla sen alapuolella. Tai se toimii hyvin, kunnes käyttäjä vierittää, ja sitten se ajautuu. Haet z-indeksiä: 9999. Joskus se auttaa, mutta toisinaan se ei tee yhtään mitään. Tämä epäjohdonmukaisuus on ensimmäinen vihje siitä, että jotain syvempää on tapahtumassa. Syy, miksi se palaa jatkuvasti, on se, että mukana on kolme erillistä selainjärjestelmää, ja useimmat kehittäjät ymmärtävät jokaisen erikseen, mutta eivät koskaan ajattele, mitä tapahtuu, kun kaikki kolme törmäävät: ylivuoto, pinoaminen kontekstit ja lohkot.
Kun ymmärrät kaikkien kolmen vuorovaikutuksen, vikatilat lakkaavat tuntumasta satunnaisilta. Itse asiassa niistä tulee ennustettavia. Kolme asiaa, jotka todella aiheuttavat tämän Katsotaanpa jokaista näistä kohteista yksityiskohtaisesti. Ylivuoto-ongelma Kun asetat elementille ylivuoto: piilotettu, ylivuoto: vieritys tai ylivuoto: automaattinen, selain leikkaa kaiken, mikä ylittää sen rajojen, mukaan lukien ehdottomasti sijoitetut jälkeläiset. .scroll-container { ylivuoto: auto; korkeus: 300px; /* Tämä leikkaa avattavan valikon, pisteen */ }
.dropdown { sijainti: absoluuttinen; /* Ei väliä -- silti leikattu .scroll-containerilla */ }
Se yllätti minut ensimmäisen kerran kun törmäsin siihen. Oletin aseman: absoluuttinen antaisi elementin paeta säiliön leikkaamisesta. Ei. Käytännössä tämä tarkoittaa sitä, että mikä tahansa esi-isä, jolla on ei-näkyvä ylivuotoarvo, voi katkaista täysin sijoitetun valikon, vaikka kyseinen esi-isä ei olisikaan valikon sisältävä lohko. Leikkaaminen ja paikannus ovat erillisiä järjestelmiä. Ne vain sattuvat törmäämään tavoilla, jotka näyttävät täysin sattumanvaraisilta, kunnes ymmärrät molemmat.
Tässä on esimerkki Reactista createPortalin avulla:
tuo { createPortal } react-domista; tuo { useState, useEffect, useRef } osoitteesta 'react';
function Dropdown({ anchorRef, isOpen, lapset }) { const [sijainti, setPosition] = useState({ top: 0, left: 0 });
useEffect(() => { if (isOpen && anchorRef.current) { const rect = anchorRef.current.getBoundingClientRect(); setPosition({ alkuun: rect.bottom + window.scrollY, vasen: rect.left + window.scrollX, }); } }, [isOpen, anchorRef]);
if (!isOpen) return null;
return createPortal(
Ja tietenkään emme voi sivuuttaa saavutettavuutta. Sisällön päällä näkyvien kiinteiden elementtien on silti oltava näppäimistöllä saavutettavissa. Jos tarkennusjärjestys ei luonnollisesti siirry kiinteään avattavaan valikkoon, sinun on hallittava sitä koodin avulla. On myös syytä tarkistaa, ettei se istu muun interaktiivisen sisällön yläpuolella ilman, että sitä voi hylätä. Se puree sinua näppäimistötestauksessa. CSS-ankkuripaikannus: mihin tämä on mielestäni menossa CSS-ankkuripaikannus on suunta, josta olen tällä hetkellä eniten kiinnostunut. En ollut varma, kuinka suuri osa tiedoista oli todella käyttökelpoista, kun katsoin sitä ensimmäisen kerran. Sen avulla voit ilmoittaa avattavan valikon ja sen liipaisimen välisen suhteen suoraan CSS:ssä, ja selain käsittelee koordinaatit. .trigger { ankkurin nimi: --my-trigger; }
.dropdown-menu { sijainti: absoluuttinen; sijainti-ankkuri: --my-trigger; yläosa: ankkuri (alhaalla); vasen: ankkuri(vasen); position-try-fallbacks: flip-block, flip-inline; }
Sijainti-try-fallbacks-ominaisuus tekee tästä käyttökelpoisen manuaalisen laskennan sijaan. Selain yrittää vaihtoehtoisia sijoitteluja ennen kuin luovuttaa, joten näkymän alareunassa oleva pudotusvalikko kääntyy automaattisesti ylöspäin sen sijaan, että se katkeaa. Selaintuki on vakaata Chromium-pohjaisissa selaimissa ja kasvaa Safarissa. Firefox tarvitsee polyfillin. @oddbird/css-anchor-positioning-paketti kattaa ydintiedot. Olen osunut sen kanssa asettelureunakoteloihin, jotka vaativat varauksia, joita en odottanut, joten pidä sitä progressiivisena parannuksena tai yhdistä seJavaScript-varausohjelma Firefoxille. Lyhyesti sanottuna lupaava, mutta ei vielä yleismaailmallinen. Testaa kohdeselaimissasi. Ja mitä tulee saavutettavuuteen, visuaalisen suhteen ilmoittaminen CSS:ssä ei kerro esteettömyyspuulle mitään. aria-controls, aria-expanded, aria-haspopup - tämä osa on edelleen sinun. Joskus korjaus on vain elementin siirtämistä Ennen kuin otan yhteyttä portaaliin tai teen koordinaattilaskelmia, esitän aina ensin yhden kysymyksen: Onko tämän pudotusvalikon todella oltava vierityssäiliön sisällä? Jos näin ei ole, merkintöjen siirtäminen korkeamman tason kääreeseen poistaa ongelman kokonaan ilman JavaScriptiä tai koordinaattilaskutoimituksia. Tämä ei ole aina mahdollista. Jos painike ja pudotusvalikko on kapseloitu samaan komponenttiin, toisen siirtäminen ilman toista tarkoittaa koko API:n uudelleenarviointia. Mutta kun voit tehdä sen, ei ole mitään korjattavaa. Ongelmaa ei vain ole olemassa. Mitä nykyaikainen CSS ei vieläkään ratkaise CSS on edennyt täällä pitkän matkan, mutta silti on paikkoja, jotka pettävät sinut. Asema: korjaus- ja muutosongelmat ovat edelleen olemassa. Se on tiedoissa tarkoituksella, mikä tarkoittaa, että CSS-kiertotapaa ei ole olemassa. Jos käytät animaatiokirjastoa, joka kääri asettelusi muunnetuksi elementiksi, tarvitset taas portaaleja tai ankkurisijoittelua. CSS-ankkuripaikannus on lupaava, mutta uusi. Kuten aiemmin mainittiin, Firefox tarvitsee vielä monitäytteen kirjoittaessani tätä. Olen lyönyt sillä asettelureunakoteloita, jotka vaativat varauksia, joita en odottanut. Jos tarvitset johdonmukaista toimintaa kaikissa selaimissa tänään, käytät edelleen JavaScriptiä vaikeissa osissa. Lisäys, johon olen itse asiassa muuttanut työnkulkuani, on HTML Popover API, joka on nyt saatavilla kaikissa nykyaikaisissa selaimissa. Elementit, joissa on popover-attribuutti, renderöidään selaimen ylimmässä kerroksessa kaiken edelle ilman JavaScript-paikannusta.
Escape-käsittely, hylkääminen klikkauksen ulkopuolella ja kiinteä esteettömyyssemantiikka ovat ilmaisia esimerkiksi työkaluvihjeille, ilmoituswidgeteille ja yksinkertaisille peittokuville. Se on ensimmäinen työkalu, johon tartun tällä hetkellä. Se ei kuitenkaan ratkaise paikannusta. Se ratkaisee kerrostuksen. Tarvitset silti ankkuripaikannusta tai JavaScriptiä kohdistaaksesi ponnahdusikkunan liipaisimen kanssa. Popover API hoitaa kerrostuksen. Ankkurin sijoitus hoitaa sijoittelun. Yhdessä käytettynä ne kattavat suurimman osan siitä, mitä olet aiemmin hakenut kirjastoon. Päätösopas tilanteeseesi Kävittyäni tämän kaiken läpi raskaasti, näin ajattelen valintaa nyt.
Käytä portaalia. Käyttäisin tätä, kun triggeri on syvällä sisäkkäisissä vierityssäiliöissä. Käytin tätä mallia taulukon toimintovalikoissa ja yhdistän sen tarkennuksen palautukseen ja esteettömyystarkistuksiin. Se on luotettavin vaihtoehto, mutta varaa aikaa lisäjohdotuksille. Käytä kiinteää sijoittelua. Tämä on tarkoitettu silloin, kun käytät vanilja JavaScriptiä tai kevyttä kehystä ja pystyt varmistamaan, ettei esi-isä käytä muunnoksia tai suodattimia. Se on helppo asentaa ja helppo korjata, kunhan tämä yksi rajoitus on voimassa. Käytä CSS-ankkuripaikannusta. Tavoita tätä, kun selaimesi tuki sallii sen. Jos Firefox-tukea tarvitaan, yhdistä se @oddbird-polyfillin kanssa. Tähän alusta on viime kädessä menossa, ja siitä tulee lopulta sinun lähestymistapasi. Järjestä DOM uudelleen. Käytä tätä, kun arkkitehtuuri sen sallii ja haluat nolla ajonaikaista monimutkaisuutta. Uskon, että se on todennäköisesti aliarvostetuin vaihtoehto. Yhdistä kuvioita.Tee tämä, kun haluat ankkurisijoittelun ensisijaiseksi menetelmäksi yhdistettynä JavaScript-varaustoimintoon ei-tuetuille selaimille. Tai portaali DOM-sijoittelua varten, joka on yhdistetty getBoundingClientRect():n kanssa koordinaattien tarkkuuden varmistamiseksi.
Johtopäätös Pidin tätä vikaa kertaluonteisena ongelmana - korjattavana ja josta on siirryttävä eteenpäin. Mutta kun istuin sen kanssa tarpeeksi kauan ymmärtääkseni kaikki kolme siihen liittyvää järjestelmää – ylivuotoleikkaus, kontekstien pinoaminen ja lohkojen sisältäminen – se lakkasi tuntumasta satunnaiselta. Voisin katsoa rikkinäistä pudotusvalikkoa ja jäljittää heti, mikä esi-isä oli vastuussa. Tämä muutos siinä, miten luin DOM:ta, oli todellinen takeway. Ei ole yhtä oikeaa vastausta. Se, mihin tavoitin, riippui siitä, mitä pystyin hallitsemaan koodikannassa: portaaleja, kun esi-isäpuu oli arvaamaton; kiinteä sijainti, kun se oli puhdas ja yksinkertainen; liikuttaa elementtiä, kun mikään ei estänyt minua; ja ankkurin sijoitus nyt,missä voin. Mitä tahansa päätätkin, älä pidä esteettömyysastetta viimeisenä askeleena. Kokemukseni mukaan se on juuri silloin, kun se ohitetaan. ARIA-suhteet, fokuksen hallinta, näppäimistön käyttäytyminen – ne eivät ole hienoja. Ne ovat osa sitä, mikä saa asian todella toimimaan. Katso koko lähdekoodi GitHub-varastostani. Lue lisää Nämä ovat viittauksia, joihin palasin jatkuvasti tätä työskennellessäni:
Pinoamiskonteksti (MDN) "CSS-ankkurin paikannusopas", Juan Diego Rodriguez "Popover API:n aloitus", Godstime Aburu Kelluva käyttöliittymä (floating-ui.com) CSS-ylivuoto (MDN)