ResizeObserver: এটি উপাদানের জন্য document.onresize এর মত

কোনো এলিমেন্টের আকার পরিবর্তিত হলে ResizeObserver আপনাকে জানিয়ে দেয়।

ResizeObserver আসার আগে, ভিউপোর্টের ডাইমেনশনের যেকোনো পরিবর্তন সম্পর্কে জানতে আপনাকে ডকুমেন্টের resize ইভেন্টে একটি লিসেনার যুক্ত করতে হতো। এরপর ইভেন্ট হ্যান্ডলারে আপনাকে খুঁজে বের করতে হতো কোন কোন এলিমেন্ট সেই পরিবর্তনের দ্বারা প্রভাবিত হয়েছে এবং যথাযথভাবে প্রতিক্রিয়া জানানোর জন্য একটি নির্দিষ্ট রুটিন কল করতে হতো। রিসাইজের পর যদি আপনার কোনো এলিমেন্টের নতুন ডাইমেনশন জানার প্রয়োজন হতো, তাহলে আপনাকে getBoundingClientRect() বা getComputedStyle() কল করতে হতো, যা আপনার সমস্ত রিড এবং রাইট অপারেশনগুলো ব্যাচিং করার ব্যবস্থা না করলে লেআউট থ্র্যাশিংয়ের কারণ হতে পারত।

এর মধ্যে সেইসব ক্ষেত্র অন্তর্ভুক্ত ছিল না যেখানে মূল উইন্ডোর আকার পরিবর্তন না করেই এলিমেন্টগুলোর আকার বদলে যায়। উদাহরণস্বরূপ, নতুন চাইল্ড যুক্ত করা, কোনো এলিমেন্টের display স্টাইল ' none এ সেট করা, বা এই ধরনের অন্যান্য কাজ একটি এলিমেন্ট, তার সিবলিং বা অ্যানসেস্টরদের আকার পরিবর্তন করতে পারে।

এই কারণেই ResizeObserver একটি দরকারি প্রিমিটিভ। এটি পর্যবেক্ষণাধীন যেকোনো উপাদানের আকারের পরিবর্তনে সাড়া দেয়, পরিবর্তনটি কী কারণে ঘটেছে তা নির্বিশেষে। এটি পর্যবেক্ষণাধীন উপাদানগুলোর নতুন আকারেও অ্যাক্সেস প্রদান করে।

Browser Support

  • ক্রোম: ৬৪।
  • প্রান্ত: ৭৯।
  • ফায়ারফক্স: ৬৯।
  • সাফারি: ১৩.১।

Source

এপিআই

উপরে উল্লিখিত Observer সাফিক্সযুক্ত সমস্ত API-এর একটি সরল API ডিজাইন রয়েছে। ResizeObserver ও এর ব্যতিক্রম নয়। আপনি একটি ResizeObserver অবজেক্ট তৈরি করেন এবং কনস্ট্রাক্টরে একটি কলব্যাক পাস করেন। কলব্যাকটিতে ResizeObserverEntry অবজেক্টের একটি অ্যারে পাস করা হয়—প্রতিটি পর্যবেক্ষণ করা এলিমেন্টের জন্য একটি করে এন্ট্রি—যেটিতে এলিমেন্টটির নতুন ডাইমেনশন থাকে।

var ro = new ResizeObserver(entries => {
  for (let entry of entries) {
    const cr = entry.contentRect;

    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  }
});

// Observe one or multiple elements
ro.observe(someElement);

কিছু বিবরণ

কী রিপোর্ট করা হচ্ছে?

সাধারণত, একটি ResizeObserverEntry একটি এলিমেন্টের কন্টেন্ট বক্সকে contentRect নামক প্রপার্টির মাধ্যমে রিপোর্ট করে, যা একটি DOMRectReadOnly অবজেক্ট রিটার্ন করে। কন্টেন্ট বক্স হলো সেই বক্স যার মধ্যে কন্টেন্ট রাখা যায়। এটি হলো বর্ডার বক্স থেকে প্যাডিং বাদ দিয়ে যা থাকে।

সিএসএস বক্স মডেলের একটি চিত্র।

