Scenarij je skoraj vedno enak, to je podatkovna tabela znotraj vsebnika, ki ga je mogoče premikati. Vsaka vrstica ima meni z dejanji, majhen spustni meni z nekaj možnostmi, kot so Uredi, Podvoji in Izbriši. Sestaviš ga, zdi se, da deluje popolnoma izolirano, potem pa ga nekdo vstavi v ta div, po katerem se lahko premika, in stvari razpadejo. Videl sem natančno to napako v treh različnih kodnih bazah: vsebniku, skladu in ogrodju, vse različne. Napaka pa je popolnoma enaka. Spustni meni se striže na robu vsebnika. Ali pa se prikaže za vsebino, ki bi logično morala biti pod njim. Ali pa deluje dobro, dokler se uporabnik ne pomakne, nato pa se premakne. Posežete po z-indeksu: 9999. Včasih pomaga, drugič pa popolnoma nič. Ta nedoslednost je prvi znak, da se dogaja nekaj globljega. Razlog, da se vedno znova vrača, je, da so vključeni trije ločeni sistemi brskalnika in večina razvijalcev razume vsakega posebej, vendar nikoli ne pomisli, kaj se zgodi, ko vsi trije trčijo: prelivanje, zlaganje kontekstov in vsebni bloki.
Ko razumete, kako vsi trije medsebojno delujejo, načini napak ne bodo več naključni. Pravzaprav postanejo predvidljivi. Tri stvari, ki to dejansko povzročajo Oglejmo si vsakega od teh predmetov podrobno. Problem prelivanja Ko za element nastavite overflow: hidden, overflow: scroll ali overflow: auto, bo brskalnik izrezal vse, kar sega čez njegove meje, vključno z absolutno pozicioniranimi potomci. .scroll-container { preliv: avto; višina: 300px; /* To bo izrezalo spustni meni, pika */ }
.dropdown { položaj: absolutno; /* Ni pomembno -- še vedno obrezano z .scroll-container */ }
To me je presenetilo, ko sem prvič naletel nanj. Zavzel sem se za položaj: absolutno bi elementu omogočil, da uide izrezku vsebnika. Ne gre. V praksi to pomeni, da lahko absolutno pozicioniran meni odreže kateri koli prednik, ki ima nevidno vrednost prelivanja, tudi če ta prednik ni blok, ki vsebuje meni. Izrezovanje in pozicioniranje sta ločena sistema. Samo zgodi se, da trčita na načine, ki so videti popolnoma naključni, dokler ne razumete obeh.
Tukaj je primer Reacta z uporabo createPortal:
import { createPortal } from 'react-dom'; import { useState, useEffect, useRef } iz 'react';
funkcija Dropdown({ anchorRef, isOpen, children}) { const [position, setPosition] = useState({ top: 0, left: 0 });
useEffect(() => { if (isOpen && anchorRef.current) { const rect = anchorRef.current.getBoundingClientRect(); setPosition({ zgoraj: rect.bottom + window.scrollY, levo: rect.left + window.scrollX, }); } }, [isOpen, anchorRef]);
if (!isOpen) vrne nič;
vrni createPortal(
In seveda ne moremo zanemariti dostopnosti. Fiksni elementi, ki se pojavljajo nad vsebino, morajo biti še vedno dosegljivi s tipkovnico. Če se vrstni red fokusa naravno ne premakne v fiksni spustni meni, ga boste morali upravljati s kodo. Prav tako je vredno preveriti, da ne stoji nad drugo interaktivno vsebino in je ni mogoče zavrniti. Ta te ugrizne pri testiranju tipkovnice. Pozicioniranje sidra CSS: Kam mislim, da to pelje CSS Anchor Positioning je smer, ki me trenutno najbolj zanima. Ko sem ga prvič pogledal, nisem bil prepričan, koliko specifikacij je dejansko uporabnih. Omogoča vam, da razglasite razmerje med spustnim menijem in njegovim sprožilcem neposredno v CSS, brskalnik pa obravnava koordinate. .trigger { ime-sidra: --moj-sprožilec; }
.spustni meni { položaj: absolutno; položaj-sidra: --my-trigger; zgoraj: sidro (spodaj); levo: sidro (levo); nadomestni poskusi položaja: flip-block, flip-inline; }
Lastnost position-try-fallbacks je tisto, zaradi česar je vredno uporabiti to namesto ročnega izračuna. Brskalnik poskusi z alternativnimi umestitvami, preden odneha, zato se spustni meni na dnu vidnega polja samodejno obrne navzgor, namesto da bi bil odrezan. Podpora za brskalnike je solidna v brskalnikih, ki temeljijo na Chromiumu, v Safariju pa raste. Firefox potrebuje polifill. Paket @oddbird/css-anchor-positioning pokriva osnovne specifikacije. Z njim sem dosegel robne primere postavitve, ki so zahtevali nadomestne možnosti, ki jih nisem pričakoval, zato ga obravnavajte kot progresivno izboljšavo ali ga združite zNadomestni JavaScript za Firefox. Skratka, obetavno, a še ne univerzalno. Preizkusite v ciljnih brskalnikih. In kar zadeva dostopnost, razglasitev vizualnega odnosa v CSS drevesu dostopnosti ne pove ničesar. aria-controls, aria-expanded, aria-haspopup — ta del je še vedno na vas. Včasih je popravek samo premik elementa Preden posežem po portalu ali naredim koordinatne izračune, vedno najprej vprašam eno vprašanje: Ali mora ta spustni meni dejansko živeti znotraj vsebnika drsenja? Če se ne zgodi, premaknite oznako v ovoj na višji ravni v celoti odpravite težavo, brez JavaScripta in izračunov koordinat. To ni vedno mogoče. Če sta gumb in spustni meni vključena v isto komponento, premikanje enega brez drugega pomeni premislek o celotnem API-ju. Toda ko lahko to storite, ni ničesar za odpravljanje napak. Težava preprosto ne obstaja. Česa sodobni CSS še vedno ne rešuje CSS je tu že daleč napredoval, vendar vas še vedno na nekaterih mestih razočara. Stališče: težave s popravljenimi in preoblikovanimi so še vedno prisotne. V specifikaciji je namerno, kar pomeni, da ne obstaja rešitev CSS. Če uporabljate knjižnico animacij, ki vašo postavitev ovije v preoblikovan element, spet potrebujete portale ali pozicioniranje sidra. CSS Anchor Positioning je obetavno, a novo. Kot sem že omenil, Firefox v času, ko to pišem, še vedno potrebuje polifill. Z njim sem dosegel robne primere postavitve, ki so zahtevali nadomestne možnosti, ki jih nisem pričakoval. Če danes potrebujete dosledno delovanje v vseh brskalnikih, še vedno posegate po JavaScriptu za zapletene dele. Dodatek, za katerega sem dejansko spremenil svoj potek dela, je HTML Popover API, ki je zdaj na voljo v vseh sodobnih brskalnikih. Elementi z atributom popover se upodabljajo v zgornji plasti brskalnika, nad vsem, brez potrebe po pozicioniranju JavaScripta.
Obdelava pobegov, opustitev ob kliku zunaj in trdna semantika dostopnosti so na voljo brezplačno za stvari, kot so namigi orodij, pripomočki za razkritje in preprosta prekrivanja. To je prvo orodje, ki ga zdaj posežem. Kljub temu ne rešuje pozicioniranja. Rešuje plastenje. Še vedno potrebujete pozicioniranje sidra ali JavaScript, da poravnate pojavni prikaz z njegovim sprožilcem. Popover API skrbi za plastenje. Pozicioniranje sidra ureja postavitev. Če jih uporabljate skupaj, pokrivajo večino tega, kar bi prej dosegli za knjižnico. Vodnik za odločanje za vašo situacijo Potem ko sem šel skozi vse to na težji način, zdaj takole dejansko razmišljam o izbiri.
Uporabite portal. To bi uporabil, ko bi sprožilec živel globoko v ugnezdenih vsebnikih drsenja. Ta vzorec sem uporabil za menije dejanj tabele in ga združil z obnovitvijo fokusa in pregledi dostopnosti. To je najbolj zanesljiva možnost, vendar si zagotovite čas za dodatno ožičenje. Uporabite fiksno pozicioniranje. To je za takrat, ko uporabljate JavaScript ali lahek okvir in lahko preverite, ali noben prednik ne uporablja transformacij ali filtrov. Enostavno ga je nastaviti in preprosto odpravljati napake, če le ta omejitev velja. Uporabite CSS Anchor Positioning. Posezite po tem, ko podpora vašega brskalnika to omogoča. Če je potrebna podpora za Firefox, jo združite z @oddbird polyfill. To je smer, kamor se končno usmeri platforma in bo sčasoma postala vaš glavni pristop. Prestrukturirajte DOM. Uporabite to, ko arhitektura to dopušča in želite ničelno kompleksnost izvajalnega časa. Verjamem, da je to verjetno najbolj podcenjena možnost. Kombinirajte vzorce. Naredite to, če želite pozicioniranje sidra kot svoj primarni pristop v kombinaciji z nadomestnim JavaScriptom za nepodprte brskalnike. Ali portal za postavitev DOM v paru z getBoundingClientRect() za natančnost koordinat.
Zaključek Včasih sem to napako obravnaval kot enkratno težavo – nekaj, kar je treba popraviti in nadaljevati. Toda ko sem sedel z njim dovolj dolgo, da sem razumel vse tri vpletene sisteme - izrezovanje prelivanja, zlaganje kontekstov in vsebovalne bloke - se ni več počutil naključno. Lahko bi pogledal pokvarjen spustni meni in takoj izsledil, kateri prednik je bil odgovoren. Ta sprememba v tem, kako sem bral DOM, je bil pravi zaključek. Ni enega samega pravilnega odgovora. Kaj sem dosegel, je bilo odvisno od tega, kaj sem lahko nadzoroval v kodni bazi: portali, ko je bilo drevo prednikov nepredvidljivo; fiksno pozicioniranje, ko je bilo čisto in preprosto; premikanje elementa, ko me nič ni ustavilo; in pozicioniranje sidra zdaj,kjer lahko. Karkoli boste na koncu izbrali, dostopnosti ne obravnavajte kot zadnji korak. Po mojih izkušnjah je ravno takrat, ko se preskoči. Odnosi ARIA, upravljanje fokusa, obnašanje tipkovnice - to ni dovršeno. So del tega, zaradi česar stvar dejansko deluje. Oglejte si celotno izvorno kodo v mojem skladišču GitHub. Nadaljnje branje To so reference, h katerim sem se nenehno vračal, ko sem delal na tem:
Kontekst zlaganja (MDN) »Vodnik za pozicioniranje sidra CSS«, Juan Diego Rodriguez “Kako začeti z API-jem Popover”, Godstime Aburu Plavajoči uporabniški vmesnik (floating-ui.com) CSS Overflow (MDN)