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

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

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

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

আপনি যদি ভিডিও পছন্দ করেন তবে এখানে এই পোস্টটির একটি 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: 1px) {
        transform: translateX(0);
        cx: 17px;
      }
    }
  }
}

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

অ্যানিমেশন

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

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

ব্যবহারকারীর অপারেটিং সিস্টেম গতি পছন্দের পিছনে ট্রানজিশন এবং অ্যানিমেশন রাখা সহজ করার জন্য, পোস্টসিএসএস প্লাগইন কাস্টম মিডিয়া মিডিয়া ক্যোয়ারী ভেরিয়েবল সিনট্যাক্সের জন্য খসড়া করা 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: 1px) {
        transform: translateX(0);
        cx: 17px;
        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 সিস্টেম পছন্দ পরিবর্তন করা থিম সুইচ অবস্থা পরিবর্তন করে

উপসংহার

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

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

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

,

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

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

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

আপনি যদি ভিডিও পছন্দ করেন তবে এখানে এই পোস্টটির একটি 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: 1px) {
        transform: translateX(0);
        cx: 17px;
      }
    }
  }
}

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

অ্যানিমেশন

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

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

ব্যবহারকারীর অপারেটিং সিস্টেম গতি পছন্দের পিছনে ট্রানজিশন এবং অ্যানিমেশন রাখা সহজ করার জন্য, পোস্টসিএসএস প্লাগইন কাস্টম মিডিয়া মিডিয়া ক্যোয়ারী ভেরিয়েবল সিনট্যাক্সের জন্য খসড়া করা 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: 1px) {
        transform: translateX(0);
        cx: 17px;
        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 সিস্টেম পছন্দ পরিবর্তন করা থিম সুইচ অবস্থা পরিবর্তন করে

উপসংহার

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

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

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

,

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

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

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

আপনি যদি ভিডিও পছন্দ করেন তবে এখানে এই পোস্টটির একটি 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: 1px) {
        transform: translateX(0);
        cx: 17px;
      }
    }
  }
}

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

অ্যানিমেশন

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

মিডিয়া অনুসন্ধানগুলি ভাগ করে নেওয়া এবং উপলভ্য আমদানি

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

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

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

অনন্য এবং সহজেই সিএসএস ইজিং ব্যবহার করার জন্য, ওপেন প্রপসগুলির ইজিং অংশটি আমদানি করুন:

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

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

সূর্য

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

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

​​.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;
      }
    }
  }
}

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

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

চাঁদ

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

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

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

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

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

হ্রাস গতি পছন্দ

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

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

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

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

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

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

এটি অর্জনের জন্য, কোনও সিএসএস বা <body> মার্কআপের আগে প্রথমে ডকুমেন্ট <head> এর একটি সাধারণ <script> ট্যাগ লোড করা হয়। যখন ব্রাউজারটি এ জাতীয় একটি অচিহ্নিত স্ক্রিপ্টের মুখোমুখি হয়, তখন এটি কোডটি চালায় এবং বাকি এইচটিএমএল এর আগে এটি কার্যকর করে। এই ব্লকিং মুহুর্তটি অল্প পরিমাণে ব্যবহার করে, প্রধান সিএসএস পৃষ্ঠাটি আঁকার আগে এইচটিএমএল বৈশিষ্ট্যটি সেট করা সম্ভব, এইভাবে কোনও ফ্ল্যাশ বা রঙ প্রতিরোধ করে।

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

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)
}

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

এরপরে, সেই ফাংশন reflectPreference() অবিলম্বে বলা হয় তাই এইচটিএমএল নথিতে এর 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()
  })
ম্যাকোস সিস্টেমের পছন্দ পরিবর্তন করা থিম স্যুইচ স্টেট পরিবর্তন করে

উপসংহার

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

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

সম্প্রদায় রিমিক্স

,

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

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

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

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

ওভারভিউ

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

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

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

মার্কআপ

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

বোতাম

