थीम स्विच करने वाला कॉम्पोनेंट बनाना

अडैप्टिव और ऐक्सेस किए जा सकने वाले थीम स्विच कॉम्पोनेंट को बनाने के तरीके के बारे में बुनियादी जानकारी.

इस पोस्ट में, हम आपको गहरे और हल्के रंग वाली थीम पर स्विच करने वाला कॉम्पोनेंट बनाने के बारे में बताना चाहते हैं. डेमो आज़माएं.

डेमो बटन का साइज़ बढ़ाया गया, ताकि यह आसानी से दिखे

अगर आप वीडियो पसंद करते हैं, तो यहां इस पोस्ट का YouTube वर्शन दिया गया है:

खास जानकारी

कोई वेबसाइट पूरी तरह से सिस्टम की प्राथमिकता पर निर्भर रहने के बजाय, कलर स्कीम को कंट्रोल करने की सेटिंग उपलब्ध करा सकती है. इसका मतलब है कि उपयोगकर्ता, सिस्टम की प्राथमिकताओं की जगह किसी दूसरे मोड में ब्राउज़ कर सकते हैं. उदाहरण के लिए, किसी उपयोगकर्ता का सिस्टम हल्के रंग वाली थीम में होता है, लेकिन उपयोगकर्ता वेबसाइट को गहरे रंग वाली थीम में दिखाना पसंद करता है.

इस सुविधा को तैयार करते समय, वेब इंजीनियरिंग के बारे में कई बातें ध्यान में रखी जाती हैं. उदाहरण के लिए, ब्राउज़र को जल्द से जल्द प्राथमिकता के बारे में जानकारी देनी चाहिए, ताकि पेज का कलर फ़्लैश से बचा जा सके. साथ ही, कंट्रोल को पहले सिस्टम के साथ सिंक करना होगा फिर क्लाइंट-साइड स्टोर किए गए अपवादों को अनुमति देनी होगी.

डायग्राम में JavaScript पेज लोड और दस्तावेज़ के इंटरैक्शन इवेंट की झलक दिखती है. इसमें, यह दिखाया गया है कि थीम सेट करने के लिए चार पाथ होते हैं

मार्कअप

टॉगल के लिए <button> का इस्तेमाल किया जाना चाहिए. ऐसा करने पर, आपको ब्राउज़र से मिले इंटरैक्शन इवेंट और सुविधाओं, जैसे कि क्लिक इवेंट और फ़ोकस करने की सुविधा से फ़ायदा मिलेगा.

बटन

