Сценариото е скоро секогаш исто, што е табела со податоци во контејнер што може да се движи. Секој ред има мени за акција, мало паѓачко мени со некои опции, како што се Уреди, Дупликат и Избриши. Ти го градиш, изгледа дека работи совршено изолирано, а потоа некој го става внатре во тој скроллив див и работите се распаѓаат. Ја видов точната грешка во три различни бази на кодови: контејнерот, магацинот и рамката, сите различни. Меѓутоа, грешката е целосно идентична. Паѓачкото мени се отсекува на работ на контејнерот. Или се појавува зад содржината која логично треба да биде под неа. Или работи добро додека корисникот не скролува, а потоа не се префрли. Посегнувате по z-индекс: 9999. Понекогаш помага, но други пати не прави апсолутно ништо. Таа недоследност е првата трага дека нешто подлабоко се случува. Причината поради која постојано се враќа е тоа што се вклучени три одделни системи на прелистувачи, а повеќето програмери го разбираат секој сам по себе, но никогаш не размислуваат што се случува кога сите три ќе се судрат: прелевање, натрупување контексти и содржи блокови.

Откако ќе разберете како сите три комуницираат, режимите на неуспех престануваат да се чувствуваат случајно. Всушност, тие стануваат предвидливи. Трите работи кои всушност го предизвикуваат ова Ајде да ја разгледаме секоја од тие ставки подетално. Проблемот со прелевање Кога ќе поставите прелевање: скриено, прелевање: лизгање или прелевање: автоматски на елемент, прелистувачот ќе исече сè што се протега надвор од неговите граници, вклучително и апсолутно позиционирани потомци. .scroll-container { претекување: автоматско; висина: 300 px; /* Ова ќе го исече паѓачкото мени, точка */ }

паѓачко { позиција: апсолутна; /* Не е важно -- сè уште е исечено од .scroll-container */ }

Тоа ме изненади првиот пат кога налетав. Би ја зазел позицијата: апсолутот би дозволил елементот да избега од исечокот на контејнерот. тоа не. Во пракса, тоа значи дека апсолутно позиционираното мени може да биде отсечено од кој било предок што има невидлива вредност на прелевање, дури и ако тој предок не е блокот што го содржи менито. Сечење и позиционирање се посебни системи. Тие едноставно се судираат на начини кои изгледаат сосема случајно додека не ги разберете и двете.

Еве пример на React со помош на createPortal:

внесете {createPortal } од 'react-dom'; увоз { useState, useEffect, useRef } од 'react';

функција паѓачко ({ anchorRef, isOpen, деца }) { const [позиција, setPosition] = useState({ горе: 0, лево: 0 });

useEffect(() => { ако (isOpen && anchorRef.current) { const rect = anchorRef.current.getBoundingClientRect(); сетПозиција({ врвот: rect.bottom + window.scrollY, лево: rec.left + window.scrollX, }); } }, [isOpen, anchorRef]);

ако (!isOpen) врати null;

врати креирајПортал( <див id = "паѓачко-демо" улога = "мени" className = "паѓачко мени" style={{ position: 'апсолутна', горе: position.top, лево: position.left }} > {деца}

, документ.тело ); }

И, се разбира, не можеме да ја игнорираме пристапноста. Поправените елементи што се појавуваат преку содржината сепак мора да бидат достапни со тастатура. Ако редоследот на фокусот природно не се премести во фиксниот паѓачки список, ќе треба да управувате со него користејќи код. Исто така, вреди да се провери дали не се наоѓа над друга интерактивна содржина без начин да се отфрли. Тој те гризе при тестирање на тастатурата. Позиционирање на сидро CSS: Каде што мислам дека се движи CSS Anchor Positioning е насоката за која најмногу ме интересира во моментов. Не бев сигурен колку од спецификациите беа всушност употребливи кога првпат го погледнав. Тоа ви овозможува да ја објавите врската помеѓу паѓачкото мени и неговото активирање директно во CSS, а прелистувачот се справува со координатите. .активира { сидро-име: --my-тригер; }

.паѓачко мени { позиција: апсолутна; позиција-сидро: --my-тригер; врвот: сидро (долу); лево: сидро (лево); позиција-обиди-резервни: превртување-блок, превртување-во линија; }

