Сценарий әрқашан дерлік бірдей, ол айналдырылатын контейнердегі деректер кестесі болып табылады. Әрбір жолда әрекет мәзірі, Өңдеу, Көшірме және Жою сияқты кейбір опциялары бар шағын ашылмалы тізім бар. Сіз оны жасайсыз, ол оқшауланған түрде жақсы жұмыс істейтін сияқты, содан кейін біреу оны айналдырылатын div ішіне қояды және заттар бұзылады. Мен бұл қатені үш түрлі код базасында көрдім: контейнер, стек және фреймворк, барлығы әртүрлі. Қате, дегенмен, мүлдем бірдей.
Ашылмалы тізім контейнердің шетінде кесіледі. Немесе ол логикалық түрде оның астында болуы керек мазмұнның артында көрсетіледі. Немесе ол пайдаланушы айналдырмайынша жақсы жұмыс істейді, содан кейін ол жылжиды.
Сіз z-индексіне қол жеткізесіз: 9999. Кейде бұл көмектеседі, бірақ басқа уақытта ол мүлдем ештеңе жасамайды. Бұл сәйкессіздік - тереңірек нәрсе болып жатқанының алғашқы белгісі.
Оның қайта оралуының себебі - үш бөлек браузер жүйесі жұмыс істейді және әзірлеушілердің көпшілігі әрқайсысын өз бетінше түсінеді, бірақ үшеуі соқтығысқанда не болатынын ешқашан ойламайды: толып кету, контексттерді жинақтау және блоктарды қамту.
Үшеуінің өзара қалай әрекет ететінін түсінгеннен кейін, сәтсіздік режимдері кездейсоқ сезінуді тоқтатады. Шындығында, олар болжамды болады.
Бұған шын мәнінде себеп болатын үш нәрсе
Осы заттардың әрқайсысын егжей-тегжейлі қарастырайық.
Толып кету мәселесі
Элементте overflow: hidden, overflow: scroll немесе overflow: auto параметрлерін орнатқанда, шолғыш оның шегінен шығатын кез келген нәрсені, соның ішінде абсолютті орналасқан ұрпақтарды қиып алады.
.scroll-контейнер {
толып кету: авто;
биіктігі: 300px;
/* Бұл ашылмалы тізімді, нүктені кесіп тастайды */
}
.аспап {
позициясы: абсолютті;
/* Маңызды емес -- әлі де .scroll-container арқылы қиылған */
}
Бұл мені бірінші рет кездестіргенімде таң қалдырды. Мен позицияны қабылдадым: абсолютті элемент контейнердің кесілуінен құтылуға мүмкіндік береді. Болмайды.
Іс жүзінде бұл абсолютті орналастырылған мәзірді көрінбейтін асып кету мәні бар кез келген ата-баба кесіп тастауы мүмкін дегенді білдіреді, тіпті бұл ата-баба мәзірдің блогы болмаса да. Қиып алу және орналастыру бөлек жүйелер. Сіз екеуін де түсінгенге дейін олар кездейсоқ көрінетін жолдармен соқтығысады.
Мұнда createPortal көмегімен реакция үлгісі берілген:
'react-dom' ішінен { createPortal } импорттау;
'react' ішінен { useState, useEffect, useRef} импорттау;
функция ашылмалы тізім({ anchorRef, isOpen, балалар }) {
const [позиция, setPosition] = useState({жоғарғы: 0, сол жақта: 0});
useEffect(() => {
егер (isOpen && anchorRef.current) {
const rect = anchorRef.current.getBoundingClientRect();
setPosition({
жоғарғы: rect.bottom + window.scrollY,
сол жақ: rect.left + window.scrollX,
});
}
}, [isOpen, anchorRef]);
егер (!isOpen) нөлді қайтарады;
CreatePortal(
<бөл
id = "ашылмалы-демо"
рөл = "мәзір"
className = "ашылмалы мәзір"
style={{позиция: 'абсолют', жоғарғы:позиция.жоғарғы, сол жақта:позиция.сол }}
>
{балалар}
,
құжат.дене
);
}
Және, әрине, біз қол жетімділікті елемеуге болмайды. Мазмұнның үстінде пайда болатын бекітілген элементтер әлі де пернетақта арқылы қол жетімді болуы керек. Фокус реті табиғи түрде бекітілген ашылмалы тізімге ауыспаса, оны код арқылы басқару керек. Сондай-ақ, оның басқа интерактивті мазмұнға сәйкес келмейтінін тексерген жөн, оны жоққа шығаруға болмайды. Бұл пернетақтаны тексеру кезінде сізді тістейді.
CSS зәкірінің орналасуы: менің ойымша, бұл бағыт
CSS анкерлік позициялау - мені қазір ең қызықтыратын бағыт. Мен оны бірінші рет қараған кезде оның қаншалықты нақты қолдануға болатынын білмедім. Ол ашылмалы тізім мен оның триггері арасындағы қатынасты тікелей CSS ішінде жариялауға мүмкіндік береді және шолғыш координаттарды өңдейді.
.триггер {
якорь-аты: --my-триггер;
}
Pozisyon-try-fallbacks қасиеті - бұл қолмен есептеуде қолдануға тұрарлық етеді. Браузер бас тартпас бұрын балама орналастыруларды қолданып көреді, сондықтан көру терезесінің төменгі жағындағы ашылмалы тізім үзілудің орнына автоматты түрде жоғары қарай бұрылады.
Браузерді қолдау Chromium негізіндегі браузерлерде берік және Safari-де өсуде. Firefox-қа политолтыру қажет. @oddbird/css-anchor-positioning пакеті негізгі спецификацияны қамтиды. Мен онымен мен күтпеген резервтерді қажет ететін макеттің шеткі жағдайларына тап болдым, сондықтан оны прогрессивті жақсарту ретінде қарастырыңыз немесе оныFirefox үшін JavaScript қалпына келтіру.
Қысқасы, перспективалы, бірақ әлі әмбебап емес. Мақсатты браузерлерде сынақтан өткізіңіз.
Ал қол жетімділікке келетін болсақ, CSS-те көрнекі қатынасты жариялау қол жетімділік ағашына ештеңе айтпайды. aria-controls, aria-expanded, aria-haspopup — бұл бөлік әлі сізде.
Кейде түзету элементті жылжытады
Порталға бармас бұрын немесе координаттарды есептеуді жасамас бұрын, мен әрқашан алдымен бір сұрақ қоямын: бұл ашылмалы тізім шын мәнінде айналдыру контейнерінің ішінде тұруы керек пе?
Олай болмаса, түзетуді жоғары деңгейлі қаптамаға жылжыту JavaScript және координаттарды есептеусіз мәселені толығымен жояды.
Бұл әрқашан мүмкін емес. Түймешік пен ашылмалы тізім бір құрамдас бөлікте инкапсуляцияланған болса, біреуін екіншісінсіз жылжыту бүкіл API-ны қайта қарауды білдіреді. Бірақ сіз мұны істей алатын болсаңыз, жөндеуге ештеңе жоқ. Мәселе жай ғана жоқ.
Қазіргі CSS нені әлі шешпейді
CSS бұл жерде ұзақ жолдан өтті, бірақ әлі де сізді ренжітетін жерлер бар.
Позиция: бекітілген және түрлендіру мәселелері әлі де бар. Бұл әдейі спецификацияда, яғни CSS-тің уақытша шешімі жоқ. Орналасуды өзгертілген элементке орап алатын анимация кітапханасын пайдалансаңыз, сізге порталдар немесе якорьді орналастыру қажет болады.
CSS Anchor Positioning перспективалы, бірақ жаңа. Жоғарыда айтылғандай, мен мұны жазып жатқан кезде Firefox әлі де политолтыруды қажет етеді. Мен онымен мен күтпеген резервтерді қажет ететін макеттің шеткі жағдайларына тап болдым. Бүгінгі күні барлық браузерлерде дәйекті әрекет қажет болса, сіз әлі де күрделі бөліктер үшін JavaScript-ке қол жеткізесіз.
Мен жұмыс үрдісін шынымен өзгерткен қосымша HTML Popover API болып табылады, ол қазір барлық заманауи браузерлерде қолжетімді. Popover атрибуты бар элементтер JavaScript орналасуын қажет етпей, браузердің жоғарғы қабатында көрсетіледі.
Popover мазмұны
Өңдеуден қашу, сыртта басу кезінде өшіру және нақты қол жетімділік семантикасы құралдар кеңестері, ашу виджеттері және қарапайым қабаттасулар сияқты нәрселер үшін ақысыз болады. Бұл мен қазір қол жеткізген бірінші құрал.
Айтуынша, бұл орналасуды шешпейді. Ол қабаттасуды шешеді. Қалқымалы файлды триггерге туралау үшін сізге әлі де якорьді орналастыру немесе JavaScript қажет. Popover API қабаттастыруды өңдейді. Анкерлік орналастыру орналастыруды өңдейді. Бірге қолданылғанда, олар бұрын кітапханаға қол жеткізген нәрселердің көпшілігін қамтиды.
Сіздің жағдайыңыз үшін шешім қабылдау нұсқаулығы
Осының бәрін бастан өткергеннен кейін, мен қазір таңдау туралы қалай ойлаймын.
Порталды пайдаланыңыз. Мен оны триггер кірістірілген айналдыру контейнерлерінде тереңде тұрғанда қолданамын. Мен бұл үлгіні кесте әрекеттерінің мәзірлері үшін қолдандым және оны фокусты қалпына келтіру және қол жетімділікті тексерулермен жұптадым. Бұл ең сенімді нұсқа, бірақ қосымша сымдар үшін бюджет уақыты.
Бекітілген орынды анықтауды пайдаланыңыз. Бұл JavaScript ванильінде немесе жеңіл құрылымда болғанда және ешбір ата-баба түрлендірулерді немесе сүзгілерді қолданбайтынын тексере алмайтын кезде арналған. Орнату оңай және түзету оңай, тек бір шектеу сақталса.
Бұл үшін браузер қолдауы рұқсат еткенде CSS Anchor Positioning.Reach пайдаланыңыз. Firefox қолдауы қажет болса, оны @oddbird polyfill бағдарламасымен жұптаңыз. Бұл платформа түптеп келгенде бағытталады және сайып келгенде сіздің негізгі әдісіңізге айналады.
DOM құрылымын қайта құрылымдаңыз. Мұны архитектура рұқсат еткенде пайдаланыңыз және орындау уақытының күрделілігі нөлдік болғанын қаласаңыз. Менің ойымша, бұл ең төмен бағаланған нұсқа.
Үлгілерді біріктіріңіз. Қолдау көрсетілмейтін браузерлер үшін JavaScript қалпына келтіру нұсқасымен жұптастырылған негізгі тәсіл ретінде якорь орналасуын қаласаңыз, мұны жасаңыз. Немесе координат дәлдігі үшін getBoundingClientRect() арқылы жұптастырылған DOM орналастыру порталы.
Қорытынды
Мен бұл қатені бір реттік мәселе ретінде қарастыратынмын - түзетуге және одан әрі қарай өтуге болатын нәрсе. Бірақ мен онымен бірге барлық үш жүйені түсіну үшін жеткілікті ұзақ отырдым - толып кетуді кесу, контексттерді жинақтау және блоктарды қамтитын - ол кездейсоқ сезінуді тоқтатты. Мен бұзылған ашылмалы тізімге қарап, қай ата-баба жауапты екенін бірден анықтадым. Менің DOM-ті оқудағы бұл өзгеріс нағыз алып кету болды.
Бірыңғай дұрыс жауап жоқ. Мен қол жеткізген нәрсе код базасында басқара алатын нәрселерге байланысты болды: ата-баба ағашын болжау мүмкін болмаған кездегі порталдар; таза және қарапайым болған кезде бекітілген позициялау; мені ештеңе тоқтатпаған кезде элементті жылжыту; және қазір зәкірді орналастыру,қайда аламын.
Нені таңдасаңыз да, қол жетімділікті соңғы қадам ретінде қабылдамаңыз. Менің тәжірибемде дәл сол кезде өткізіп жібереді. ARIA қарым-қатынастары, фокусты басқару, пернетақта әрекеті - бұл жылтыр емес. Олар іс жүзінде жұмыс істейтін нәрсенің бөлігі болып табылады.
Менің GitHub репосындағы толық бастапқы кодты тексеріңіз.
Қосымша оқу
Бұл жұмыс барысында мен қайта оралған сілтемелер: