প্যারালাক্সিন'

ভূমিকা

প্যারালাক্স সাইটগুলি সম্প্রতি সব রাগ হয়েছে, শুধু এগুলি একবার দেখুন:

আপনি যদি তাদের সাথে পরিচিত না হন তবে তারা এমন সাইট যেখানে আপনি স্ক্রোল করার সাথে সাথে পৃষ্ঠার ভিজ্যুয়াল কাঠামো পরিবর্তন হয়। সাধারণত পৃষ্ঠা স্কেলের মধ্যে উপাদানগুলি, পৃষ্ঠার স্ক্রোল অবস্থানের সমানুপাতিকভাবে ঘোরান বা সরান৷

একটি ডেমো প্যারালাক্স পৃষ্ঠা
আমাদের ডেমো পৃষ্ঠা প্যারালাক্স প্রভাব সহ সম্পূর্ণ

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

এই মত একটি সমান্তরাল সাইট সাধারণীকরণ করা যুক্তিসঙ্গত:

  • পটভূমি উপাদান যা আপনি উপরে এবং নিচে স্ক্রোল করার সাথে সাথে তাদের অবস্থান, ঘূর্ণন এবং স্কেল পরিবর্তন করুন।
  • পৃষ্ঠার বিষয়বস্তু, যেমন টেক্সট বা ছোট ছবি, যা সাধারণত টপ-টু-বটম ফ্যাশনে স্ক্রোল করে।

আমরা আগে স্ক্রোলিং কার্যকারিতা এবং আপনি আপনার অ্যাপের প্রতিক্রিয়াশীলতা উন্নত করার উপায়গুলি কভার করেছি এবং এই নিবন্ধটি সেই ভিত্তির উপর ভিত্তি করে তৈরি করা হয়েছে তাই এটি পড়ার মূল্য হতে পারে যদি আপনি ইতিমধ্যে এটি না করে থাকেন।

সুতরাং প্রশ্ন হল আপনি যদি একটি প্যারালাক্স স্ক্রলিং সাইট তৈরি করছেন তবে আপনি কি ব্যয়বহুল রিপেইন্টে আটকে আছেন বা কর্মক্ষমতা সর্বাধিক করার জন্য আপনি বিকল্প পদ্ধতি গ্রহণ করতে পারেন? আসুন আমাদের বিকল্পগুলি একবার দেখে নেওয়া যাক।

বিকল্প 1: DOM উপাদান এবং পরম অবস্থান ব্যবহার করুন

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

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

ডিবাউন্সড স্ক্রোল ইভেন্ট ছাড়াই Chrome DevTools।
DevTools একটি একক ফ্রেমে বড় পেইন্ট এবং একাধিক ইভেন্ট-ট্রিগার করা লেআউট দেখাচ্ছে।

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

আসুন আপডেট কোডটিকে স্ক্রোল ইভেন্ট থেকে একটি requestAnimationFrame কলব্যাকে সরিয়ে দেওয়া যাক এবং স্ক্রোল ইভেন্টের কলব্যাকে স্ক্রোল মানটি ক্যাপচার করুন।

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

ডিবাউন্স স্ক্রোল ইভেন্ট সহ Chrome DevTools।
DevTools একটি একক ফ্রেমে বড় পেইন্ট এবং একাধিক ইভেন্ট-ট্রিগার করা লেআউট দেখাচ্ছে।

আমরা এখন প্রতি ফ্রেমে এক বা একশত স্ক্রোল ইভেন্ট পরিচালনা করতে পারি কিন্তু যখনই requestAnimationFrame কলব্যাক চলে এবং আমাদের ভিজ্যুয়াল আপডেটগুলি সম্পাদন করে তখনই আমরা ব্যবহারের জন্য সবচেয়ে সাম্প্রতিক মান সংরক্ষণ করি। মোদ্দা কথা হল আপনি প্রতিবার স্ক্রোল ইভেন্ট গ্রহণ করার সময় ভিজ্যুয়াল আপডেটগুলি জোরপূর্বক করার চেষ্টা থেকে সরে এসেছেন যাতে ব্রাউজার আপনাকে একটি উপযুক্ত উইন্ডো দেয় যাতে সেগুলি করতে হয়৷ তুমি মিষ্টি না?

