একটি থিম সুইচ উপাদান নির্মাণ

কীভাবে একটি অভিযোজিত এবং অ্যাক্সেসযোগ্য থিম সুইচ উপাদান তৈরি করা যায় তার একটি ভিত্তিগত ওভারভিউ।

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

সহজ দৃশ্যমানতার জন্য ডেমো বোতামের আকার বৃদ্ধি করা হয়েছে

আপনি যদি ভিডিও পছন্দ করেন তবে এখানে এই পোস্টটির একটি YouTube সংস্করণ রয়েছে:

ওভারভিউ

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

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

ডায়াগ্রাম জাভাস্ক্রিপ্ট পৃষ্ঠা লোড এবং নথি ইন্টারঅ্যাকশন ইভেন্টগুলির একটি পূর্বরূপ দেখায় সামগ্রিকভাবে দেখানোর জন্য থিম সেট করার জন্য 4টি পথ রয়েছে

মার্কআপ

টগলের জন্য একটি <button> ব্যবহার করা উচিত, কারণ আপনি ব্রাউজার-প্রদত্ত ইন্টারঅ্যাকশন ইভেন্ট এবং বৈশিষ্ট্যগুলি যেমন ক্লিক ইভেন্ট এবং ফোকাসযোগ্যতা থেকে উপকৃত হবেন।

বোতাম

CSS থেকে ব্যবহারের জন্য বোতামটির একটি ক্লাস এবং JavaScript থেকে ব্যবহারের জন্য একটি আইডি প্রয়োজন৷ উপরন্তু, যেহেতু বোতামের বিষয়বস্তু পাঠ্যের পরিবর্তে একটি আইকন, তাই বোতামটির উদ্দেশ্য সম্পর্কে তথ্য প্রদানের জন্য একটি শিরোনাম বৈশিষ্ট্য যোগ করুন। সবশেষে, আইকন বোতামের অবস্থা ধরে রাখতে একটি [aria-label] যোগ করুন, যাতে স্ক্রীন রিডাররা দৃষ্টি প্রতিবন্ধীদের সাথে থিমের অবস্থা শেয়ার করতে পারে।

<button 
  class="theme-toggle" 
  id="theme-toggle" 
  title="Toggles light & dark" 
  aria-label="auto"
>
  …
</button>

aria-label এবং aria-live ভদ্র

স্ক্রীন রিডারদের বোঝাতে যে aria-label পরিবর্তন ঘোষণা করা উচিত, বোতামে aria-live="polite" যোগ করুন।

<button 
  class="theme-toggle" 
  id="theme-toggle" 
  title="Toggles light & dark" 
  aria-label="auto" 
  aria-live="polite"
>
  …
</button>

এই মার্কআপ সংযোজনটি স্ক্রীন রিডারদেরকে aria-live="assertive" এর পরিবর্তে বিনীতভাবে, ব্যবহারকারীকে কী পরিবর্তন হয়েছে তা বলুন। এই বোতামের ক্ষেত্রে, aria-label কী হয়েছে তার উপর নির্ভর করে এটি "আলো" বা "অন্ধকার" ঘোষণা করবে।

স্কেলযোগ্য ভেক্টর গ্রাফিক (SVG) আইকন

SVG ন্যূনতম মার্কআপ সহ উচ্চ-মানের, মাপযোগ্য আকার তৈরি করার একটি উপায় প্রদান করে। বোতামের সাথে ইন্টারঅ্যাক্ট করা ভেক্টরের জন্য নতুন ভিজ্যুয়াল স্টেট ট্রিগার করতে পারে, যা SVG কে আইকনগুলির জন্য দুর্দান্ত করে তোলে।

নিম্নলিখিত SVG মার্কআপটি <button> এর ভিতরে যায়:

<svg class="sun-and-moon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
  …
</svg>