Својството position-try-fallbacks е она што вреди да се користи преку рачна пресметка. Прелистувачот пробува алтернативни места пред да се откаже, така што паѓачкото мени на дното на приказот автоматски се превртува нагоре наместо да се прекине. Поддршката на прелистувачите е солидна во прелистувачите базирани на Chromium и расте во Safari. На Firefox му треба полифил. Пакетот за позиционирање @oddbird/css-anchor ги опфаќа основните спецификации. Ги погодив рабовите на распоредот што бараа резервни копии што не ги очекував, затоа третирајте го како прогресивно подобрување или спарете го соРезервно JavaScript за Firefox. Накратко, ветувачко, но сè уште не е универзално. Тестирајте во целните прелистувачи. И што се однесува до пристапноста, декларирањето визуелна врска во CSS не му кажува ништо на дрвото за пристапност. aria-controls, aria-expanded, aria-haspopup - тој дел е сè уште на вас. Понекогаш поправката е само поместување на елементот Пред да посегнам по портал или да направам пресметки за координатите, секогаш прво поставувам едно прашање: Дали овој паѓачки список навистина треба да живее во контејнерот за лизгање? Ако не е така, преместувањето на ознаката во обвивка на повисоко ниво целосно го елиминира проблемот, без JavaScript и без пресметки на координати. Ова не е секогаш можно. Ако копчето и паѓачкото мени се инкапсулирани во истата компонента, поместувањето на едното без другото значи преиспитување на целиот API. Но, кога можете да го направите тоа, нема што да се дебагира. Проблемот едноставно не постои. Што сè уште не го решава модерниот CSS CSS измина долг пат овде, но сè уште има места што ве изневери. Позицијата: проблемите со поправени и трансформирани сè уште се таму. Намерно е во спецификацијата, што значи дека не постои CSS решение. Ако користите библиотека со анимација што го обвива вашиот распоред во трансформиран елемент, повторно ви требаат портали или позиционирање на сидро. CSS Anchor Positioning е ветувачко, но ново. Како што споменавме порано, на Firefox сè уште му треба полифил во моментот кога го пишувам ова. Ги погодив рабовите на распоредот што бараа резервни копии што не ги очекував. Ако ви треба постојано однесување на сите прелистувачи денес, сè уште посегнувате по JavaScript за незгодните делови. Додатокот за кој всушност го променив мојот работен тек е HTML Popover API, сега достапен во сите модерни прелистувачи. Елементите со атрибут popover се прикажуваат во горниот слој на прелистувачот, пред сè, без потреба од позиционирање JavaScript.

Управувањето со бегство, отфрлање-на-клик-надвор и солидна семантика за пристапност се бесплатни за работи како совети за алатки, додатоци за откривање и едноставни преклопувања. Тоа е првата алатка што ја допирам засега. Тоа, рече, не го решава позиционирањето. Го решава слоевитоста. Сè уште ви треба позиционирање на сидро или JavaScript за да го усогласите поповерот со неговиот активирач. Popover API се справува со слоевитоста. Поставувањето сидро се справува со поставувањето. Употребени заедно, тие покриваат поголем дел од она што претходно би сакале да го направите во библиотека. Водич за одлуки за вашата ситуација Откако поминав низ сето ова на потешкиот начин, еве како всушност размислувам за изборот сега.

Користете портал. Јас би го користел ова кога активирањето живее длабоко во вгнездени контејнери за лизгање. Ја користев оваа шема за менија за дејствување на табелата и ја споив со обновување на фокусот и проверки за пристапност. Тоа е најсигурната опција, но буџетско време за дополнителни жици. Користете фиксно позиционирање. Ова е за кога сте во JavaScript од ванила или лесна рамка и може да потврдите дека ниту еден предок не применува трансформации или филтри. Лесно е да се постави и едноставно да се дебагира, се додека важи едното ограничување. Користете го CSS Anchor Positioning. Постигнете го ова кога поддршката од вашиот прелистувач ќе го дозволи тоа. Ако е потребна поддршка за Firefox, спарете ја со полифилот @oddbird. Ова е местото каде што платформата на крајот се движи и на крајот ќе стане вашиот пристап. Реструктуирајте го DOM. Користете го ова кога архитектурата го дозволува тоа и сакате да нема сложеност на времето на работа. Верувам дека тоа е веројатно најпотценетата опција. Комбинирајте обрасци. Направете го ова кога сакате позиционирање на сидро како ваш примарен пристап, поврзан со резервен JavaScript за неподдржани прелистувачи. Или портал за поставување DOM поврзан со getBoundingClientRect() за точност на координатите.

Заклучок Порано ја третирав оваа грешка како еднократен проблем - нешто од кое треба да се закрпи и да продолжи понатаму. Но, штом седнав со него доволно долго за да ги разберам сите три вклучени системи - прелевање клип, редење контексти и содржи блокови - престана да се чувствува случајно. Можев да погледнам во скршена паѓачка листа и веднаш да пронајдам кој предок е одговорен. Таа промена во начинот на кој го читав ДОМ беше вистинската брза помош. Нема единствен точен одговор. Она по што посегнав зависеше од она што можам да го контролирам во базата на кодови: портали кога дрвото на предците беше непредвидливо; фиксно позиционирање кога било чисто и едноставно; поместување на елементот кога ништо не ме спречуваше; и позиционирање на сидрото сега,каде можам. Што и да изберете, не ја третирајте пристапноста како последен чекор. Според моето искуство, тоа е точно кога се прескокнува. Односите на ARIA, управувањето со фокусот, однесувањето на тастатурата - тие не се добри. Тие се дел од она што ја прави работата всушност да функционира. Проверете го целосниот изворен код во моето складиште на GitHub. Понатамошно читање Ова се референците на кои постојано се навраќав додека работев преку ова:

Контекст на редење (MDN) „Водич за позиционирање на сидро CSS“, Хуан Диего Родригез „Започнување со Popover API“, Godstime Aburu Лебдечки интерфејс (floating-ui.com) Прелевање на CSS (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