বোতামটির সিএসএস থেকে ব্যবহারের জন্য একটি শ্রেণি এবং জাভাস্ক্রিপ্ট থেকে ব্যবহারের জন্য একটি আইডি প্রয়োজন। অতিরিক্তভাবে, যেহেতু বোতামের সামগ্রীটি পাঠ্যের পরিবর্তে একটি আইকন, তাই বোতামের উদ্দেশ্য সম্পর্কে তথ্য সরবরাহ করতে একটি শিরোনাম বৈশিষ্ট্য যুক্ত করুন। সর্বশেষে, আইকন বোতামের অবস্থা ধরে রাখতে একটি [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 কী হয়েছে তার উপর নির্ভর করে "হালকা" বা "গা dark ়" ঘোষণা করবে।

স্কেলেবল ভেক্টর গ্রাফিক (এসভিজি) আইকন

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

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

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

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

সূর্য

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

সূর্যের গ্রাফিকটিতে একটি বৃত্ত এবং লাইন রয়েছে যা এসভিজি সুবিধার্থে আকার ধারণ করে। <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>

অতিরিক্তভাবে, মুখোশ সম্পত্তিটি একটি এসভিজি এলিমেন্টের আইডির দিকে ইঙ্গিত করে, যা আপনি পরবর্তী তৈরি করবেন এবং অবশেষে একটি ভরাট রঙ দিয়েছেন যা পৃষ্ঠার পাঠ্য রঙের সাথে 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 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>
মাস্কিং কীভাবে কাজ করে তা দেখানোর জন্য তিনটি উল্লম্ব স্তর সহ গ্রাফিক। শীর্ষ স্তরটি একটি কালো বৃত্ত সহ একটি সাদা বর্গক্ষেত্র। মাঝের স্তরটি হ'ল সান আইকন। নীচের স্তরটি ফলাফল হিসাবে লেবেলযুক্ত এবং এটি একটি কাটআউট সহ সান আইকনটি দেখায় যেখানে শীর্ষ স্তরটি কালো বৃত্ত রয়েছে।

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

সিএসএস লোড না হলে কী হবে?

ভিতরে সান আইকন সহ একটি প্লেইন ব্রাউজার বোতামের স্ক্রিনশট।

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

লেআউট

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

শৈলী

.theme-toggle স্টাইল

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

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

.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 দ্রুত প্রতিক্রিয়াযুক্ত স্পর্শের অভিজ্ঞতার জন্য ম্যানিপুলেশন। আধা-স্বচ্ছ হাইলাইট আইওএস বোতামগুলিতে প্রযোজ্য সরান। সর্বশেষে, উপাদানটির প্রান্ত থেকে ফোকাস রাষ্ট্রের রূপরেখাটি কিছু শ্বাসকষ্ট দিন:

.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;
}

বোতামের ভিতরে এসভিজির পাশাপাশি কিছু স্টাইলের প্রয়োজন। এসভিজির বোতামের আকারটি ফিট করা উচিত এবং ভিজ্যুয়াল নরমতার জন্য, লাইনটি শেষ করে দেয়:

.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;
  }
}

সূর্য এবং চাঁদ এসভিজি স্টাইল

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

হালকা থিম

ALT_TEXT_HERE

এসভিজি আকারের কেন্দ্র থেকে স্কেল এবং ঘোরানো অ্যানিমেশনগুলির জন্য, তাদের 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: 1px) {
        transform: translateX(0);
        cx: 17px;
      }
    }
  }
}

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

অ্যানিমেশন

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

মিডিয়া অনুসন্ধানগুলি ভাগ করে নেওয়া এবং উপলভ্য আমদানি

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

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

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

অনন্য এবং সহজেই সিএসএস ইজিং ব্যবহার করার জন্য, ওপেন প্রপসগুলির ইজিং অংশটি আমদানি করুন:

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

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

সূর্য

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

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

​​.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;
      }
    }
  }
}

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

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

চাঁদ

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

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

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

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

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

হ্রাস গতি পছন্দ

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

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

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

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

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

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

এটি অর্জনের জন্য, কোনও সিএসএস বা <body> মার্কআপের আগে প্রথমে ডকুমেন্ট <head> এর একটি সাধারণ <script> ট্যাগ লোড করা হয়। যখন ব্রাউজারটি এ জাতীয় একটি অচিহ্নিত স্ক্রিপ্টের মুখোমুখি হয়, তখন এটি কোডটি চালায় এবং বাকি এইচটিএমএল এর আগে এটি কার্যকর করে। এই ব্লকিং মুহুর্তটি অল্প পরিমাণে ব্যবহার করে, প্রধান সিএসএস পৃষ্ঠাটি আঁকার আগে এইচটিএমএল বৈশিষ্ট্যটি সেট করা সম্ভব, এইভাবে কোনও ফ্ল্যাশ বা রঙ প্রতিরোধ করে।

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

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)
}

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

এরপরে, সেই ফাংশন reflectPreference() অবিলম্বে বলা হয় তাই এইচটিএমএল নথিতে এর 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()
  })
ম্যাকোস সিস্টেমের পছন্দ পরিবর্তন করা থিম স্যুইচ স্টেট পরিবর্তন করে

উপসংহার

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

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

সম্প্রদায় রিমিক্স