aria-hidden যোগ করা হয়েছে SVG উপাদানে যাতে স্ক্রিন রিডাররা এটিকে উপেক্ষা করতে জানে কারণ এটিকে উপস্থাপনামূলক হিসেবে চিহ্নিত করা হয়েছে। এটি একটি বোতামের ভিতরে আইকনের মতো ভিজ্যুয়াল সজ্জার জন্য করা দুর্দান্ত। উপাদানটিতে প্রয়োজনীয় viewBox বৈশিষ্ট্য ছাড়াও, একই কারণে উচ্চতা এবং প্রস্থ যোগ করুন যাতে চিত্রগুলি ইনলাইন আকার পেতে পারে

সূর্য

সূর্যের আলোর সাথে দেখানো সূর্যের আইকনটি বিবর্ণ হয়ে গেছে এবং একটি হটপিঙ্ক তীরটি কেন্দ্রে বৃত্তের দিকে নির্দেশ করছে।

সান গ্রাফিক একটি বৃত্ত এবং রেখা নিয়ে গঠিত যা SVG-এর সুবিধামত আকার রয়েছে। <circle> cx এবং cy বৈশিষ্ট্যগুলিকে 12 এ সেট করে কেন্দ্রীভূত করা হয়, যা ভিউপোর্ট আকারের অর্ধেক (24), এবং তারপরে 6 এর একটি ব্যাসার্ধ ( r ) দেওয়া হয় যা আকার নির্ধারণ করে।

<svg class="sun-and-moon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
  <circle class="sun" cx="12" cy="12" r="6" mask="url(#moon-mask)" fill="currentColor" />
</svg>

অতিরিক্তভাবে, মাস্ক প্রপার্টি একটি SVG এলিমেন্টের আইডি নির্দেশ করে, যা আপনি পরবর্তী তৈরি করবেন এবং অবশেষে একটি ফিল কালার দেওয়া হবে যা currentColor সাথে পৃষ্ঠার পাঠ্যের রঙের সাথে মিলে যায়।

সূর্যের রশ্মি

সূর্যের কেন্দ্রে দেখানো সূর্যের আইকনটি বিবর্ণ হয়ে গেছে এবং একটি হটপিঙ্ক তীরটি সূর্যরশ্মির দিকে নির্দেশ করছে।

এরপরে, একটি গ্রুপ এলিমেন্ট <g> গ্রুপের ভিতরে, বৃত্তের ঠিক নীচে সূর্যরশ্মি লাইন যোগ করা হয়।

<svg class="sun-and-moon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
  <circle class="sun" cx="12" cy="12" r="6" mask="url(#moon-mask)" fill="currentColor" />
  <g class="sun-beams" stroke="currentColor">
    <line x1="12" y1="1" x2="12" y2="3" />
    <line x1="12" y1="21" x2="12" y2="23" />
    <line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
    <line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
    <line x1="1" y1="12" x2="3" y2="12" />
    <line x1="21" y1="12" x2="23" y2="12" />
    <line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
    <line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
  </g>
</svg>

এবার, ফিল করার মানের পরিবর্তে currentColor হচ্ছে, প্রতিটি লাইনের স্ট্রোক সেট করা হয়েছে। রেখা এবং বৃত্তের আকার বিম সহ একটি সুন্দর সূর্য তৈরি করে।

চাঁদ

আলো (সূর্য) এবং অন্ধকার (চাঁদের) মধ্যে একটি নিরবচ্ছিন্ন পরিবর্তনের বিভ্রম তৈরি করতে, চাঁদ একটি SVG মুখোশ ব্যবহার করে সূর্যের আইকনের একটি বৃদ্ধি।

<svg class="sun-and-moon" aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
  <circle class="sun" cx="12" cy="12" r="6" mask="url(#moon-mask)" fill="currentColor" />
  <g class="sun-beams" stroke="currentColor">
    …
  </g>
  <mask class="moon" id="moon-mask">
    <rect x="0" y="0" width="100%" height="100%" fill="white" />
    <circle cx="24" cy="10" r="6" fill="black" />
  </mask>