এই পদ্ধতির সাথে প্রধান সমস্যা, requestAnimationFrame বা না, আমাদের কাছে মূলত পুরো পৃষ্ঠার জন্য একটি স্তর থাকে এবং এই ভিজ্যুয়াল উপাদানগুলিকে চারপাশে সরানোর মাধ্যমে আমাদের বড় (এবং ব্যয়বহুল) পুনরায় রঙের প্রয়োজন হয়। সাধারণত পেইন্টিংটি একটি ব্লকিং অপারেশন (যদিও এটি পরিবর্তিত হচ্ছে ), যার অর্থ ব্রাউজারটি অন্য কোন কাজ করতে পারে না এবং আমরা প্রায়শই আমাদের ফ্রেমের বাজেট 16ms এর উপর দিয়ে চলে যাই এবং জিনিসগুলি অস্থির থাকে।

বিকল্প 2: DOM উপাদান এবং 3D রূপান্তর ব্যবহার করুন

নিখুঁত অবস্থানগুলি ব্যবহার করার পরিবর্তে আমরা আরেকটি পদ্ধতি নিতে পারি তা হল উপাদানগুলিতে 3D রূপান্তর প্রয়োগ করা। এই পরিস্থিতিতে আমরা দেখতে পাই যে 3D রূপান্তর প্রয়োগ করা উপাদানগুলিকে প্রতি এলিমেন্টে একটি নতুন স্তর দেওয়া হয় এবং, ওয়েবকিট ব্রাউজারগুলিতে, এটি প্রায়শই হার্ডওয়্যার কম্পোজিটরে একটি সুইচ ওভার করে। বিকল্প 1-এ, বিপরীতে, আমাদের কাছে পৃষ্ঠাটির জন্য একটি বড় স্তর ছিল যা কিছু পরিবর্তন হলে পুনরায় রং করা প্রয়োজন এবং সমস্ত পেইন্টিং এবং কম্পোজিটিং CPU দ্বারা পরিচালিত হয়েছিল।

এর মানে এই বিকল্পের সাথে, জিনিসগুলি আলাদা: আমাদের কাছে সম্ভাব্য যে কোনও উপাদানের জন্য একটি স্তর রয়েছে যাতে আমরা একটি 3D রূপান্তর প্রয়োগ করি। এই বিন্দু থেকে যদি আমরা যা করি তা হলে উপাদানগুলির আরও রূপান্তর হলে আমাদের স্তরটিকে পুনরায় রঙ করার প্রয়োজন হবে না, এবং GPU উপাদানগুলিকে চারপাশে সরানো এবং চূড়ান্ত পৃষ্ঠাটি একসাথে সংমিশ্রণ করতে পারে।

অনেক সময় মানুষ শুধু -webkit-transform: translateZ(0); হ্যাক করুন এবং যাদুকর কর্মক্ষমতা উন্নতি দেখুন, এবং এটি আজ কাজ করার সময় সমস্যা আছে:

  1. এটি ক্রস-ব্রাউজার সামঞ্জস্যপূর্ণ নয়।
  2. এটি প্রতিটি রূপান্তরিত উপাদানের জন্য একটি নতুন স্তর তৈরি করে ব্রাউজারের হাতকে জোর করে। অনেক স্তর অন্যান্য কর্মক্ষমতা প্রতিবন্ধকতা আনতে পারে, তাই অল্প ব্যবহার করুন!
  3. এটি কিছু WebKit পোর্টের জন্য নিষ্ক্রিয় করা হয়েছে (নীচ থেকে চতুর্থ বুলেট!)