এটা মনে রাখা গুরুত্বপূর্ণ যে, ResizeObserver যদিও contentRect এর ডাইমেনশন এবং প্যাডিং উভয়ই রিপোর্ট করে , এটি শুধুমাত্র contentRect পর্যবেক্ষণ করেcontentRect এলিমেন্টের বাউন্ডিং বক্সের সাথে গুলিয়ে ফেলবেন নাgetBoundingClientRect() দ্বারা রিপোর্ট করা বাউন্ডিং বক্স হলো সেই বক্স যা সম্পূর্ণ এলিমেন্ট এবং তার অধীনস্থ এলিমেন্টগুলোকে ধারণ করে। SVG এই নিয়মের একটি ব্যতিক্রম, যেখানে ResizeObserver বাউন্ডিং বক্সের ডাইমেনশন রিপোর্ট করে।

ক্রোম ৮৪ থেকে, আরও বিস্তারিত তথ্য প্রদানের জন্য ResizeObserverEntry তিনটি নতুন প্রপার্টি যুক্ত হয়েছে। এই প্রপার্টিগুলোর প্রতিটি একটি ResizeObserverSize অবজেক্ট রিটার্ন করে, যাতে একটি blockSize প্রপার্টি এবং একটি inlineSize প্রপার্টি থাকে। কলব্যাকটি আহ্বান করার মুহূর্তে পর্যবেক্ষণাধীন এলিমেন্টটির তথ্য এই বিবরণে থাকে।

  • borderBoxSize
  • contentBoxSize
  • devicePixelContentBoxSize

এই সমস্ত আইটেম রিড-অনলি অ্যারে রিটার্ন করে, কারণ ভবিষ্যতে আশা করা যায় যে এগুলো একাধিক ফ্র্যাগমেন্টযুক্ত এলিমেন্টকেও সাপোর্ট করতে পারবে, যা মাল্টি-কলাম পরিস্থিতিতে দেখা যায়। আপাতত, এই অ্যারেগুলোতে কেবল একটি এলিমেন্টই থাকবে।

এই প্রোপার্টিগুলোর জন্য প্ল্যাটফর্ম সমর্থন সীমিত, কিন্তু ফায়ারফক্স ইতিমধ্যেই প্রথম দুটি সমর্থন করে

কখন এটি রিপোর্ট করা হচ্ছে?

স্পেসিফিকেশন অনুযায়ী, ResizeObserver অবশ্যই পেইন্টের আগে এবং লেআউটের পরে সমস্ত রিসাইজ ইভেন্ট প্রসেস করতে হবে। এর ফলে, আপনার পেজের লেআউটে পরিবর্তন আনার জন্য ResizeObserver এর কলব্যাক একটি আদর্শ জায়গা হয়ে ওঠে। যেহেতু ResizeObserver প্রসেসিং লেআউট এবং পেইন্টের মাঝে ঘটে, তাই এটি করলে শুধুমাত্র লেআউটই ইনভ্যালিডেট হবে, পেইন্ট নয়।

গোটচা

আপনি হয়তো নিজেকে প্রশ্ন করছেন: ResizeObserver এর কলব্যাকের ভিতরে যদি আমি পর্যবেক্ষণ করা কোনো এলিমেন্টের আকার পরিবর্তন করি, তাহলে কী হবে? উত্তর হলো: সাথে সাথেই কলব্যাকটিতে আরেকটি কল ট্রিগার হবে। সৌভাগ্যবশত, অসীম কলব্যাক লুপ এবং চক্রাকার নির্ভরতা এড়ানোর জন্য ResizeObserver একটি ব্যবস্থা রয়েছে। পরিবর্তনগুলো শুধুমাত্র তখনই একই ফ্রেমে প্রসেস করা হবে, যদি রিসাইজ করা এলিমেন্টটি আগের কলব্যাকে প্রসেস করা সবচেয়ে অগভীর এলিমেন্টের চেয়ে DOM ট্রি-তে আরও গভীরে থাকে। অন্যথায়, সেগুলো পরবর্তী ফ্রেমের জন্য স্থগিত হয়ে যাবে।

আবেদন

