দৃশ্যপট প্রায় সবসময় একই, যা একটি স্ক্রোলযোগ্য পাত্রের ভিতরে একটি ডেটা টেবিল। প্রতিটি সারিতে একটি অ্যাকশন মেনু রয়েছে, কিছু বিকল্প সহ একটি ছোট ড্রপডাউন, যেমন সম্পাদনা, সদৃশ এবং মুছুন। আপনি এটি তৈরি করেন, এটি বিচ্ছিন্নভাবে পুরোপুরি কাজ করে বলে মনে হয়, এবং তারপর কেউ এটিকে স্ক্রোলযোগ্য ডিভের ভিতরে রাখে এবং জিনিসগুলি আলাদা হয়ে যায়। আমি তিনটি ভিন্ন কোডবেসে এই সঠিক বাগটি দেখেছি: ধারক, স্ট্যাক এবং ফ্রেমওয়ার্ক, সব আলাদা। বাগ, যদিও, সম্পূর্ণ অভিন্ন. ড্রপডাউনটি কন্টেইনারের প্রান্তে ক্লিপ করা হয়। অথবা এটি এমন সামগ্রীর পিছনে দেখায় যা যৌক্তিকভাবে এটির নীচে থাকা উচিত৷ অথবা ব্যবহারকারী স্ক্রোল না করা পর্যন্ত এটি সূক্ষ্ম কাজ করে এবং তারপরে এটি প্রবাহিত হয়। আপনি z-index এর জন্য পৌঁছান: 9999। কখনও কখনও এটি সাহায্য করে, কিন্তু অন্য সময় এটি একেবারে কিছুই করে না। এই অসামঞ্জস্যতা হল প্রথম সূত্র যে গভীর কিছু ঘটছে। এটি বারবার ফিরে আসার কারণ হল যে তিনটি পৃথক ব্রাউজার সিস্টেম জড়িত, এবং বেশিরভাগ বিকাশকারীরা প্রতিটিকে নিজের থেকে বোঝেন কিন্তু যখন তিনটি সংঘর্ষ হয় তখন কী হয় তা নিয়ে কখনই ভাবেন না: ওভারফ্লো, স্ট্যাকিং প্রসঙ্গ এবং ব্লক রয়েছে৷
একবার আপনি বুঝতে পেরেছেন যে তিনটি কীভাবে ইন্টারঅ্যাক্ট করে, ব্যর্থতার মোডগুলি এলোমেলো অনুভব করা বন্ধ করে দেয়। আসলে, তারা অনুমানযোগ্য হয়ে ওঠে। তিনটি জিনিস আসলে এই কারণ আসুন বিস্তারিতভাবে এই আইটেম প্রতিটি তাকান. ওভারফ্লো সমস্যা আপনি যখন ওভারফ্লো সেট করেন: লুকানো, ওভারফ্লো: স্ক্রোল, বা ওভারফ্লো: একটি উপাদানে অটো, ব্রাউজার তার সীমার বাইরে প্রসারিত যেকোন কিছুকে ক্লিপ করবে, যার মধ্যে একেবারে অবস্থান করা বংশধর রয়েছে। .scroll-container { overflow: স্বয়ংক্রিয়; উচ্চতা: 300px; /* এটি ড্রপডাউন ক্লিপ করবে, ফুল স্টপ */ }
.ড্রপডাউন { অবস্থান: পরম; /* কোন ব্যাপার না -- এখনও .scroll-container */ দ্বারা ক্লিপ করা হয়েছে }
প্রথমবার যখন আমি এতে ছুটে যাই তখন আমাকে অবাক করে দেয়। আমি অবস্থান ধরে নিতাম: পরম একটি উপাদানকে একটি পাত্রের ক্লিপিং থেকে বাঁচতে দেবে। এটা না. অনুশীলনে, এর মানে হল যে কোনও পূর্বপুরুষের দ্বারা একটি সম্পূর্ণ অবস্থানযুক্ত মেনু কেটে ফেলা যেতে পারে যার একটি অদৃশ্যমান ওভারফ্লো মান রয়েছে, এমনকি যদি সেই পূর্বপুরুষটি মেনুতে থাকা ব্লক নাও হয়। ক্লিপিং এবং পজিশনিং আলাদা সিস্টেম। আপনি উভয় বুঝতে না হওয়া পর্যন্ত এগুলি কেবল এমনভাবে সংঘর্ষ হয় যা সম্পূর্ণরূপে এলোমেলো দেখায়।
CreatePortal ব্যবহার করে এখানে একটি প্রতিক্রিয়া উদাহরণ দেওয়া হল:
'react-dom' থেকে { createPortal } আমদানি করুন; 'প্রতিক্রিয়া' থেকে { useState, useEffect, useRef} আমদানি করুন;
ফাংশন ড্রপডাউন ({ anchorRef, isOpen, Children }) { const [position, setPosition] = useState({ top: 0, left: 0 });
useEffect(() => { যদি (isOpen && anchorRef.current) { const rect = anchorRef.current.getBoundingClientRect(); সেটপজিশন({ শীর্ষ: rect.bottom + window.scrollY, বাম: rect.left + window.scrollX, }); } }, [isOpen, anchorRef]);
যদি (!isOpen) রিটার্ন নাল;
তৈরি পোর্টাল ফেরত (
এবং, অবশ্যই, আমরা অ্যাক্সেসযোগ্যতা উপেক্ষা করতে পারি না। বিষয়বস্তুর উপরে প্রদর্শিত স্থির উপাদানগুলি এখনও কীবোর্ডের কাছে পৌঁছাতে হবে। যদি ফোকাস অর্ডার স্বাভাবিকভাবে নির্দিষ্ট ড্রপডাউনে না যায়, তাহলে আপনাকে কোড ব্যবহার করে এটি পরিচালনা করতে হবে। এটি খারিজ করার কোন উপায় ছাড়া এটি অন্যান্য ইন্টারেক্টিভ বিষয়বস্তুর উপর বসে না তাও পরীক্ষা করা মূল্যবান। যে একটি কিবোর্ড পরীক্ষা আপনি কামড়. CSS অ্যাঙ্কর পজিশনিং: যেখানে আমি মনে করি এটি শিরোনাম হচ্ছে CSS অ্যাঙ্কর পজিশনিং হল সেই দিকটি যা আমি এই মুহূর্তে সবচেয়ে বেশি আগ্রহী। আমি নিশ্চিত ছিলাম না যে কতটা স্পেক আসলে ব্যবহারযোগ্য ছিল যখন আমি এটি প্রথম দেখেছিলাম। এটি আপনাকে সরাসরি CSS-এ একটি ড্রপডাউন এবং এর ট্রিগারের মধ্যে সম্পর্ক ঘোষণা করতে দেয় এবং ব্রাউজার স্থানাঙ্কগুলি পরিচালনা করে। .ট্রিগার { অ্যাঙ্কর-নাম: --আমার-ট্রিগার; }
.ড্রপডাউন-মেনু { অবস্থান: পরম; অবস্থান-অ্যাঙ্কর: --আমার-ট্রিগার; শীর্ষ: নোঙ্গর (নীচে); বাম: নোঙ্গর (বাম); পজিশন-ট্রাই-ফলব্যাকস: ফ্লিপ-ব্লক, ফ্লিপ-ইনলাইন; }
পজিশন-ট্রাই-ফলব্যাকস প্রপার্টি ম্যানুয়াল ক্যালকুলেশন ব্যবহার করে এটিকে মূল্যবান করে তোলে। ব্রাউজারটি ছেড়ে দেওয়ার আগে বিকল্প প্লেসমেন্ট চেষ্টা করে, তাই ভিউপোর্টের নীচে একটি ড্রপডাউন স্বয়ংক্রিয়ভাবে কেটে যাওয়ার পরিবর্তে উপরের দিকে উল্টে যায়। ক্রোমিয়াম-ভিত্তিক ব্রাউজারগুলিতে ব্রাউজার সমর্থন শক্ত এবং সাফারিতে বাড়ছে। ফায়ারফক্স একটি পলিফিল প্রয়োজন. @oddbird/css-অ্যাঙ্কর-পজিশনিং প্যাকেজ মূল বৈশিষ্ট্যকে কভার করে। আমি এটির সাথে লেআউট এজ কেসগুলি হিট করেছি যার জন্য আমি অনুমান করিনি এমন ফলব্যাকগুলির প্রয়োজন, তাই এটিকে একটি প্রগতিশীল বর্ধন হিসাবে বিবেচনা করুন বা এটির সাথে যুক্ত করুনফায়ারফক্সের জন্য জাভাস্ক্রিপ্ট ফলব্যাক। সংক্ষেপে, প্রতিশ্রুতিশীল কিন্তু এখনও সর্বজনীন নয়। আপনার লক্ষ্য ব্রাউজার পরীক্ষা. এবং যতদূর অ্যাক্সেসিবিলিটি সম্পর্কিত, CSS-এ একটি ভিজ্যুয়াল সম্পর্ক ঘোষণা করা অ্যাক্সেসিবিলিটি ট্রিকে কিছু বলে না। aria-controls, aria-expanded, aria-haspopup — সেই অংশটি এখনও আপনার উপর রয়েছে। কখনও কখনও ফিক্স শুধু উপাদান সরানো হয় একটি পোর্টালে পৌঁছানোর আগে বা স্থানাঙ্ক গণনা করার আগে, আমি সর্বদা প্রথমে একটি প্রশ্ন জিজ্ঞাসা করি: এই ড্রপডাউনটি কি আসলেই স্ক্রোল কন্টেইনারের ভিতরে থাকা দরকার? যদি তা না হয়, মার্কআপটিকে একটি উচ্চ-স্তরের র্যাপারে সরানো সমস্যাটি সম্পূর্ণরূপে দূর করে, কোন জাভাস্ক্রিপ্ট এবং কোন সমন্বয় গণনা ছাড়াই। এটা সবসময় সম্ভব হয় না। যদি বোতাম এবং ড্রপডাউন একই কম্পোনেন্টে এনক্যাপসুলেট করা হয়, তাহলে অন্যটি ছাড়া একটি সরানো মানে পুরো API নিয়ে পুনর্বিবেচনা করা। কিন্তু যখন আপনি এটি করতে পারেন, ডিবাগ করার কিছু নেই। সমস্যাটি কেবল বিদ্যমান নয়। যা আধুনিক CSS এখনও সমাধান করে না CSS এখানে অনেক দূর এগিয়েছে, কিন্তু এখনও এমন জায়গা আছে যা আপনাকে হতাশ করে। অবস্থান: স্থির এবং রূপান্তর সমস্যা এখনও আছে। এটি ইচ্ছাকৃতভাবে স্পেকের মধ্যে রয়েছে, যার মানে কোন CSS ওয়ার্কআরাউন্ড বিদ্যমান নেই। আপনি যদি একটি অ্যানিমেশন লাইব্রেরি ব্যবহার করেন যা আপনার লেআউটকে একটি রূপান্তরিত উপাদানে মোড়ানো হয়, তাহলে আপনি পোর্টাল বা অ্যাঙ্কর অবস্থানের প্রয়োজনে ফিরে এসেছেন। CSS অ্যাঙ্কর পজিশনিং আশাব্যঞ্জক, কিন্তু নতুন। আগেই উল্লেখ করা হয়েছে, আমি যখন এটি লিখছি তখনও ফায়ারফক্সের একটি পলিফিল প্রয়োজন। আমি এটির সাথে লেআউট এজ কেসগুলিকে আঘাত করেছি যার জন্য আমি অনুমান করিনি এমন ফলব্যাকগুলির প্রয়োজন৷ আপনার যদি আজ সমস্ত ব্রাউজার জুড়ে সামঞ্জস্যপূর্ণ আচরণের প্রয়োজন হয়, আপনি এখনও জটিল অংশগুলির জন্য জাভাস্ক্রিপ্টে পৌঁছাচ্ছেন। আমি আসলে আমার ওয়ার্কফ্লো পরিবর্তন করেছি তা হল HTML Popover API, এখন সমস্ত আধুনিক ব্রাউজারে উপলব্ধ। পপওভার অ্যাট্রিবিউট সহ উপাদানগুলি ব্রাউজারের উপরের স্তরে, সবকিছুর উপরে, কোন জাভাস্ক্রিপ্ট অবস্থানের প্রয়োজন নেই।
এস্কেপ হ্যান্ডলিং, ডিসমিস-অন-ক্লিক-বাইরে, এবং কঠিন অ্যাক্সেসিবিলিটি শব্দার্থবিদ্যা টুলটিপ, ডিসক্লোজার উইজেট এবং সাধারণ ওভারলেগুলির মতো জিনিসগুলির জন্য বিনামূল্যে পাওয়া যায়। এটিই প্রথম টুল যা আমি এখন পর্যন্ত পৌঁছেছি। এটি বলেছিল, এটি অবস্থানের সমাধান করে না। এটা লেয়ারিং সমাধান করে। একটি পপওভারকে তার ট্রিগারে সারিবদ্ধ করতে আপনার এখনও অ্যাঙ্কর পজিশনিং বা জাভাস্ক্রিপ্টের প্রয়োজন। Popover API লেয়ারিং পরিচালনা করে। অ্যাঙ্কর পজিশনিং প্লেসমেন্ট পরিচালনা করে। একসাথে ব্যবহার করা হয়, আপনি আগে লাইব্রেরিতে যা করতে চান তার বেশিরভাগই তারা কভার করে। আপনার পরিস্থিতির জন্য একটি সিদ্ধান্ত নির্দেশিকা এই সমস্ত কঠিন পথের মধ্য দিয়ে যাওয়ার পরে, আমি এখন পছন্দটি সম্পর্কে আসলে কীভাবে চিন্তা করি তা এখানে।
একটি পোর্টাল ব্যবহার করুন৷ আমি এটি ব্যবহার করব যখন ট্রিগারটি নেস্টেড স্ক্রোল পাত্রে গভীরভাবে থাকে৷ আমি টেবিল অ্যাকশন মেনুর জন্য এই প্যাটার্নটি ব্যবহার করেছি এবং এটিকে ফোকাস পুনরুদ্ধার এবং অ্যাক্সেসিবিলিটি চেকের সাথে যুক্ত করেছি। এটি সবচেয়ে নির্ভরযোগ্য বিকল্প, তবে অতিরিক্ত তারের জন্য বাজেট সময়। ফিক্সড পজিশনিং ব্যবহার করুন। আপনি যখন ভ্যানিলা জাভাস্ক্রিপ্ট বা হালকা ফ্রেমওয়ার্কে থাকেন এবং কোন পূর্বপুরুষ রূপান্তর বা ফিল্টার প্রয়োগ করে না তা যাচাই করতে পারেন। এটি সেট আপ করা সহজ এবং ডিবাগ করা সহজ, যতক্ষণ পর্যন্ত একটি সীমাবদ্ধতা থাকে। CSS অ্যাঙ্কর পজিশনিং ব্যবহার করুন৷ আপনার ব্রাউজার সমর্থন এটির অনুমতি দিলে এটির জন্য পৌঁছান৷ ফায়ারফক্স সমর্থন প্রয়োজন হলে, এটি @oddbird পলিফিলের সাথে যুক্ত করুন। এই প্ল্যাটফর্মটি শেষ পর্যন্ত শিরোনাম হচ্ছে এবং শেষ পর্যন্ত আপনার কাছে যাওয়ার পদ্ধতিতে পরিণত হবে। DOM এর পুনর্গঠন করুন৷ আর্কিটেকচার এটির অনুমতি দিলে এটি ব্যবহার করুন এবং আপনি শূন্য রানটাইম জটিলতা চান৷ আমি বিশ্বাস করি এটি সম্ভবত সবচেয়ে আন্ডাররেটেড বিকল্প। প্যাটার্নগুলি একত্রিত করুন৷ আপনি যখন অসমর্থিত ব্রাউজারগুলির জন্য জাভাস্ক্রিপ্ট ফলব্যাকের সাথে যুক্ত আপনার প্রাথমিক পদ্ধতি হিসাবে অ্যাঙ্কর পজিশনিং চান তখন এটি করুন৷ অথবা সমন্বয় নির্ভুলতার জন্য getBoundingClientRect() এর সাথে যুক্ত DOM প্লেসমেন্টের জন্য একটি পোর্টাল।
উপসংহার আমি এই বাগটিকে এক-একটি সমস্যা হিসাবে বিবেচনা করতাম — প্যাচ করার এবং এর থেকে এগিয়ে যাওয়ার মতো কিছু। কিন্তু একবার আমি এটির সাথে জড়িত তিনটি সিস্টেম - ওভারফ্লো ক্লিপিং, স্ট্যাকিং কনটেক্সট এবং ব্লক ধারণকারী - বুঝতে যথেষ্ট সময় ধরে এটির সাথে বসেছিলাম - এটি এলোমেলো অনুভব করা বন্ধ করে দেয়। আমি একটি ভাঙা ড্রপডাউন দেখতে এবং অবিলম্বে কোন পূর্বপুরুষ দায়ী ছিল ট্রেস করতে পারেন. আমি কিভাবে DOM পড়ি সেই পরিবর্তনটাই আসল টেকঅ্যাওয়ে ছিল। কোন একক সঠিক উত্তর নেই। আমি কোডবেসে কী নিয়ন্ত্রণ করতে পারি তার উপর নির্ভর করে: পূর্বপুরুষ গাছটি অনির্দেশ্য ছিল; স্থির অবস্থান যখন এটি পরিষ্কার এবং সহজ ছিল; উপাদান সরানো যখন কিছুই আমাকে থামাচ্ছে না; এবং এখন অ্যাঙ্কর পজিশনিং,যেখানে আমি পারি। আপনি যা-ই বেছে নিন না কেন, অ্যাক্সেসযোগ্যতাকে শেষ ধাপ হিসেবে বিবেচনা করবেন না। আমার অভিজ্ঞতায়, ঠিক তখনই এটি এড়িয়ে যায়। ARIA সম্পর্ক, ফোকাস ম্যানেজমেন্ট, কীবোর্ড আচরণ — এগুলো পোলিশ নয়। তারা জিনিসটি আসলে কাজ করে তার অংশ। আমার GitHub রেপোতে সম্পূর্ণ সোর্স কোডটি দেখুন। আরও পড়া এইগুলির মাধ্যমে কাজ করার সময় আমি যে রেফারেন্সগুলিতে ফিরে এসেছি:
স্ট্যাকিং কনটেক্সট (MDN) "সিএসএস অ্যাঙ্কর পজিশনিং গাইড", জুয়ান দিয়েগো রদ্রিগেজ "পপওভার API দিয়ে শুরু করা", গডসটাইম আবুরু ভাসমান UI (floating-ui.com) CSS ওভারফ্লো (MDN)