আপনি যদি 3D অনুবাদের পথে যান তবে সতর্ক থাকুন, এটি আপনার সমস্যার একটি অস্থায়ী সমাধান! আদর্শভাবে বলতে গেলে আমরা 3D এর মতো 2D রূপান্তর থেকে অনুরূপ রেন্ডারিং বৈশিষ্ট্য দেখতে পাব। ব্রাউজারগুলি একটি অসাধারণ হারে অগ্রগতি করছে, তাই আশা করি তার আগে আমরা যা দেখতে পাব।

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

বিকল্প 3: একটি নির্দিষ্ট অবস্থানের ক্যানভাস বা WebGL ব্যবহার করুন

আমরা যে চূড়ান্ত বিকল্পটি বিবেচনা করতে যাচ্ছি তা হল পৃষ্ঠার পিছনে একটি নির্দিষ্ট অবস্থানের ক্যানভাস ব্যবহার করা যেখানে আমরা আমাদের রূপান্তরিত চিত্রগুলি আঁকব। প্রথম নজরে এটি সবচেয়ে কার্যকরী সমাধান বলে মনে হতে পারে না, তবে এই পদ্ধতির কিছু সুবিধা রয়েছে:

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

একটি ক্যানভাস উপাদান ব্যবহার করা আমাদের একটি নতুন স্তর দেয়, কিন্তু এটি শুধুমাত্র একটি স্তর, যেখানে বিকল্প 2-এ আমাদের প্রতিটি উপাদানের জন্য একটি 3D রূপান্তর প্রয়োগের সাথে একটি নতুন স্তর দেওয়া হয়েছিল, তাই আমাদের কাছে সেই সমস্ত স্তরগুলিকে একত্রে সংমিশ্রিত করার কাজের চাপ বেড়েছে৷ ট্রান্সফর্মের ভিন্ন ভিন্ন ক্রস-ব্রাউজার বাস্তবায়নের আলোকে এটিও আজকের সবচেয়ে সামঞ্জস্যপূর্ণ সমাধান।


/**
 * Updates and draws in the underlying visual elements to the canvas.
 */
function updateElements () {

  var relativeY = lastScrollY / h;

  // Fill the canvas up
  context.fillStyle = "#1e2124";
  context.fillRect(0, 0, canvas.width, canvas.height);

  // Draw the background
  context.drawImage(bg, 0, pos(0, -3600, relativeY, 0));

  // Draw each of the blobs in turn
  context.drawImage(blob1, 484, pos(254, -4400, relativeY, 0));
  context.drawImage(blob2, 84, pos(954, -5400, relativeY, 0));
  context.drawImage(blob3, 584, pos(1054, -3900, relativeY, 0));
  context.drawImage(blob4, 44, pos(1400, -6900, relativeY, 0));
  context.drawImage(blob5, -40, pos(1730, -5900, relativeY, 0));
  context.drawImage(blob6, 325, pos(2860, -7900, relativeY, 0));
  context.drawImage(blob7, 725, pos(2550, -4900, relativeY, 0));
  context.drawImage(blob8, 570, pos(2300, -3700, relativeY, 0));
  context.drawImage(blob9, 640, pos(3700, -9000, relativeY, 0));

  // Allow another rAF call to be scheduled
  ticking = false;
}

/**
 * Calculates a relative disposition given the page's scroll
 * range normalized from 0 to 1
 * @param {number} base The starting value.
 * @param {number} range The amount of pixels it can move.
 * @param {number} relY The normalized scroll value.
 * @param {number} offset A base normalized value from which to start the scroll behavior.
 * @returns {number} The updated position value.
 */
function pos(base, range, relY, offset) {
  return base + limit(0, 1, relY - offset) * range;
}

/**
 * Clamps a number to a range.
 * @param {number} min The minimum value.
 * @param {number} max The maximum value.
 * @param {number} value The value to limit.
 * @returns {number} The clamped value.
 */
function limit(min, max, value) {
  return Math.max(min, Math.min(max, value));
}