ResizeObserver এর একটি সুবিধা হলো প্রতিটি এলিমেন্টের জন্য আলাদা মিডিয়া কোয়েরি প্রয়োগ করা। এলিমেন্টগুলোকে পর্যবেক্ষণ করার মাধ্যমে, আপনি অপরিহার্যভাবে আপনার ডিজাইনের ব্রেকপয়েন্ট নির্ধারণ করতে এবং একটি এলিমেন্টের স্টাইল পরিবর্তন করতে পারেন। নিচের উদাহরণে , দ্বিতীয় বক্সটি তার প্রস্থ অনুযায়ী বর্ডার রেডিয়াস পরিবর্তন করবে।

const ro = new ResizeObserver(entries => {
  for (let entry of entries) {
    entry.target.style.borderRadius =
        Math.max(0, 250 - entry.contentRect.width) + 'px';
  }
});
// Only observe the second box
ro.observe(document.querySelector('.box:nth-child(2)'));

আরেকটি আকর্ষণীয় উদাহরণ হলো একটি চ্যাট উইন্ডো। একটি সাধারণ উপর থেকে নিচের দিকে সাজানো কথোপকথনের লেআউটে যে সমস্যাটি দেখা দেয়, তা হলো স্ক্রল পজিশনিং। ব্যবহারকারীকে বিভ্রান্তি থেকে বাঁচাতে, উইন্ডোটি কথোপকথনের একেবারে নিচে স্থির থাকলে সুবিধা হয়, যেখানে নতুন বার্তাগুলো দেখা যায়। এছাড়াও, যেকোনো ধরনের লেআউট পরিবর্তনের ক্ষেত্রেও (যেমন একটি ফোন ল্যান্ডস্কেপ থেকে পোর্ট্রেটে বা এর উল্টোটা) একই ফল পাওয়া উচিত।

ResizeObserver আপনাকে এমন একটিমাত্র কোড লেখার সুযোগ দেয় যা উভয় পরিস্থিতিই সামলে নিতে পারে। উইন্ডোর আকার পরিবর্তন করা এমন একটি ঘটনা যা একটি ResizeObserver সংজ্ঞানুসারেই ধরতে পারে, কিন্তু appendChild() কল করলে সেই এলিমেন্টটিরও আকার পরিবর্তন হয়ে যায় (যদি না overflow: hidden সেট করা থাকে), কারণ নতুন এলিমেন্টগুলোর জন্য জায়গা তৈরি করতে হয়। এই বিষয়টি মাথায় রাখলে, কাঙ্ক্ষিত ফলাফল পেতে খুব অল্প কয়েকটি লাইনই যথেষ্ট:

const ro = new ResizeObserver(entries => {
  document.scrollingElement.scrollTop =
    document.scrollingElement.scrollHeight;
});

// Observe the scrollingElement for when the window gets resized
ro.observe(document.scrollingElement);

// Observe the timeline to process new messages
ro.observe(timeline);

বেশ চমৎকার, তাই না?

এখান থেকে, আমি এমন পরিস্থিতি সামাল দেওয়ার জন্য আরও কোড যোগ করতে পারি, যেখানে ব্যবহারকারী নিজে থেকে স্ক্রল উপরে করেছেন এবং চান যে নতুন কোনো বার্তা এলে স্ক্রলিংটি সেই বার্তাতেই স্থির থাকুক।

এর আরেকটি ব্যবহার হলো এমন যেকোনো ধরনের কাস্টম এলিমেন্টের ক্ষেত্রে, যা নিজের লেআউট নিজেই তৈরি করে। ResizeObserver আসার আগে, এর ডাইমেনশন পরিবর্তিত হলে নোটিফিকেশন পাওয়ার কোনো নির্ভরযোগ্য উপায় ছিল না, যাতে এর চাইল্ড এলিমেন্টগুলোকে পুনরায় লেআউট করা যায়।

পরবর্তী পেইন্টের (INP) সাথে মিথস্ক্রিয়ার প্রভাব

ইন্টারঅ্যাকশন টু নেক্সট পেইন্ট (INP) হলো এমন একটি মেট্রিক যা ব্যবহারকারীর ইন্টারঅ্যাকশনের প্রতি একটি পেজের সামগ্রিক প্রতিক্রিয়াশীলতা পরিমাপ করে। যদি একটি পেজের INP "ভালো" সীমার মধ্যে থাকে—অর্থাৎ, ২০০ মিলিসেকেন্ড বা তার কম—তবে বলা যেতে পারে যে পেজটি ব্যবহারকারীর ইন্টারঅ্যাকশনের প্রতি নির্ভরযোগ্যভাবে প্রতিক্রিয়াশীল।

