Het scenario is bijna altijd hetzelfde: een gegevenstabel in een schuifbare container. Elke rij heeft een actiemenu, een kleine vervolgkeuzelijst met enkele opties, zoals Bewerken, Dupliceren en Verwijderen. Je bouwt het, het lijkt perfect geïsoleerd te werken, en dan stopt iemand het in die scrollbare div en alles valt uit elkaar. Ik heb deze exacte bug in drie verschillende codebases gezien: de container, de stapel en het raamwerk, allemaal verschillend. De bug is echter volledig identiek. De vervolgkeuzelijst wordt aan de rand van de container afgekapt. Of het verschijnt achter inhoud die er logischerwijs onder zou moeten staan. Of het werkt prima totdat de gebruiker scrollt, en dan drijft het af. Je bereikt z-index: 9999. Soms helpt het, maar soms doet het helemaal niets. Die inconsistentie is de eerste aanwijzing dat er iets diepers aan de hand is. De reden dat het steeds terugkomt is dat er drie afzonderlijke browsersystemen bij betrokken zijn, en de meeste ontwikkelaars begrijpen elk afzonderlijk browsersysteem, maar denken nooit na over wat er gebeurt als ze alle drie botsen: overflow, het stapelen van contexten en het bevatten van blokken.

Als je eenmaal begrijpt hoe alle drie op elkaar inwerken, voelen de faalmodi niet langer willekeurig aan. Sterker nog, ze worden voorspelbaar. De drie dingen die dit feitelijk veroorzaken Laten we elk van deze items in detail bekijken. Het overloopprobleem Wanneer u overflow: verborgen, overflow: scrollen of overflow: auto instelt op een element, knipt de browser alles af dat buiten de grenzen valt, inclusief absoluut gepositioneerde afstammelingen. .scroll-container { overloop: automatisch; hoogte: 300px; /* Hierdoor wordt de vervolgkeuzelijst geknipt, punt */ }

.dropdown { positie: absoluut; /* Maakt niet uit - nog steeds geknipt door .scroll-container */ }

Dat verbaasde mij toen ik er voor het eerst mee in aanraking kwam. Ik had een standpunt ingenomen: absoluut zou een element aan de clipping van een container laten ontsnappen. Dat is niet het geval. In de praktijk betekent dit dat een absoluut gepositioneerd menu kan worden afgesloten door elke voorloper die een niet-zichtbare overloopwaarde heeft, zelfs als die voorouder niet het blok is dat het menu bevat. Clippen en positioneren zijn afzonderlijke systemen. Ze komen toevallig met elkaar in botsing op een manier die volkomen willekeurig lijkt, totdat je beide begrijpt.

Hier is een React-voorbeeld met createPortal:

importeer { createPortal } uit 'react-dom'; import { useState, useEffect, useRef } van 'reageren';

function Dropdown({ anchorRef, isOpen, kinderen }) { const [positie, setPositie] = useState({boven: 0, links: 0 });

gebruikEffect(() => { if (isOpen && anchorRef.current) { const rect = anchorRef.current.getBoundingClientRect(); setPositie({ boven: rect.onder + venster.scrollY, links: rect.left + window.scrollX, }); } }, [isOpen, anchorRef]);

if (!isOpen) retourneert null;

return createPortal(

, document.body ); }

En natuurlijk kunnen we de toegankelijkheid niet negeren. Vaste elementen die over de inhoud heen verschijnen, moeten nog steeds via het toetsenbord bereikbaar zijn. Als de focusvolgorde niet op natuurlijke wijze naar de vaste vervolgkeuzelijst wordt verplaatst, moet u deze beheren met behulp van code. Het is ook de moeite waard om te controleren of het niet boven andere interactieve inhoud staat en het op geen enkele manier kan negeren. Die bijt je bij het testen van toetsenborden. CSS-ankerpositionering: waar ik denk dat dit naartoe gaat CSS-ankerpositionering is de richting waarin ik momenteel het meest geïnteresseerd ben. Toen ik er voor het eerst naar keek, wist ik niet zeker hoeveel van de specificaties daadwerkelijk bruikbaar waren. Hiermee kunt u de relatie tussen een vervolgkeuzelijst en de trigger rechtstreeks in CSS declareren, terwijl de browser de coördinaten verwerkt. .trigger { ankernaam: --mijn-trigger; }

.dropdownmenu { positie: absoluut; positie-anker: --mijn-trigger; boven: anker(onder); links: anker(links); positie-try-fallbacks: flip-block, flip-inline; }

De eigenschap position-try-fallbacks maakt dit de moeite waard om te gebruiken in plaats van een handmatige berekening. De browser probeert alternatieve plaatsingen voordat hij het opgeeft, dus een vervolgkeuzelijst onder aan de viewport klapt automatisch naar boven in plaats van te worden afgesneden. Browserondersteuning is solide in Chromium-gebaseerde browsers en groeit in Safari. Firefox heeft een polyfill nodig. Het @oddbird/css-anchor-positioning-pakket dekt de kernspecificaties. Ik ben er randgevallen mee tegengekomen die terugval vereisten die ik niet had verwacht, dus beschouw het als een progressieve verbetering of combineer het met eenJavaScript-fallback voor Firefox. Kortom veelbelovend maar nog niet universeel. Test in uw doelbrowser. En wat de toegankelijkheid betreft, vertelt het declareren van een visuele relatie in CSS niets aan de toegankelijkheidsboom. aria-controls, aria-expanded, aria-haspopup - dat deel is nog steeds voor jou. Soms is de oplossing gewoon het verplaatsen van het element Voordat ik naar een portaal ga of coördinatenberekeningen maak, stel ik altijd eerst één vraag: moet deze vervolgkeuzelijst eigenlijk in de scrollcontainer staan? Als dit niet het geval is, wordt het probleem volledig geëlimineerd door de markup naar een wrapper op een hoger niveau te verplaatsen, zonder JavaScript en zonder coördinatenberekeningen. Dit is niet altijd mogelijk. Als de knop en de vervolgkeuzelijst in hetzelfde onderdeel zijn ingekapseld, betekent het verplaatsen van de ene zonder de andere dat de hele API opnieuw moet worden bekeken. Maar als je het kunt, valt er niets te debuggen. Het probleem bestaat gewoon niet. Wat moderne CSS nog steeds niet oplost CSS heeft hier een lange weg afgelegd, maar er zijn nog steeds plaatsen waar het je in de steek laat. Het standpunt: opgeloste en transformatieproblemen zijn er nog steeds. Het staat opzettelijk in de specificatie, wat betekent dat er geen CSS-oplossing bestaat. Als u een animatiebibliotheek gebruikt die uw lay-out in een getransformeerd element verpakt, heeft u weer portalen of ankerpositionering nodig. CSS-ankerpositionering is veelbelovend, maar nieuw. Zoals eerder vermeld heeft Firefox op het moment dat ik dit schrijf nog steeds een polyfill nodig. Ik heb er lay-out-randgevallen mee tegengekomen die terugval vereisten die ik niet had verwacht. Als je tegenwoordig consistent gedrag in alle browsers nodig hebt, grijp je nog steeds naar JavaScript voor de lastige delen. De toevoeging waarvoor ik mijn workflow daadwerkelijk heb veranderd, is de HTML Popover API, nu beschikbaar in alle moderne browsers. Elementen met het popover-attribuut worden in de bovenste laag van de browser weergegeven, boven alles, zonder dat JavaScript-positionering nodig is.

Ontsnappen, negeren bij klikken naar buiten en solide toegankelijkheidssemantiek zijn gratis voor zaken als tooltips, openbaarmakingswidgets en eenvoudige overlays. Het is voorlopig het eerste hulpmiddel dat ik bereik. Dat gezegd hebbende, het lost de positionering niet op. Het lost gelaagdheid op. U hebt nog steeds ankerpositionering of JavaScript nodig om een ​​popover uit te lijnen met de trigger. De Popover API zorgt voor de gelaagdheid. Ankerpositionering zorgt voor de plaatsing. Als je ze samen gebruikt, dekken ze het grootste deel van wat je voorheen voor een bibliotheek zou doen. Een beslissingsgids voor uw situatie Nadat ik dit allemaal op de moeilijke manier heb meegemaakt, denk ik nu als volgt over de keuze.

Gebruik een portaal. Ik zou dit gebruiken als de trigger diep in geneste scrollcontainers leeft. Ik heb dit patroon gebruikt voor tabelactiemenu's en gecombineerd met focusherstel en toegankelijkheidscontroles. Het is de meest betrouwbare optie, maar budget tijd voor de extra bedrading. Gebruik een vaste positionering. Dit is bedoeld als u standaard JavaScript of een lichtgewicht raamwerk gebruikt en kunt verifiëren dat geen enkele voorouder transformaties of filters toepast. Het is eenvoudig in te stellen en eenvoudig te debuggen, zolang die ene beperking maar geldt. Gebruik CSS Anchor Positioning. Reik hiervoor wanneer uw browserondersteuning dit toestaat. Als Firefox-ondersteuning vereist is, koppel deze dan aan de @oddbird polyfill. Dit is waar het platform uiteindelijk naartoe gaat en uiteindelijk jouw go-to-aanpak zal worden. Herstructureer de DOM. Gebruik dit wanneer de architectuur dit toestaat en u geen runtime-complexiteit wilt. Ik denk dat dit waarschijnlijk de meest onderschatte optie is. Combineer patronen. Doe dit als u ankerpositionering als uw primaire aanpak wilt, gecombineerd met een JavaScript-fallback voor niet-ondersteunde browsers. Of een portal voor DOM-plaatsing gecombineerd met getBoundingClientRect() voor coördinatennauwkeurigheid.

Conclusie Vroeger behandelde ik deze bug als een eenmalig probleem, iets dat ik moest patchen en verder kon gaan. Maar toen ik er lang genoeg mee bezig was om alle drie de betrokken systemen te begrijpen – overflow-clipping, het stapelen van contexten en het bevatten van blokken – voelde het niet langer willekeurig aan. Ik kon naar een kapotte vervolgkeuzelijst kijken en onmiddellijk nagaan welke voorouder verantwoordelijk was. Die verandering in de manier waarop ik de DOM las, was de echte afhaalmaaltijd. Er is niet één juist antwoord. Waar ik naar streefde, hing af van wat ik kon controleren in de codebase: portalen als de voorouderboom onvoorspelbaar was; vaste positionering als het schoon en eenvoudig was; het element verplaatsen terwijl niets mij tegenhield; en ankerpositionering nu,waar ik kan. Wat u ook kiest, beschouw toegankelijkheid niet als de laatste stap. In mijn ervaring is dat precies het moment waarop het wordt overgeslagen. De ARIA-relaties, het focusbeheer, het toetsenbordgedrag – die zijn niet gepolijst. Ze maken deel uit van wat ervoor zorgt dat het ding echt werkt. Bekijk de volledige broncode in mijn GitHub-repository. Verder lezen Dit zijn de referenties waar ik steeds op terugkwam terwijl ik hieraan werkte:

De stapelcontext (MDN) “CSS-ankerpositioneringsgids”, Juan Diego Rodriguez “Aan de slag met de Popover API”, Godstime Aburu Zwevende gebruikersinterface (floating-ui.com) CSS-overloop (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