এই পদ্ধতিটি সত্যিই কাজ করে যেখানে আপনি বড় ইমেজ (অথবা অন্যান্য উপাদান যা সহজেই একটি ক্যানভাসে লেখা যায়) নিয়ে কাজ করছেন এবং অবশ্যই টেক্সটের বড় ব্লকের সাথে কাজ করা আরও চ্যালেঞ্জিং হবে, কিন্তু আপনার সাইটের উপর নির্ভর করে এটি প্রমাণিত হতে পারে সবচেয়ে উপযুক্ত সমাধান। যদি আপনাকে ক্যানভাসে পাঠ্যের সাথে মোকাবিলা করতে হয় তবে আপনাকে fillText API পদ্ধতিটি ব্যবহার করতে হবে, তবে এটি অ্যাক্সেসযোগ্যতার মূল্যে (আপনি কেবল পাঠ্যটিকে একটি বিটম্যাপে রাস্টারাইজ করেছেন!) এবং আপনাকে এখন লাইন মোড়ানোর সাথে মোকাবিলা করতে হবে এবং অন্যান্য সমস্যার একটি সম্পূর্ণ গাদা। আপনি যদি এটি এড়াতে পারেন তবে আপনার সত্যিই উচিত এবং উপরের রূপান্তর পদ্ধতি ব্যবহার করে আপনাকে সম্ভবত আরও ভাল পরিবেশন করা হবে।

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

আপনার তাৎক্ষণিক প্রতিক্রিয়া হতে পারে যে WebGL অতিমাত্রায়, বা এটি সমর্থনের দিক থেকে সর্বব্যাপী নয়, কিন্তু আপনি যদি Three.js এর মতো কিছু ব্যবহার করেন তবে আপনি সর্বদা একটি ক্যানভাস উপাদান ব্যবহারে ফিরে যেতে পারেন এবং আপনার কোডটি সামঞ্জস্যপূর্ণভাবে বিমূর্ত হয় এবং বন্ধুত্বপূর্ণ পদ্ধতিতে। উপযুক্ত API সমর্থন পরীক্ষা করার জন্য আমাদের যা করতে হবে তা হল Modernizr ব্যবহার করুন:

// check for WebGL support, otherwise switch to canvas
if (Modernizr.webgl) {
  renderer = new THREE.WebGLRenderer();
} else if (Modernizr.canvas) {
  renderer = new THREE.CanvasRenderer();
}

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

সিদ্ধান্ত আপনার

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

রূপান্তর, অবশ্যই 3D ধরনের, আপনাকে DOM উপাদানগুলির সাথে সরাসরি কাজ করার এবং একটি কঠিন ফ্রেম রেট অর্জন করার ক্ষমতা প্রদান করে। এখানে সাফল্যের চাবিকাঠি হল আপনি যেখানেই পারেন পেইন্টিং এড়ান এবং সহজভাবে চেষ্টা করুন এবং উপাদানগুলিকে চারপাশে সরান৷ মনে রাখবেন যে ওয়েবকিট ব্রাউজারগুলি যেভাবে স্তরগুলি তৈরি করে তা অপরিহার্যভাবে অন্যান্য ব্রাউজার ইঞ্জিনগুলির সাথে সম্পর্কযুক্ত নয়, তাই সেই সমাধানে নিজেকে প্রতিশ্রুতিবদ্ধ করার আগে এটি পরীক্ষা করতে ভুলবেন না৷

আপনি যদি ব্রাউজারগুলির শীর্ষ স্তরের জন্য লক্ষ্য করে থাকেন এবং ক্যানভাস ব্যবহার করে সাইটটি রেন্ডার করতে সক্ষম হন তবে এটি আপনার জন্য সেরা বিকল্প হতে পারে। অবশ্যই আপনি যদি Three.js ব্যবহার করেন তবে আপনার প্রয়োজনীয় সমর্থনের উপর নির্ভর করে আপনি খুব সহজেই রেন্ডারারগুলির মধ্যে অদলবদল এবং পরিবর্তন করতে সক্ষম হবেন।

উপসংহার

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

এবং সর্বদা হিসাবে, আপনি যে পদ্ধতির চেষ্টা করুন: এটি অনুমান করবেন না, এটি পরীক্ষা করুন