যদিও ব্যবহারকারীর কোনো ইন্টারঅ্যাকশনের প্রতিক্রিয়ায় ইভেন্ট কলব্যাকগুলো চলতে যে সময় লাগে, তা একটি ইন্টারঅ্যাকশনের মোট ল্যাটেন্সিতে উল্লেখযোগ্যভাবে অবদান রাখতে পারে, তবে INP-এর বিবেচনার জন্য এটিই একমাত্র দিক নয়। INP ইন্টারঅ্যাকশনটির পরবর্তী পেইন্ট সম্পন্ন হতে যে সময় লাগে, তাও বিবেচনা করে। কোনো ইন্টারঅ্যাকশনের প্রতিক্রিয়ায় ইউজার ইন্টারফেস আপডেট করার জন্য প্রয়োজনীয় রেন্ডারিং কাজটি সম্পূর্ণ হতে যে সময় লাগে, এটিই সেই সময়।

ResizeObserver ক্ষেত্রে এটি গুরুত্বপূর্ণ, কারণ একটি ResizerObserver ইনস্ট্যান্স যে কলব্যাকটি চালায়, তা রেন্ডারিংয়ের কাজ শুরু হওয়ার ঠিক আগে ঘটে। এটি ইচ্ছাকৃতভাবেই করা হয়, কারণ কলব্যাকে যে কাজটি সম্পন্ন হয়, তা অবশ্যই বিবেচনায় রাখতে হয়, যেহেতু সেই কাজের ফলাফলের জন্য ইউজার ইন্টারফেসে পরিবর্তনের প্রয়োজন হওয়ার প্রবল সম্ভাবনা থাকে।

একটি ResizeObserver কলব্যাকে যতটা সম্ভব কম রেন্ডারিং কাজ করার ব্যাপারে সতর্ক থাকুন, কারণ অতিরিক্ত রেন্ডারিং কাজের ফলে ব্রাউজার গুরুত্বপূর্ণ কাজ করতে দেরি করতে পারে। উদাহরণস্বরূপ, যদি কোনো ইন্টারঅ্যাকশনের এমন কোনো কলব্যাক থাকে যা একটি ResizeObserver কলব্যাককে চালু করে, তবে সম্ভাব্য সবচেয়ে মসৃণ অভিজ্ঞতা নিশ্চিত করতে আপনি নিম্নলিখিত কাজগুলো করছেন কিনা তা নিশ্চিত করুন:

  • অতিরিক্ত স্টাইল পুনঃগণনার কাজ এড়ানোর জন্য আপনার CSS সিলেক্টরগুলো যথাসম্ভব সহজ রাখুন। স্টাইল পুনঃগণনা লেআউটের ঠিক আগে ঘটে, এবং জটিল CSS সিলেক্টর লেআউট কার্যক্রমকে বিলম্বিত করতে পারে।
  • আপনার ResizeObserver কলব্যাকে এমন কোনো কাজ করা থেকে বিরত থাকুন যা ফোর্সড রিফ্লো ট্রিগার করতে পারে।
  • একটি পেজের লেআউট আপডেট করার জন্য প্রয়োজনীয় সময় সাধারণত সেই পেজে থাকা DOM এলিমেন্টের সংখ্যার সাথে বৃদ্ধি পায়। পেজগুলো ResizeObserver ব্যবহার করুক বা না করুক, এই কথাটি সত্য হলেও, একটি পেজের কাঠামোগত জটিলতা বাড়ার সাথে সাথে ResizeObserver কলব্যাকে সম্পাদিত কাজটি তাৎপর্যপূর্ণ হয়ে উঠতে পারে।

উপসংহার

ResizeObserver সব প্রধান ব্রাউজারে উপলব্ধ এবং এটি এলিমেন্ট পর্যায়ে এলিমেন্টের আকার পরিবর্তন পর্যবেক্ষণ করার একটি কার্যকর উপায় প্রদান করে। তবে এই শক্তিশালী API ব্যবহার করার সময় রেন্ডারিংয়ে খুব বেশি দেরি না করার ব্যাপারে সতর্ক থাকতে হবে।