Սցենարը գրեթե միշտ նույնն է, որը տվյալների աղյուսակ է պտտվող կոնտեյների ներսում: Յուրաքանչյուր տող ունի գործողությունների ընտրացանկ, փոքր բացվող ցանկ՝ որոշ ընտրանքներով, ինչպիսիք են Խմբագրել, Կրկնօրինակել և Ջնջել: Դուք կառուցում եք այն, թվում է, որ այն հիանալի աշխատում է առանձին, և հետո ինչ-որ մեկը այն դնում է պտտվող դիվի ներսում, և իրերը քանդվում են: Ես տեսել եմ այս ճշգրիտ սխալը երեք տարբեր կոդերի բազաներում՝ կոնտեյներ, կույտ և շրջանակ, բոլորը տարբեր են: Սխալը, սակայն, բոլորովին նույնական է: Բացվող ցանկը կտրվում է տարայի եզրին: Կամ այն հայտնվում է բովանդակության հետևում, որը տրամաբանորեն պետք է լինի դրա տակ: Կամ այն լավ է աշխատում, քանի դեռ օգտատերը չի պտտվում, այնուհետև այն շեղվում է: Դուք հասնում եք z-ինդեքսին՝ 9999: Երբեմն դա օգնում է, բայց երբեմն դա բացարձակապես ոչինչ չի անում: Այդ անհամապատասխանությունն առաջին հուշումն է, որ ավելի խորը բան է տեղի ունենում: Շարունակական վերադառնալու պատճառն այն է, որ ներգրավված են բրաուզերի երեք առանձին համակարգեր, և ծրագրավորողներից շատերը հասկանում են յուրաքանչյուրն ինքնուրույն, բայց երբեք չեն մտածում, թե ինչ է տեղի ունենում, երբ երեքն էլ բախվում են.
Երբ հասկանում եք, թե ինչպես են երեքն էլ փոխազդում, ձախողման ռեժիմները դադարում են պատահական զգալ: Իրականում դրանք դառնում են կանխատեսելի։ Երեք բաներ, որոնք իրականում դա են առաջացնում Եկեք մանրամասն նայենք այդ կետերից յուրաքանչյուրին: Հորդառատ խնդիրը Երբ տարրի վրա սահմանում եք արտահոսք՝ թաքնված, գերհեռացում՝ ոլորել կամ գերհեռացում՝ ավտոմատ, զննարկիչը կտրում է այն ամենը, ինչ դուրս է գալիս իր սահմաններից, ներառյալ բացարձակապես դիրքավորված ժառանգները: .scroll-container { արտահոսք `ավտոմատ; բարձրությունը՝ 300px; /* Սա կկտրի բացվող ցանկը, վերջակետ */ }
.բացվող { դիրքը `բացարձակ; /* Կարևոր չէ. դեռ կտրված է .scroll-container-ի կողմից */ }
Դա ինձ զարմացրեց առաջին անգամ, երբ հանդիպեցի դրան: Ես ենթադրում էի դիրք՝ բացարձակը թույլ կտա տարրին խուսափել տարայի հատվածից: Դա չի անում: Գործնականում դա նշանակում է, որ բացարձակապես տեղադրված ընտրացանկը կարող է կտրվել ցանկացած նախնիի կողմից, որն ունի անտեսանելի արտահոսքի արժեք, նույնիսկ եթե այդ նախնին մենյուի բլոկը չէ: Կտրումը և դիրքավորումը առանձին համակարգեր են: Նրանք պարզապես պատահականորեն բախվում են այնպիսի ձևերով, որոնք բոլորովին պատահական են թվում, մինչև չհասկանաք երկուսն էլ:
Ահա React-ի օրինակ՝ օգտագործելով createPortal-ը.
ներմուծել {createPortal } 'react-dom'-ից; ներմուծել { useState, useEffect, useRef } «react»-ից;
գործառույթը բացվող ({ anchorRef, isOpen, երեխաներ }) { const [դիրք, setPosition] = useState({ վերև՝ 0, ձախ՝ 0 });
useEffect(() => { if (isOpen && anchorRef.current) { const rect = anchorRef.current.getBoundingClientRect(); setPosition ({ վերև՝ rect.bottom + window.scrollY, ձախ՝ rect.left + window.scrollX, }); } }, [isOpen, anchorRef]);
եթե (!isOpen) վերադարձնել null;
վերադարձնել createPortal (
Եվ, իհարկե, մենք չենք կարող անտեսել մատչելիությունը: Ֆիքսված տարրերը, որոնք հայտնվում են բովանդակության վրա, դեռևս պետք է հասանելի լինեն ստեղնաշարով: Եթե ֆոկուսի կարգը բնականաբար չի տեղափոխվում ֆիքսված բացվող ցանկ, դուք պետք է այն կառավարեք՝ օգտագործելով կոդը: Արժե նաև ստուգել, որ այն չի նստում այլ ինտերակտիվ բովանդակության վրա՝ առանց այն մերժելու: Այդ մեկը կծում է ձեզ ստեղնաշարի թեստավորման ժամանակ: CSS խարիսխի դիրքավորում. որտեղ ես կարծում եմ, որ սա ուղղվում է CSS Anchor Positioning-ը այն ուղղությունն է, որն ինձ ամենաշատն է հետաքրքրում այս պահին: Ես վստահ չէի, թե որքան մասն է իրականում օգտագործելի, երբ ես առաջին անգամ նայեցի դրան: Այն թույլ է տալիս Ձեզ հայտարարել բացվող ցանկի և դրա գործարկիչի միջև կապը անմիջապես CSS-ում, և զննարկիչը մշակում է կոորդինատները: .trigger { խարիսխ-անունը՝ --my-trigger; }
.dropdown-menu { դիրքը `բացարձակ; դիրք-խարիսխ. --my-trigger; վերևում `խարիսխ (ներքևում); ձախ: խարիսխ (ձախ); դիրք-փորձել-փակումներ. շրջել-բլոկ, շրջել-ինլայն; }
«Position-try-fallbacks» հատկությունն այն է, ինչն արժե այն օգտագործել ձեռքով հաշվարկով: Զննարկիչը փորձում է այլընտրանքային տեղաբաշխումներ նախքան հանձնվելը, այնպես որ տեսադաշտի ներքևում գտնվող բացվող ցանկն ինքնաբերաբար շրջվում է դեպի վեր՝ կտրվելու փոխարեն: Բրաուզերի աջակցությունը ամուր է Chromium-ի վրա հիմնված բրաուզերներում և աճում է Safari-ում: Firefox-ին անհրաժեշտ է պոլիֆիլմ: @oddbird/css-anchor-positioning փաթեթն ընդգրկում է հիմնական սպեկտրը: Ես դրա հետ հարվածել եմ դասավորության եզրային պատյաններ, որոնք պահանջում էին հետադարձ կապեր, որոնք ես չէի ակնկալում, այնպես որ վերաբերվեք այն որպես առաջադեմ բարելավում կամ զուգակցեք այն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-ն իր ձգանին հավասարեցնելու համար: Popover API-ն կարգավորում է շերտավորումը: Խարիսխի դիրքավորումը կարգավորում է տեղադրումը: Միասին օգտագործված դրանք ընդգրկում են այն ամենի մեծ մասը, ինչ դուք նախկինում կհասնեիք գրադարանի համար: Որոշումների ուղեցույց ձեր իրավիճակի համար Այս ամենի միջով դժվար ճանապարհ անցնելուց հետո, ահա թե ինչպես եմ ես իրականում մտածում այժմ ընտրության մասին:
Օգտագործեք պորտալ: Ես դա կօգտագործեի, երբ ձգանն ապրում է ոլորման մեջ տեղադրված բեռնարկղերի խորքում: Ես օգտագործել եմ այս օրինաչափությունը սեղանի գործողությունների ընտրացանկերի համար և զուգակցել այն ֆոկուսի վերականգնման և հասանելիության ստուգումների հետ: Դա ամենահուսալի տարբերակն է, բայց բյուջետային ժամանակ է լրացուցիչ լարերի համար: Օգտագործեք ֆիքսված դիրքավորում: Սա այն դեպքում, երբ դուք գտնվում եք վանիլային JavaScript-ում կամ թեթև շրջանակում և չեք կարող հաստատել, որ որևէ նախահայր չի կիրառում փոխակերպումներ կամ զտիչներ: Պարզ է կարգավորելը և հեշտ է վրիպազերծել, քանի դեռ պահպանվում է այդ մեկ սահմանափակումը: Օգտագործեք CSS Anchor Positioning-ը: Հասեք դրան, երբ ձեր դիտարկիչի աջակցությունը դա թույլ է տալիս: Եթե Firefox-ի աջակցությունը պահանջվում է, զուգակցեք այն @oddbird polyfill-ի հետ: Սա այն վայրն է, որտեղ հարթակը, ի վերջո, գնում է և ի վերջո կդառնա ձեր հիմնական մոտեցումը: Վերակազմավորեք DOM-ը: Օգտագործեք սա, երբ ճարտարապետությունը դա թույլ է տալիս, և դուք ցանկանում եք զրոյական գործարկման բարդություն: Կարծում եմ, որ դա, հավանաբար, ամենաթերագնահատված տարբերակն է: Միավորեք օրինաչափությունները: Դա արեք, երբ ցանկանում եք խարիսխի դիրքավորումը որպես ձեր առաջնային մոտեցում՝ զուգակցված JavaScript-ի հետադարձ կապի հետ չաջակցվող բրաուզերների համար: Կամ DOM-ի տեղադրման պորտալը, որը զուգակցված է getBoundingClientRect()-ի հետ՝ կոորդինատների ճշգրտության համար:
Եզրակացություն Ես այս վրիպակին վերաբերվում էի որպես միանվագ խնդրի՝ կարկատելու և դրանից առաջ շարժվելու մի բան: Բայց երբ ես բավական երկար նստեցի դրա հետ՝ հասկանալու համար, որ ներգրավված են բոլոր երեք համակարգերը՝ հորդառատ կտրում, համատեքստերի կուտակում և բլոկներ պարունակող, այն դադարեց պատահական զգալ: Ես կարող էի նայել կոտրված բացվող ցանկին և անմիջապես հետագծել, թե որ նախնին է պատասխանատու: Այդ փոփոխությունը, թե ինչպես էի կարդում DOM-ը, իրական միջոց էր: Մեկ ճիշտ պատասխան չկա. Այն, ինչին ես հասել էի, կախված էր նրանից, թե ինչ կարող էի կառավարել կոդերի բազայում. պորտալներ, երբ նախնի ծառը անկանխատեսելի էր. ֆիքսված դիրքավորում, երբ այն մաքուր և պարզ էր; շարժելով տարրը, երբ ինձ ոչինչ չէր խանգարում. և խարիսխի դիրքավորումն այժմ,որտեղ ես կարող եմ. Ինչ էլ որ ընտրեք, մի համարեք հասանելիությունը որպես վերջին քայլ: Իմ փորձով, դա հենց այն ժամանակ է, երբ այն բաց է թողնվում: ARIA-ի հարաբերությունները, ֆոկուսի կառավարումը, ստեղնաշարի վարքագիծը. Նրանք մաս են կազմում այն բանի, ինչը ստիպում է իրականում աշխատել: Ստուգեք ամբողջական աղբյուրի կոդը իմ GitHub պահեստում: Հետագա ընթերցում Սրանք այն հղումներն են, որոնց ես անընդհատ վերադառնում էի այս միջոցով աշխատելիս.
Stacking Context (MDN) «CSS խարիսխի դիրքավորման ուղեցույց», Խուան Դիեգո Ռոդրիգես «Սկսել Popover API-ով», Godstime Aburu Լողացող միջերես (floating-ui.com) CSS Overflow (MDN)