A forgatókönyv szinte mindig ugyanaz, ami egy adattábla egy görgethető tárolóban. Minden sor rendelkezik egy műveleti menüvel, egy kis legördülő menüvel, ahol néhány beállítás található, például Szerkesztés, Másolás és Törlés. Megépíted, úgy tűnik, elszigetelten tökéletesen működik, aztán valaki beleteszi azt a görgethető divet, és szétesnek a dolgok. Pontosan ezt a hibát három különböző kódbázisban láttam: a tárolóban, a veremben és a keretrendszerben, mindegyik más. A hiba azonban teljesen azonos. A legördülő menü le van vágva a tartály szélén. Vagy olyan tartalom mögött jelenik meg, amelynek logikusan alatta kell lennie. Vagy jól működik, amíg a felhasználó nem görget, aztán elsodródik. A z-indexhez nyúlsz: 9999. Néha segít, máskor viszont egyáltalán nem. Ez a következetlenség az első jel, hogy valami mélyebb dolog történik. Ennek az az oka, hogy ez folyamatosan visszatér, az az, hogy három különálló böngészőrendszerről van szó, és a legtöbb fejlesztő mindegyiket önmagában érti, de soha nem gondol arra, hogy mi történik, ha mindhárom ütközik: túlcsordulás, kontextusok halmozása és blokkok tárolása.
Ha megérti, hogyan működik mindhárom kölcsönhatás, a hibamódok megszűnnek véletlenszerűnek lenni. Valójában kiszámíthatóvá válnak. A három dolog, ami ezt valójában okozza Nézzük meg mindegyik elemet részletesen. A túlcsordulási probléma Ha egy elemen beállítja a túlcsordulást: rejtett, túlcsordulás: görgetés vagy túlcsordulás: automatikus, a böngésző mindent levág, ami túlmutat a határain, beleértve az abszolút pozicionált leszármazottakat is. .scroll-container { túlcsordulás: auto; magasság: 300 képpont; /* Ezzel levágja a legördülő listát, pont */ }
.dropdown { pozíció: abszolút; /* Nem számít -- még mindig a .scroll-container vágta le */ }
Ez meglepett, amikor először belefutottam. Azt feltételeztem, hogy az abszolút lehetővé teszi, hogy egy elem elkerülje a tároló kivágását. Nem. A gyakorlatban ez azt jelenti, hogy egy abszolút pozicionált menüt bármely nem látható túlcsordulási értékkel rendelkező ős levághat, még akkor is, ha az ős nem a menüt tartalmazó blokk. A vágás és a pozicionálás külön rendszer. Csak véletlenszerűen ütköznek egymásnak egészen addig, amíg mindkettőt megérted.
Íme egy React példa a createPortal használatával:
import { createPortal } from 'react-dom'; import { useState, useEffect, useRef } from 'react';
function Dropdown({ anchorRef, isOpen, children }) { const [pozíció, setPosition] = useState({ top: 0, left: 0 });
useEffect(() => { if (isOpen && anchorRef.current) { const rect = anchorRef.current.getBoundingClientRect(); setPosition({ felül: rect.bottom + window.scrollY, balra: rect.left + window.scrollX, }); } }, [isOpen, anchorRef]);
if (!isOpen) return null;
return createPortal(
És természetesen nem hagyhatjuk figyelmen kívül az akadálymentesítést sem. A tartalom felett megjelenő rögzített elemeknek továbbra is billentyűzettel elérhetőknek kell lenniük. Ha a fókuszsorrend természetesen nem kerül be a rögzített legördülő menübe, akkor kód segítségével kell kezelnie. Azt is érdemes ellenőrizni, hogy ne üljön felül más interaktív tartalommal, és ne utasítsa el. Ez megharap a billentyűzet tesztelése során. CSS horgonypozícionálás: Ahová szerintem ez vezet A CSS Anchor Positioning az az irány, amely jelenleg a legjobban érdekel. Amikor először megnéztem, nem voltam benne biztos, hogy a specifikációból mennyi volt ténylegesen használható. Lehetővé teszi a kapcsolat deklarálását a legördülő menü és a triggere között közvetlenül a CSS-ben, és a böngésző kezeli a koordinátákat. .trigger { horgonynév: --my-trigger; }
.dropdown-menu { pozíció: abszolút; pozíció-horgony: --my-trigger; felső: horgony(alul); balra: horgony(bal); pozíció-próbálkozás-visszaesések: flip-block, flip-inline; }
A position-try-fallbacks tulajdonság miatt érdemes ezt manuális számítással szemben használni. A böngésző alternatív elhelyezésekkel próbálkozik, mielőtt feladná, így a nézetablak alján lévő legördülő menü automatikusan felfelé csúszik ahelyett, hogy levágna. A böngésző támogatása szilárd a Chromium-alapú böngészőkben, és egyre növekszik a Safariban. A Firefoxnak polifillre van szüksége. Az @oddbird/css-anchor-positioning csomag lefedi az alapvető specifikációkat. Eltaláltam vele olyan elrendezési szélső eseteket, amelyek olyan visszaeséseket igényeltek, amelyekre nem számítottam, ezért kezelje progresszív fejlesztésként, vagy párosítsa egyJavaScript tartalék Firefoxhoz. Röviden, ígéretes, de még nem univerzális. Tesztelje a célböngészőket. Ami pedig az akadálymentesítést illeti, a vizuális kapcsolat CSS-ben való deklarálása nem mond semmit az akadálymentesítési fának. aria-controls, aria-expanded, aria-haspopup – ez a rész még mindig rajtad áll. Néha a javítás csak az elem mozgatása Mielőtt egy portálhoz nyúlnék, vagy koordinátaszámításokat végeznék, először mindig felteszek egy kérdést: ennek a legördülő menünek valóban a görgetőtárolóban kell lennie? Ha nem, akkor a jelölés magasabb szintű burkolóba való áthelyezése teljesen kiküszöböli a problémát, JavaScript és koordináta-számítások nélkül. Ez nem mindig lehetséges. Ha a gomb és a legördülő menü ugyanabba az összetevőbe van beépítve, az egyik mozgatása a másik nélkül a teljes API újragondolását jelenti. De amikor megteheti, nincs mit hibakeresnie. A probléma egyszerűen nem létezik. Amit a modern CSS még mindig nem old meg A CSS hosszú utat tett meg itt, de még mindig vannak helyek, amelyek csalódást okoznak. Az álláspont: a rögzített és az átalakítási problémák továbbra is fennállnak. Szándékosan szerepel a specifikációban, ami azt jelenti, hogy nem létezik CSS-megkerülő megoldás. Ha olyan animációs könyvtárat használ, amely átalakított elembe burkolja az elrendezést, akkor ismét portálokra vagy horgonypozícionálásra van szüksége. A CSS Anchor Positioning ígéretes, de új. Ahogy korábban említettük, a Firefoxnak még mindig szüksége van egy polifilre, amikor ezt írom. Eltaláltam vele az elrendezési éles eseteket, amelyek olyan visszaeséseket igényeltek, amelyekre nem számítottam. Ha ma egységes viselkedésre van szüksége az összes böngészőben, akkor is a JavaScripthez nyúl a trükkös részekhez. Az a kiegészítés, amelyre megváltoztattam a munkafolyamatot, a HTML Popover API, amely már minden modern böngészőben elérhető. A popover attribútummal rendelkező elemek mindenek felett a böngésző legfelső rétegében jelennek meg, JavaScript-pozicionálás nélkül.
Az Escape kezelés, az elvetés kattintással kívülről és a szilárd akadálymentesítési szemantika ingyenesen elérhető olyan dolgokhoz, mint például az eszköztippek, közzétételi modulok és egyszerű fedvények. Ez az első eszköz, amihez most nyúlok. Ez azt jelenti, hogy nem oldja meg a pozicionálást. Megoldja a rétegezést. Továbbra is szükség van a horgonypozícionálásra vagy a JavaScriptre, hogy a felugró ablakot az indítóhoz igazítsa. A Popover API kezeli a rétegezést. A horgony elhelyezése kezeli az elhelyezést. Együtt használva lefedik a legtöbbet annak, amit korábban egy könyvtárhoz nyúlt volna. Döntési útmutató az Ön helyzetéhez Miután végigmentem mindezen a kemény úton, most a következőképpen gondolkodom a választásról.
Használjon portált. Ezt akkor használnám, ha az eseményindító mélyen beágyazott görgetőtárolókban van. Ezt a mintát az asztali műveletmenükhöz használtam, és párosítottam a fókusz visszaállításával és a hozzáférhetőség ellenőrzésével. Ez a legmegbízhatóbb lehetőség, de az extra vezetékezéshez időt kell fordítani. Használjon rögzített pozicionálást. Ez arra az esetre vonatkozik, ha vanília JavaScriptet vagy könnyű keretrendszert használ, és ellenőrizheti, hogy az elődök nem alkalmaznak átalakításokat vagy szűrőket. Egyszerű a beállítása és egyszerű a hibakeresés, mindaddig, amíg ez az egyetlen megkötés fennáll. Használja a CSS horgonypozícionálást. Érje el ezt, ha a böngésző támogatása lehetővé teszi. Ha Firefox támogatásra van szükség, párosítsa az @oddbird polifill-lel. Ez az a hely, ahová a platform végső soron halad, és végül ez lesz az Ön által választott megközelítés. Szerkezze újra a DOM-ot. Használja ezt, ha az architektúra lehetővé teszi, és nulla futásidejű bonyolultságot szeretne. Szerintem ez a leginkább alulértékelt lehetőség. Kombinálja a mintákat. Tegye ezt, ha a horgonypozícionálást szeretné elsődleges megközelítésként használni, párosítva a JavaScript tartalékkal a nem támogatott böngészőkhöz. Vagy egy portál DOM-elhelyezéshez a getBoundingClientRect()-el párosítva a koordinátapontosság érdekében.
Következtetés Korábban ezt a hibát egyszeri problémaként kezeltem – javítani kell, és tovább kell lépni. De miután elég sokáig ültem vele, hogy megértsem mindhárom érintett rendszert – a túlcsordulási kivágást, a kontextusok halmozását és a blokkok tárolását –, megszűnt a véletlenszerűség érzése. Meg tudtam nézni egy törött legördülő listát, és azonnal nyomon követhettem, melyik ős a felelős. Ez a változás abban, ahogyan a DOM-ot olvastam, volt az igazi elvihető. Nincs egyetlen helyes válasz. Hogy mire nyúltam, az attól függött, hogy mit tudtam irányítani a kódbázisban: portálokat, amikor az ősfa kiszámíthatatlan volt; rögzített pozicionálás, amikor tiszta és egyszerű volt; mozgassa az elemet, amikor semmi sem állított meg; és rögzítse a horgonyt most,ahol tudok. Bármit is választ, ne tekintse az akadálymentesítést az utolsó lépésnek. Tapasztalataim szerint pontosan ilyenkor kerül kihagyásra. Az ARIA kapcsolatok, a fókuszkezelés, a billentyűzet viselkedése – ezek nem finomak. Részei annak, amitől a dolog ténylegesen működik. Tekintse meg a teljes forráskódot a GitHub-tárhelyemben. További olvasás Ezek azok a hivatkozások, amelyekre folyamatosan visszatértem, miközben dolgoztam:
A halmozási kontextus (MDN) „CSS horgonypozícionálási útmutató”, Juan Diego Rodriguez „Kezdő lépések a Popover API-val”, Godstime Aburu Lebegő felhasználói felület (floating-ui.com) CSS túlcsordulás (MDN)