</svg>
মাস্কিং কিভাবে কাজ করে তা দেখানোর জন্য তিনটি উল্লম্ব স্তর সহ গ্রাফিক। উপরের স্তরটি একটি কালো বৃত্ত সহ একটি সাদা বর্গক্ষেত্র। মাঝের স্তরটি সূর্যের আইকন। নীচের স্তরটি ফলাফল হিসাবে লেবেলযুক্ত এবং এটি একটি কাটআউট সহ সূর্যের আইকনটি দেখায় যেখানে উপরের স্তরটি কালো বৃত্ত রয়েছে।

এসভিজি সহ মাস্কগুলি শক্তিশালী, সাদা এবং কালো রঙগুলিকে অন্য গ্রাফিকের অংশগুলি অপসারণ বা অন্তর্ভুক্ত করার অনুমতি দেয়। সূর্যের আইকনটি একটি SVG মাস্ক সহ একটি চাঁদের <circle> আকৃতি দ্বারা গ্রহন করা হবে, কেবল একটি মুখোশ এলাকায় এবং বাইরে একটি বৃত্তের আকৃতি সরানোর মাধ্যমে।

CSS লোড না হলে কি হবে?

ভিতরে সূর্য আইকন সহ একটি সাধারণ ব্রাউজার বোতামের স্ক্রিনশট।

আপনার SVG পরীক্ষা করা ভাল হতে পারে যেন CSS লোড না করে নিশ্চিত করে যে ফলাফলটি খুব বড় নয় বা লেআউট সমস্যা সৃষ্টি করছে না। SVG-তে ইনলাইন উচ্চতা এবং প্রস্থের বৈশিষ্ট্যগুলি এবং CSS লোড না হলে ব্রাউজারকে ব্যবহার করার জন্য ন্যূনতম শৈলীর নিয়মগুলি এবং currentColor ব্যবহার। এটি নেটওয়ার্ক টার্বুলেন্সের বিরুদ্ধে চমৎকার প্রতিরক্ষামূলক শৈলী তৈরি করে।

লেআউট

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

শৈলী

.theme-toggle শৈলী

<button> উপাদানটি আইকনের আকার এবং শৈলীর ধারক। এই অভিভাবক প্রসঙ্গটি SVG-এ যাওয়ার জন্য অভিযোজিত রং এবং মাপ ধারণ করবে।

প্রথম কাজটি হল বোতামটিকে একটি বৃত্ত করা এবং ডিফল্ট বোতাম শৈলীগুলি সরানো:

.theme-toggle {
  --size: 2rem;
  
  background: none;
  border: none;
  padding: 0;

  inline-size: var(--size);
  block-size: var(--size);
  aspect-ratio: 1;
  border-radius: 50%;
}

এরপরে, কিছু মিথস্ক্রিয়া শৈলী যোগ করুন। মাউস ব্যবহারকারীদের জন্য একটি কার্সার শৈলী যোগ করুন। touch-action: manipulation দ্রুত প্রতিক্রিয়াশীল স্পর্শ অভিজ্ঞতার জন্য ম্যানিপুলেশন। আধা-স্বচ্ছ হাইলাইট সরান iOS বোতামগুলিতে প্রযোজ্য। সবশেষে, উপাদানটির প্রান্ত থেকে কিছু শ্বাস-প্রশ্বাসের ঘরের ফোকাস স্টেটের রূপরেখা দিন:

.theme-toggle {
  --size: 2rem;

  background: none;
  border: none;
  padding: 0;

  inline-size: var(--size);
  block-size: var(--size);
  aspect-ratio: 1;
  border-radius: 50%;

  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  outline-offset: 5px;
}

বোতামের ভিতরের SVG-এরও কিছু স্টাইল প্রয়োজন। SVG বোতামের আকারের সাথে মানানসই হওয়া উচিত এবং চাক্ষুষ স্নিগ্ধতার জন্য, লাইনের প্রান্তগুলিকে বৃত্তাকার করা উচিত:

.theme-toggle {
  --size: 2rem;

  background: none;
  border: none;
  padding: 0;

  inline-size: var(--size);
  block-size: var(--size);
  aspect-ratio: 1;
  border-radius: 50%;

  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  outline-offset: 5px;

  & > svg {
    inline-size: 100%;
    block-size: 100%;
    stroke-linecap: round;
  }
}

