Stsenaarium on peaaegu alati sama, mis on andmetabel keritava konteineri sees. Igal real on toimingumenüü, väike rippmenüü teatud valikutega, nagu Redigeerimine, Dubleerimine ja Kustuta. Ehitate selle, tundub, et see töötab suurepäraselt isoleeritult ja siis keegi paneb selle selle keritava div sisse ja asjad lagunevad. Olen näinud seda täpset viga kolmes erinevas koodibaasis: konteineris, virnas ja raamistikus, kõik erinevad. Viga on aga täiesti identne. Rippmenüü kärbitakse konteineri servast. Või ilmub see sisu taha, mis peaks loogiliselt selle all olema. Või töötab see hästi, kuni kasutaja kerib ja seejärel triivib. Jõuate z-indeksini: 9999. Mõnikord see aitab, kuid mõnikord ei aita see absoluutselt mitte midagi. See vastuolu on esimene vihje, et toimub midagi sügavamat. Põhjus, miks see ikka ja jälle tagasi tuleb, on see, et tegemist on kolme erineva brauserisüsteemiga ja enamik arendajaid mõistab igaüks neist eraldi, kuid ei mõtle kunagi sellele, mis juhtub siis, kui kõik kolm kokku põrkuvad: ülevool, kontekstide virnastamine ja plokkide sisaldamine.
Kui saate aru, kuidas kõik kolm omavahel suhtlevad, lakkavad tõrkerežiimid tunduma juhuslikud. Tegelikult muutuvad need etteaimatavaks. Kolm asja, mis seda tegelikult põhjustavad Vaatame kõiki neid elemente üksikasjalikult. Ülevoolu probleem Kui määrate elemendil ületäitumine: peidetud, ületäitmine: kerimine või ületäitmine: automaatne, lõikab brauser kõik, mis ulatub väljapoole selle piire, sealhulgas absoluutselt paigutatud järeltulijad. .scroll-container { ülevool: auto; kõrgus: 300 pikslit; /* See lõikab rippmenüü, punkt */ }
.dropdown { positsioon: absoluutne; /* Pole tähtis – ikka kärbitud .scroll-containeriga */ }
See üllatas mind esimest korda, kui sellega kokku puutusin. Eeldasin seisukohta: absoluutne lubaks elemendil konteineri lõikest välja pääseda. Ei tee seda. Praktikas tähendab see, et absoluutselt positsioneeritud menüü saab välja lõigata mis tahes esivanem, millel on mittenähtav ülevoolu väärtus, isegi kui see esivanem ei ole menüüd sisaldav plokk. Lõikamine ja positsioneerimine on eraldi süsteemid. Need lihtsalt põrkuvad täiesti juhuslikult, kuni mõistate mõlemat.
Siin on Reacti näide CreatePortali kasutamisest:
import { createPortal } 'react-dom'ist; import { useState, useEffect, useRef } alates 'react';
function Rippmenüü ({ anchorRef, isOpen, lapsed }) { const [positsioon, setPosition] = useState({ top: 0, left: 0 });
useEffect(() => { if (isOpen && anchorRef.current) { const rect = anchorRef.current.getBoundingClientRect(); setPosition({ ülemine: rect.bottom + window.scrollY, vasakule: rect.left + window.scrollX, }); } }, [isOpen, anchorRef]);
if (!isOpen) tagastab null;
return createPortal(
Ja loomulikult ei saa me juurdepääsetavust tähelepanuta jätta. Sisu kohal kuvatavad fikseeritud elemendid peavad siiski olema klaviatuuriga juurdepääsetavad. Kui fookuse järjekord ei liigu loomulikult fikseeritud rippmenüüsse, peate seda koodi abil haldama. Samuti tasub kontrollida, et see ei asuks muu interaktiivse sisu kohal, ilma et oleks võimalik sellest loobuda. See hammustab teid klaviatuuri testimisel. CSS-i ankru positsioneerimine: kuhu see minu arvates liigub CSS-i ankru positsioneerimine on suund, mis mind praegu kõige rohkem huvitab. Kui ma seda esimest korda vaatasin, ei olnud ma kindel, kui suur osa spetsifikatsioonidest tegelikult kasutatav oli. See võimaldab teil deklareerida rippmenüü ja selle päästiku vahelise seose otse CSS-is ning brauser käsitleb koordinaate. .trigger { ankru nimi: --minu-päästik; }
.dropdown-menu { positsioon: absoluutne; positsiooniankur: --minu-trigger; ülemine: ankur (alumine); vasak: ankur(vasakul); asendi-proovi-varumised: flip-block, flip-inline; }
Atribuut position-try-fallbacks on see, mis muudab selle käsitsi arvutamise asemel kasulikuks. Brauser proovib enne loobumist alternatiivseid paigutusi, nii et vaateakna allosas olev rippmenüü libiseb katkemise asemel automaatselt üles. Brauseri tugi on Chromiumipõhistes brauserites kindel ja kasvab Safaris. Firefox vajab polütäitmist. @oddbird/css-anchor-positsioneerimispakett katab põhispetsifikatsioonid. Olen sellega tabanud paigutuse äärejuhtumeid, mis nõudsid tagasiminekuid, mida ma ei oodanud, nii et käsitlege seda kui järkjärgulist täiustust või siduge seeJavaScripti varundus Firefoxile. Ühesõnaga paljulubav, kuid veel mitte universaalne. Testige oma sihtbrauserites. Ja mis puudutab juurdepääsetavust, siis visuaalse seose deklareerimine CSS-is ei ütle juurdepääsetavuse puule midagi. aria-controls, aria-expanded, aria-haspopup – see osa on endiselt teie käes. Mõnikord on parandus lihtsalt elemendi liigutamine Enne portaali poole pöördumist või koordinaatide arvutuste tegemist esitan alati ühe küsimuse: kas see rippmenüü peab tõesti asuma kerimiskonteineris? Kui seda ei juhtu, kõrvaldab märgistuse teisaldamine kõrgema taseme ümbrisesse probleemi täielikult, ilma JavaScripti ja koordinaatide arvutusteta. See ei ole alati võimalik. Kui nupp ja rippmenüü on kapseldatud samasse komponenti, tähendab ühe liigutamine ilma teiseta kogu API ümbermõtestamist. Aga kui saate seda teha, pole midagi siluda. Probleemi lihtsalt ei eksisteeri. Mida kaasaegne CSS ikka veel ei lahenda CSS on siin kaugele jõudnud, kuid siiski on kohti, mis teid alt veab. Seisukoht: fikseeritud ja teisendusprobleemid on endiselt olemas. See on spetsifikatsioonis tahtlikult, mis tähendab, et CSS-i lahendust pole. Kui kasutate animatsiooniteeki, mis mähib teie paigutuse teisendatud elemendiks, vajate taas portaale või ankurpositsioneerimist. CSS-ankru positsioneerimine on paljulubav, kuid uus. Nagu varem mainitud, vajab Firefox selle kirjutamise ajal endiselt polütäitmist. Olen sellega tabanud paigutuse äärejuhtumeid, mis nõudsid tagasiminekuid, mida ma ei osanud oodata. Kui vajate täna ühtlast käitumist kõigis brauserites, otsite keeruliste osade jaoks endiselt JavaScripti. Täiendus, mille jaoks olen oma töövoogu muutnud, on HTML Popover API, mis on nüüd saadaval kõigis kaasaegsetes brauserites. Popover-atribuudiga elemendid renderdatakse brauseri ülemises kihis, ennekõike, ilma JavaScripti positsioneerimiseta.
Põgenemiskäsitlus, väljastpoolt klõpsamisel loobumine ja kindel juurdepääsetavuse semantika on tasuta selliste asjade jaoks nagu kohtspikrid, avalikustamisvidinad ja lihtsad ülekatted. See on esimene tööriist, mille poole ma praegu jõuan. See tähendab, et see ei lahenda positsioneerimist. See lahendab kihilisuse. Hüpikakna joondamiseks selle päästikuga on siiski vaja ankru positsioneerimist või JavaScripti. Popover API tegeleb kihistamisega. Ankru positsioneerimine tegeleb paigutusega. Koos kasutades katavad need suurema osa sellest, mida olete varem raamatukogu poole püüdnud. Otsuste juhend teie olukorra jaoks Pärast seda, kui olen selle kõige raskema tee läbi teinud, mõtlen ma valikule praegu järgmiselt.
Kasutage portaali. Kasutaksin seda siis, kui päästik asub sügaval pesastatud kerimiskonteinerites. Kasutasin seda mustrit tabeli toimingute menüüde jaoks ja sidusin selle fookuse taastamise ja juurdepääsetavuse kontrollimisega. See on kõige usaldusväärsem valik, kuid lisajuhtmete jaoks kulub aega. Kasutage fikseeritud positsioneerimist. See on mõeldud siis, kui kasutate vanilje JavaScripti või kerget raamistikku ja saate kontrollida, et ükski esivanem ei rakendaks teisendusi ega filtreid. Seda on lihtne seadistada ja lihtne siluda, kui see piirang kehtib. Kasutage CSS-i ankru positsioneerimist. Jõudke selleks siis, kui teie brauseri tugi seda võimaldab. Kui vajate Firefoxi tuge, siduge see @oddbird polütäitega. See on koht, kuhu platvorm lõpuks liigub ja sellest saab lõpuks teie lähenemine. Struktureerige DOM ümber. Kasutage seda siis, kui arhitektuur seda lubab ja te ei soovi käitusaja keerukust. Usun, et see on tõenäoliselt kõige alahinnatud variant. Kombineerige mustreid. Tehke seda siis, kui soovite oma peamiseks lähenemisviisiks ankru positsioneerimist, mis on seotud toetamata brauserite jaoks mõeldud JavaScripti tagavaraga. Või DOM-i paigutuse portaal, mis on koordinaatide täpsuse jaoks seotud funktsiooniga getBoundingClientRect().
Järeldus Varem käsitlesin seda viga kui ühekordset probleemi – midagi, mida parandada ja millest edasi liikuda. Kuid kui ma olin sellega piisavalt kaua istunud, et mõista kõiki kolme kaasatud süsteemi – ülevoolulõikamist, kontekstide virnatamist ja plokkide sisaldamist –, ei tundunud see juhuslikult. Sain vaadata rippuvat rippmenüüd ja kohe jälgida, milline esivanem oli selle eest vastutav. See nihe selles, kuidas ma DOM-i lugesin, oli tõeline mulje. Ei ole ühest õiget vastust. See, mille poole ma jõudsin, sõltus sellest, mida ma sain koodibaasis juhtida: portaale, kui esivanemate puu oli ettearvamatu; fikseeritud positsioneerimine, kui see oli puhas ja lihtne; elemendi liigutamine, kui miski mind ei takistanud; ja ankru positsioneerimine kohe,kus saan. Ükskõik, mille lõpuks valite, ärge käsitlege juurdepääsetavust viimase sammuna. Minu kogemuse kohaselt jäetakse see täpselt siis vahele. ARIA suhted, fookuse haldamine, klaviatuuri käitumine – need pole lihvitud. Need on osa sellest, mis paneb asja tegelikult tööle. Vaadake täielikku lähtekoodi minu GitHubi repost. Edasine Lugemine Need on viited, mille juurde ma seda läbi töötades pidevalt tagasi tulin:
Virnastamise kontekst (MDN) "CSS-i ankru positsioneerimise juhend", Juan Diego Rodriguez "Popover API-ga alustamine", Godstime Aburu Ujuv kasutajaliides (floating-ui.com) CSS-i ületäitumine (MDN)