बटन को सीएसएस से इस्तेमाल करने के लिए एक क्लास और JavaScript से इस्तेमाल करने के लिए एक आईडी चाहिए. बटन का कॉन्टेंट, टेक्स्ट के बजाय आइकॉन होता है. इसलिए, बटन को इस्तेमाल करने के मकसद के बारे में जानकारी देने के लिए, title एट्रिब्यूट जोड़ें. आखिर में, आइकॉन बटन की स्थिति को रखने के लिए [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>

इस बार, fill की वैल्यू 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> के आकार में दिखाया जाएगा. यह SVG मास्क के साथ दिखेगा. इसके लिए, गोल आकार को मास्क वाले हिस्से के अंदर और बाहर लेकर जाना होगा.

सीएसएस लोड न होने पर क्या होता है?

ब्राउज़र के सादे बटन का स्क्रीनशॉट, जिसके अंदर सन आइकॉन है.

अपने SVG की जांच करना अच्छा हो सकता है, जैसे कि सीएसएस लोड ही न हुई हो, ताकि यह पक्का किया जा सके कि न तो बहुत बड़ा नतीजा आ रहा है और न ही लेआउट से जुड़ी समस्याएं आ रही हैं. SVG पर इनलाइन ऊंचाई और चौड़ाई वाले एट्रिब्यूट और currentColor का इस्तेमाल करने से, ब्राउज़र पर स्टाइल के कम से कम नियम तय होते हैं. इनकी मदद से, सीएसएस के लोड न होने पर भी ब्राउज़र का इस्तेमाल किया जा सकता है. इससे नेटवर्क में रुकावट के ख़िलाफ़ रक्षा के अच्छे तरीके अपनाए जाते हैं.

लेआउट

थीम स्विच करने वाले कॉम्पोनेंट का सरफ़ेस एरिया बहुत कम होता है. इसलिए, आपको लेआउट के लिए ग्रिड या फ़्लेक्सबॉक्स की ज़रूरत नहीं होती. इसके बजाय, SVG पोज़िशनिंग और सीएसएस ट्रांसफ़ॉर्म का इस्तेमाल किया जाता है.

स्टाइल

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

ध्यान दें कि गहरे रंग वाली थीम में कोई रंग या ट्रांज़िशन नहीं है. पैरंट बटन कॉम्पोनेंट, रंगों का मालिक होता है, जहां वे गहरे और हल्के रंग में पहले से ही अनुकूल होते हैं. ट्रांज़िशन की जानकारी उपयोगकर्ता की मोशन प्राथमिकता मीडिया क्वेरी के पीछे होनी चाहिए.

Animation

बटन, फ़ंक्शनल और स्टेटफ़ुल होना चाहिए, लेकिन इस पर ट्रांज़िशन नहीं होना चाहिए. नीचे दिए गए सेक्शन में यह बताया गया है कि ट्रांज़िशन कैसे और क्या होने चाहिए.

मीडिया क्वेरी शेयर करना और ईज़िंग इंपोर्ट करना

उपयोगकर्ता के ऑपरेटिंग सिस्टम मोशन से जुड़ी प्राथमिकताओं के पीछे ट्रांज़िशन और ऐनिमेशन का इस्तेमाल आसानी से करने के लिए, PostCSS प्लगिन कस्टम मीडिया, मीडिया क्वेरी वैरिएबल सिंटैक्स के लिए ड्राफ़्ट किए गए सीएसएस स्पेसिफ़िकेशन का इस्तेमाल करने की सुविधा देता है:

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

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

यूनीक और इस्तेमाल में आसान सीएसएस ईज़िंग के लिए, 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

इस कॉम्पोनेंट में JavaScript पर बहुत काम करना होता है. जैसे, स्क्रीन रीडर के लिए ARIA की जानकारी मैनेज करना और लोकल स्टोरेज से वैल्यू पाना और सेट करना.

पेज लोड होने का अनुभव

यह ज़रूरी था कि पेज लोड होने पर कलर फ़्लैश न हो. अगर किसी उपयोगकर्ता ने गहरे रंग की स्कीम इस्तेमाल की है, तो यह बताता है कि उसे इस कॉम्पोनेंट से रोशनी पसंद है. इसके बाद, पेज को फिर से लोड किया जाता है. सबसे पहले, पेज गहरे रंग का होगा और फिर लाइट पर फ़्लैश होगा. इसे रोकने का मतलब है कि एचटीएमएल एट्रिब्यूट data-theme को जल्द से जल्द सेट करने के लक्ष्य के साथ JavaScript को कुछ हद तक ब्लॉक करना.

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

इसके लिए, <head> दस्तावेज़ में मौजूद सादा <script> टैग, किसी भी सीएसएस या <body> मार्कअप से पहले लोड होता है. जब ब्राउज़र को इस तरह की, बिना निशान वाली स्क्रिप्ट मिलती है, तो वह कोड चलाता है और उसे बाकी एचटीएमएल से पहले लागू करता है. ब्लॉक करने के इस पल का कम से कम इस्तेमाल करके, मुख्य सीएसएस के पेज को पेंट करने से पहले, एचटीएमएल एट्रिब्यूट को सेट किया जा सकता है. इससे फ़्लैश या कलर दिखने से बचा जा सकता है.

JavaScript, सबसे पहले लोकल स्टोरेज में उपयोगकर्ता की सेटिंग की जांच करता है. स्टोरेज में कुछ भी न मिलने पर, सिस्टम की प्राथमिकता की जांच करने के लिए फ़ॉलबैक करता है:

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

यहां पर ध्यान देने वाली एक ज़रूरी बात है एचटीएमएल दस्तावेज़ को पार्स करने की स्थिति. ब्राउज़र को अभी तक "#theme-toggle" बटन के बारे में नहीं पता है, क्योंकि <head> टैग पूरी तरह से पार्स नहीं हुआ है. हालांकि, ब्राउज़र में एक document.firstElementChild होता है, जिसे <html> टैग कहते हैं. फ़ंक्शन दोनों को सिंक में रखने के लिए सेट करने की कोशिश करता है, लेकिन पहली बार चलाने पर सिर्फ़ एचटीएमएल टैग सेट किया जा सकेगा. querySelector को सबसे पहले कुछ नहीं दिखेगा और वैकल्पिक चेनिंग ऑपरेटर यह पक्का करेगा कि सिंटैक्स से जुड़ी गड़बड़ी न मिलने पर, कोई सिंटैक्स गड़बड़ी न हो. साथ ही, setAttribute फ़ंक्शन को शुरू करने की कोशिश की जाती है.

इसके बाद, उस फ़ंक्शन 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)
}

टॉगल करने का अनुभव

जब बटन पर क्लिक किया जाता है, तो JavaScript मेमोरी और दस्तावेज़ में थीम को बदलना पड़ता है. मौजूदा थीम वैल्यू की जांच करनी होगी और उसकी नई स्थिति के बारे में फ़ैसला लेना होगा. नई स्थिति सेट हो जाने के बाद, इसे सेव करें और दस्तावेज़ अपडेट करें:

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

  setPreference()
}

सिस्टम के साथ सिंक करना

इस थीम स्विच का इस्तेमाल, सिस्टम की प्राथमिकता के साथ सिंक करने के लिए किया जाता है. कोई पेज और यह कॉम्पोनेंट दिखने के दौरान, अगर कोई उपयोगकर्ता अपने सिस्टम की प्राथमिकता बदलता है, तो नई उपयोगकर्ता प्राथमिकता के हिसाब से थीम स्विच हो जाएगा. जैसे, उपयोगकर्ता ने सिस्टम स्विच करते समय ही थीम स्विच से इंटरैक्ट किया हो.

JavaScript और मीडिया क्वेरी में बदलावों को सुनने के लिए matchMedia इवेंट की मदद से इसे हासिल करें:

window
  .matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', ({matches:isDark}) => {
    theme.value = isDark ? 'dark' : 'light'
    setPreference()
  })
MacOS के सिस्टम की प्राथमिकता बदलने से थीम स्विच की स्थिति बदल जाती है

नतीजा

अब आपको पता चल गया है कि मैंने इसे कैसे किया, तो आप कैसी होंगी‽ 🙂

चलिए, इसे अलग-अलग तरीके से समझें और वेब पर सभी के काम करने के तरीके सीखें. एक डेमो तैयार करें, मुझे ट्वीट करें वाले लिंक, और मैं उसे नीचे दिए गए कम्यूनिटी रीमिक्स सेक्शन में जोड़ दूंगी!

कम्यूनिटी रीमिक्स