hover মিডিয়া ক্যোয়ারী সহ অভিযোজিত আকার

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

.theme-toggle {
  --size: 2rem;
  
  
  @media (hover: none) {
    --size: 48px;
  }
}

সূর্য এবং চাঁদ SVG শৈলী

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

হালকা থিম

ALT_TEXT_HERE

SVG আকারের কেন্দ্র থেকে স্কেল এবং ঘোরানো অ্যানিমেশনগুলি ঘটতে, তাদের transform-origin: center center । বোতাম দ্বারা উপলব্ধ অভিযোজিত রং এখানে আকার দ্বারা ব্যবহার করা হয়. চাঁদ এবং সূর্য তাদের ফিল করার জন্য var(--icon-fill) এবং var(--icon-fill-hover) প্রদত্ত বোতাম ব্যবহার করে, যখন সূর্যরশ্মি স্ট্রোকের জন্য ভেরিয়েবল ব্যবহার করে।

.sun-and-moon {
  & > :is(.moon, .sun, .sun-beams) {
    transform-origin: center center;
  }

  & > :is(.moon, .sun) {
    fill: var(--icon-fill);

    @nest .theme-toggle:is(:hover, :focus-visible) > & {
      fill: var(--icon-fill-hover);
    }
  }

  & > .sun-beams {
    stroke: var(--icon-fill);
    stroke-width: 2px;

    @nest .theme-toggle:is(:hover, :focus-visible) & {
      stroke: var(--icon-fill-hover);
    }
  }
}

গাঢ় থিম

ALT_TEXT_HERE

চাঁদের শৈলীগুলির জন্য সূর্যের রশ্মিগুলি অপসারণ করতে হবে, সূর্যের বৃত্তকে স্কেল করতে হবে এবং বৃত্তের মুখোশটি সরাতে হবে।

.sun-and-moon {
  @nest [data-theme="dark"] & {
    & > .sun {
      transform: scale(1.75);
    }

    & > .sun-beams {
      opacity: 0;
    }

    & > .moon > circle {
      transform: translateX(-7px);

      @supports (cx: 1) {
        transform: translateX(0);
        cx: 17;
      }
    }
  }
}

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

অ্যানিমেশন

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

মিডিয়া প্রশ্ন শেয়ার করা এবং ইজিং আমদানি করা

ব্যবহারকারীর অপারেটিং সিস্টেম গতি পছন্দের পিছনে ট্রানজিশন এবং অ্যানিমেশন রাখা সহজ করার জন্য, পোস্টসিএসএস প্লাগইন কাস্টম মিডিয়া মিডিয়া ক্যোয়ারী ভেরিয়েবল সিনট্যাক্সের জন্য খসড়া করা CSS স্পেসিফিকেশন ব্যবহার করতে সক্ষম করে:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

/* usage example */
@media (--motionOK) {
  .sun {
    transition: transform .5s var(--ease-elastic-3);
  }
}

অনন্য এবং সহজে ব্যবহারযোগ্য CSS ইজিংয়ের জন্য, Open Props- এর ইজিং অংশ আমদানি করুন:

@import "https://unpkg.com/open-props/easings.min.css";

/* usage example */
.sun {
  transition: transform .5s var(--ease-elastic-3);
}

সূর্য

বাউন্সি ইজিং সহ এই প্রভাবটি অর্জন করে সূর্যের পরিবর্তনগুলি চাঁদের চেয়ে বেশি খেলাধুলাপূর্ণ হবে। সূর্যকিরণগুলি ঘোরার সাথে সাথে অল্প পরিমাণে বাউন্স করা উচিত এবং সূর্যের কেন্দ্রটি দাঁড়িপাল্লার সাথে সাথে অল্প পরিমাণে বাউন্স করা উচিত।

ডিফল্ট (হালকা থিম) শৈলীগুলি রূপান্তরকে সংজ্ঞায়িত করে এবং অন্ধকার থিম শৈলীগুলি আলোতে রূপান্তরের জন্য কাস্টমাইজেশনগুলিকে সংজ্ঞায়িত করে:

​​.sun-and-moon {
  @media (--motionOK) {
    & > .sun {
      transition: transform .5s var(--ease-elastic-3);
    }

    & > .sun-beams {
      transition: 
        transform .5s var(--ease-elastic-4),
        opacity .5s var(--ease-3)
      ;
    }

    @nest [data-theme="dark"] & {
      & > .sun {
        transform: scale(1.75);
        transition-timing-function: var(--ease-3);
        transition-duration: .25s;
      }

      & > .sun-beams {
        transform: rotateZ(-25deg);
        transition-duration: .15s;
      }
    }
  }
}

Chrome DevTools-এর অ্যানিমেশন প্যানেলে, আপনি অ্যানিমেশন ট্রানজিশনের জন্য একটি টাইমলাইন খুঁজে পেতে পারেন। মোট অ্যানিমেশনের সময়কাল, উপাদানগুলি এবং সহজ করার সময় পরিদর্শন করা যেতে পারে।

হালকা থেকে অন্ধকার রূপান্তর
অন্ধকার থেকে হালকা রূপান্তর

চাঁদ

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

বিলম্বের সাথে সময় এবং সময়কাল এই রূপান্তরটি পরিষ্কার করার জন্য গুরুত্বপূর্ণ। যদি খুব তাড়াতাড়ি সূর্যগ্রহণ হয়, উদাহরণস্বরূপ, রূপান্তরটি সাজানো বা কৌতুকপূর্ণ মনে হয় না, এটি বিশৃঙ্খল বোধ করে।

​​.sun-and-moon {
  @media (--motionOK) {
    & .moon > circle {
      transform: translateX(-7px);
      transition: transform .25s var(--ease-out-5);

      @supports (cx: 1) {
        transform: translateX(0);
        cx: 17;
        transition: cx .25s var(--ease-out-5);
      }
    }

    @nest [data-theme="dark"] & {
      & > .moon > circle {
        transition-delay: .25s;
        transition-duration: .5s;
      }
    }
  }
}
হালকা থেকে অন্ধকার রূপান্তর
অন্ধকার থেকে হালকা রূপান্তর

কম গতি পছন্দ করে

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

জাভাস্ক্রিপ্ট

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

পৃষ্ঠা লোড অভিজ্ঞতা

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

<script src="./theme-toggle.js"></script>

এটি অর্জন করার জন্য, নথিতে একটি প্লেইন <script> ট্যাগ <head> প্রথমে লোড করা হয়, যেকোনো CSS বা <body> মার্কআপের আগে। ব্রাউজার যখন এইরকম একটি অচিহ্নিত স্ক্রিপ্টের মুখোমুখি হয়, তখন এটি কোডটি চালায় এবং বাকি HTML এর আগে এটি কার্যকর করে। এই ব্লকিং মুহূর্তটি অল্প ব্যবহার করে, মূল CSS পেজটি পেইন্ট করার আগে HTML অ্যাট্রিবিউট সেট করা সম্ভব, এইভাবে একটি ফ্ল্যাশ বা রঙ প্রতিরোধ করা যায়।

জাভাস্ক্রিপ্ট প্রথমে স্থানীয় সঞ্চয়স্থানে ব্যবহারকারীর পছন্দের জন্য পরীক্ষা করে এবং সঞ্চয়স্থানে কিছু না পাওয়া গেলে সিস্টেম পছন্দ চেক করতে ফলব্যাক করে:

const storageKey = 'theme-preference'

const getColorPreference = () => {
  if (localStorage.getItem(storageKey))
    return localStorage.getItem(storageKey)
  else
    return window.matchMedia('(prefers-color-scheme: dark)').matches
      ? 'dark'
      : 'light'
}

স্থানীয় স্টোরেজে ব্যবহারকারীর পছন্দ সেট করার জন্য একটি ফাংশন পরবর্তী পার্স করা হয়েছে:

const setPreference = () => {
  localStorage.setItem(storageKey, theme.value)
  reflectPreference()
}

পছন্দের সাথে ডকুমেন্ট পরিবর্তন করার জন্য একটি ফাংশন অনুসরণ করে।

const reflectPreference = () => {
  document.firstElementChild
    .setAttribute('data-theme', theme.value)

  document
    .querySelector('#theme-toggle')
    ?.setAttribute('aria-label', theme.value)
}

এই মুহুর্তে লক্ষ্য করা একটি গুরুত্বপূর্ণ বিষয় হল HTML নথি পার্সিং অবস্থা। ব্রাউজারটি এখনও "#theme-toggle" বোতাম সম্পর্কে জানে না, কারণ <head> ট্যাগ সম্পূর্ণভাবে পার্স করা হয়নি। যাইহোক, ব্রাউজারে একটি document.firstElementChild , ওরফে <html> ট্যাগ আছে। ফাংশন উভয়কে সিঙ্কে রাখার জন্য সেট করার চেষ্টা করে, কিন্তু প্রথম রানে শুধুমাত্র HTML ট্যাগ সেট করতে সক্ষম হবে। querySelector প্রথমে কিছু খুঁজে পাবে না এবং ঐচ্ছিক চেইনিং অপারেটর নিশ্চিত করে যে কোন সিনট্যাক্স ত্রুটি নেই যখন এটি খুঁজে পাওয়া যায় না এবং setAttribute ফাংশনটি চালু করার চেষ্টা করা হয়।

এর পরে, সেই ফাংশন reflectPreference() অবিলম্বে বলা হয় যাতে HTML নথিতে তার data-theme বৈশিষ্ট্য সেট থাকে:

reflectPreference()

বোতামটির এখনও অ্যাট্রিবিউটের প্রয়োজন, তাই পৃষ্ঠা লোড ইভেন্টের জন্য অপেক্ষা করুন, তারপরে প্রশ্ন করা, শ্রোতাদের যোগ করা এবং বৈশিষ্ট্যগুলি সেট করা নিরাপদ হবে:

window.onload = () => {
  // set on load so screen readers can get the latest value on the button
  reflectPreference()

  // now this script can find and listen for clicks on the control
  document
    .querySelector('#theme-toggle')
    .addEventListener('click', onClick)
}

টগল করার অভিজ্ঞতা

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

const onClick = () => {
  theme.value = theme.value === 'light'
    ? 'dark'
    : 'light'

  setPreference()
}

সিস্টেমের সাথে সিঙ্ক্রোনাইজ করা হচ্ছে

এই থিম সুইচের অনন্য হল সিস্টেম পছন্দের সাথে সিঙ্ক্রোনাইজেশন যখন এটি পরিবর্তন হয়। একটি পৃষ্ঠা এবং এই উপাদানটি দৃশ্যমান থাকার সময় যদি একজন ব্যবহারকারী তাদের সিস্টেম পছন্দ পরিবর্তন করে, তাহলে থিম সুইচটি নতুন ব্যবহারকারীর পছন্দের সাথে মেলে, যেন ব্যবহারকারী একই সময়ে থিম সুইচের সাথে ইন্টারঅ্যাক্ট করেছে যেভাবে এটি সিস্টেম সুইচ করেছে৷

জাভাস্ক্রিপ্ট এবং একটি matchMedia ইভেন্টের মাধ্যমে এটি অর্জন করুন একটি মিডিয়া ক্যোয়ারীতে পরিবর্তনের জন্য শুনুন:

window
  .matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', ({matches:isDark}) => {
    theme.value = isDark ? 'dark' : 'light'
    setPreference()
  })
MacOS সিস্টেম পছন্দ পরিবর্তন করা থিম সুইচ অবস্থা পরিবর্তন করে

উপসংহার

এখন যেহেতু আপনি জানেন যে আমি কীভাবে এটি করেছি, আপনি কেমন হবে‽ 🙂৷

আসুন আমাদের পদ্ধতির বৈচিত্র্য আনুন এবং ওয়েবে তৈরি করার সমস্ত উপায় শিখি। একটি ডেমো তৈরি করুন, আমাকে লিঙ্কগুলি টুইট করুন এবং আমি নীচের সম্প্রদায়ের রিমিক্স বিভাগে এটি যুক্ত করব!

কমিউনিটি রিমিক্স