सेटिंग कॉम्पोनेंट बनाना

स्लाइडर और चेकबॉक्स के सेटिंग कॉम्पोनेंट बनाने के तरीके के बारे में बुनियादी जानकारी.

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

डेमो

अगर आपको वीडियो देखना पसंद है या आपको हमारे बनाए जा रहे यूज़र इंटरफ़ेस (यूआई)/उपयोगकर्ता अनुभव (यूएक्स) की झलक देखनी है, तो YouTube पर यह छोटा सा वॉकथ्रू देखें:

खास जानकारी

मैंने इस कॉम्पोनेंट के पहलुओं को इन सेक्शन में बांटा है:

  1. लेआउट
  2. रंग
  3. कस्टम रेंज का इनपुट
  4. कस्टम चेकबॉक्स इनपुट
  5. सुलभता से जुड़ी ज़रूरी बातें
  6. JavaScript

लेआउट

यह पहला ऐसा जीयूआई चैलेंज डेमो है जो पूरी तरह से सीएसएस ग्रिड पर आधारित है! यहां हर ग्रिड को ग्रिड के लिए Chrome DevTools की मदद से हाइलाइट किया गया है:

रंगीन आउटलाइन और गैप स्पेसिंग ओवरले, जो सेटिंग लेआउट बनाने वाले सभी बॉक्स दिखाते हैं

Just for gap

सबसे आम लेआउट:

foo {
  display: grid;
  gap: var(--something);
}

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

इस रणनीति का इस्तेमाल पांच लेआउट करते हैं. यहां उन सभी को दिखाया गया है:

वर्टिकल ग्रिड लेआउट, जिन्हें आउटलाइन से हाइलाइट किया गया है और खाली जगहों को भरा गया है

fieldset एलिमेंट में हर इनपुट ग्रुप (.fieldset-item) शामिल होता है. यह एलिमेंट, gap: 1px का इस्तेमाल करके एलिमेंट के बीच हेयरलाइन बॉर्डर बनाता है. बॉर्डर से जुड़ी कोई समस्या नहीं!

कॉन्टेंट गैप को भरना
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
बॉर्डर ट्रिक
.grid {
  display: grid;

  & > .fieldset-item {
    background: var(--bg-surface-2);

    &:not(:last-child) {
      border-bottom: 1px solid var(--bg-surface-1);
    }
  }
}

नैचुरल ग्रिड रैपिंग

सबसे मुश्किल लेआउट, मैक्रो लेआउट था. यह <main> और <form> के बीच का लॉजिकल लेआउट सिस्टम था.

रैपिंग कॉन्टेंट को बीच में अलाइन करना

फ़्लेक्सबॉक्स और ग्रिड, दोनों में align-items या align-content करने की सुविधाएं मिलती हैं. साथ ही, रैपिंग एलिमेंट के साथ काम करते समय, content लेआउट अलाइनमेंट, चाइल्ड एलिमेंट के बीच स्पेस को एक ग्रुप के तौर पर बांटेंगे.

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
}

मुख्य एलिमेंट में place-content: center अलाइनमेंट शॉर्टहैंड का इस्तेमाल किया जा रहा है, ताकि चाइल्ड एलिमेंट एक और दो कॉलम वाले लेआउट में, वर्टिकल और हॉरिज़ॉन्टल तौर पर बीच में हों.

ऊपर दिए गए वीडियो में देखें कि रैपिंग होने के बावजूद, "कॉन्टेंट" बीच में कैसे रहता है.

Repeat auto-fit minmax

<form>, हर सेक्शन के लिए अडैप्टिव ग्रिड लेआउट का इस्तेमाल करता है. यह लेआउट, उपलब्ध जगह के हिसाब से एक से दो कॉलम में स्विच हो जाता है.

form {
  display: grid;
  gap: var(--space-xl) var(--space-xxl);
  grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
  align-items: flex-start;
  max-width: 89vw;
}

इस ग्रिड में row-gap (--space-xl) के लिए, column-gap (--space-xxl) से अलग वैल्यू है. इससे रिस्पॉन्सिव लेआउट को कस्टम टच दिया जा सकता है. जब कॉलम स्टैक होते हैं, तो हमें ज़्यादा गैप चाहिए होता है. हालांकि, यह गैप उतना ज़्यादा नहीं होना चाहिए जितना कि बड़ी स्क्रीन पर होता है.

grid-template-columns प्रॉपर्टी में तीन सीएसएस फ़ंक्शन इस्तेमाल किए जाते हैं: repeat(), minmax(), और min(). Una Kravets ने इस बारे में एक शानदार लेआउट ब्लॉग पोस्ट लिखी है. इसमें उन्होंने इसे RAM कहा है.

अगर ऊना के लेआउट से तुलना करें, तो हमारे लेआउट में तीन खास चीज़ें जोड़ी गई हैं:

  • हम एक अतिरिक्त min() फ़ंक्शन पास करते हैं.
  • हम align-items: flex-start की जानकारी देते हैं.
  • max-width: 89vw स्टाइल में वीडियो जनरेट करने की सुविधा उपलब्ध है.

इवान मिंटो ने अपने ब्लॉग पर, min() फ़ंक्शन के बारे में अच्छे से बताया है. उनकी पोस्ट Intrinsically Responsive CSS Grid with minmax() and min() पढ़ें. हमारा सुझाव है कि आप इसे ज़रूर पढ़ें. flex-start अलाइनमेंट में सुधार करने का मकसद, डिफ़ॉल्ट स्ट्रेचिंग इफ़ेक्ट को हटाना है. इससे इस लेआउट के चाइल्ड एलिमेंट की ऊंचाई बराबर होना ज़रूरी नहीं है. उनकी ऊंचाई नैचुरल और इंट्रिन्सिक हो सकती है. YouTube वीडियो में, अलाइनमेंट की इस नई सुविधा के बारे में खास जानकारी दी गई है.

max-width: 89vw के बारे में इस पोस्ट में थोड़ी जानकारी दी गई है. आइए, आपको स्टाइल लागू करने के साथ और उसके बिना लेआउट दिखाते हैं:

क्या बदलाव हो रहे हैं? max-width की वैल्यू देने पर, यह auto-fitलेआउट एल्गोरिदम को कॉन्टेक्स्ट, साफ़ तौर पर साइज़ या तय साइज़ की जानकारी देता है. इससे एल्गोरिदम को यह पता चलता है कि स्पेस में कितनी बार दोहराव किया जा सकता है. सीएसएस ग्रिड की खास जानकारी के मुताबिक, भले ही यह साफ़ तौर पर दिखता हो कि स्पेस "पूरी चौड़ाई" का है, लेकिन इसके लिए तय साइज़ या ज़्यादा से ज़्यादा साइज़ देना ज़रूरी है. मैंने इमेज का ज़्यादा से ज़्यादा साइज़ सेट किया है.

तो, 89vw ही क्यों? क्योंकि यह मेरे लेआउट के लिए "काम कर गया". मैं और Chrome के कुछ अन्य लोग इस बात की जांच कर रहे हैं कि 100vw जैसी ज़्यादा सही वैल्यू काफ़ी क्यों नहीं है. साथ ही, क्या यह वाकई कोई गड़बड़ी है.

स्पेसिंग

इस लेआउट में ज़्यादातर हार्मनी, स्पेसिंग के सीमित पैलेट से आती है. इसमें सात स्पेसिंग होती हैं.

:root {
  --space-xxs: .25rem;
  --space-xs:  .5rem;
  --space-sm:  1rem;
  --space-md:  1.5rem;
  --space-lg:  2rem;
  --space-xl:  3rem;
  --space-xxl: 6rem;
}

इनका इस्तेमाल ग्रिड, CSS @nest, और @media के लेवल 5 सिंटैक्स के साथ बहुत अच्छे से किया जा सकता है. यहां एक उदाहरण दिया गया है, जिसमें <main> लेआउट के लिए स्टाइल का पूरा सेट है.

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
  padding: var(--space-sm);

  @media (width >= 540px) {
    & {
      padding: var(--space-lg);
    }
  }

  @media (width >= 800px) {
    & {
      padding: var(--space-xl);
    }
  }
}

सेंटर में कॉन्टेंट वाली ग्रिड, जिसमें डिफ़ॉल्ट रूप से सामान्य पैडिंग होती है (जैसे कि मोबाइल पर). हालांकि, व्यूपोर्ट में ज़्यादा जगह उपलब्ध होने पर, यह पैडिंग बढ़ाकर फैल जाता है. साल 2021 में सीएसएस काफ़ी अच्छा लग रहा है!

क्या आपको पहले वाला लेआउट याद है, "सिर्फ़ गैप के लिए"? इस कॉम्पोनेंट में वे कैसे दिखते हैं, इसका ज़्यादा जानकारी वाला वर्शन यहां दिया गया है:

header {
  display: grid;
  gap: var(--space-xxs);
}

section {
  display: grid;
  gap: var(--space-md);
}

रंग

रंगों के सही इस्तेमाल से, यह डिज़ाइन आकर्षक और सिंपल दिखता है. मैं इसे इस तरह करता हूं:

:root {
  --surface1: lch(10 0 0);
  --surface2: lch(15 0 0);
  --surface3: lch(20 0 0);
  --surface4: lch(25 0 0);

  --text1: lch(95 0 0);
  --text2: lch(75 0 0);
}

मैं अपने सरफ़ेस और टेक्स्ट के रंगों को surface-dark और surface-darker जैसे नामों के बजाय नंबरों से नाम देता हूं. ऐसा इसलिए, क्योंकि मीडिया क्वेरी में, मैं उन्हें फ़्लिप कर रहा होऊंगा और लाइट और डार्क का कोई मतलब नहीं होगा.

मैं उन्हें इस तरह की मीडिया क्वेरी में फ़्लिप करता हूं:

:root {
  ...

  @media (prefers-color-scheme: light) {
    & {
      --surface1: lch(90 0 0);
      --surface2: lch(100 0 0);
      --surface3: lch(98 0 0);
      --surface4: lch(85 0 0);

      --text1: lch(20 0 0);
      --text2: lch(40 0 0);
    }
  }
}

कलर सिंटैक्स की जानकारी में जाने से पहले, पूरी तस्वीर और रणनीति पर एक नज़र डालना ज़रूरी है. हालांकि, मैंने आपको कुछ ज़्यादा ही जानकारी दे दी है. इसलिए, अब मैं आपको थोड़ा पीछे ले चलता हूं.

LCH?

कलर थ्योरी के बारे में ज़्यादा गहराई से जाने बिना, एलसीएच एक ऐसा सिंटैक्स है जो इंसानों के हिसाब से काम करता है. यह इस बात पर ध्यान देता है कि हम रंग को कैसे देखते हैं, न कि इस बात पर कि हम गणित (जैसे, 255) की मदद से रंग को कैसे मापते हैं. इससे इसे एक अलग फ़ायदा मिलता है, क्योंकि इंसान इसे ज़्यादा आसानी से लिख सकते हैं और अन्य लोग इन बदलावों के साथ तालमेल बिठा पाएंगे.

pod.link/csspodcast वेबपेज का स्क्रीनशॉट, जिसमें Color 2: Perception एपिसोड दिखाया गया है
CSS पॉडकास्ट पर, परसेप्टुअल कलर और अन्य चीज़ों के बारे में जानें

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

:root {
  --surface1: lch(10 0 0);
  --text1:    lch(95 0 0);

  @media (prefers-color-scheme: light) {
    & {
      --surface1: lch(90 0 0);
      --text1:    lch(40 0 0);
    }
  }
}

--surface1: lch(10 0 0) का मतलब है 10% लाइटनेस, 0 क्रोमा, और 0 ह्यू: बहुत गहरा रंगहीन ग्रे. इसके बाद, हल्के रंग वाले मोड के लिए मीडिया क्वेरी में, रोशनी को --surface1: lch(90 0 0); के साथ 90% पर फ़्लिप किया जाता है. इस रणनीति का यही मकसद है. दोनों थीम के बीच सिर्फ़ रोशनी को बदलकर शुरुआत करें. साथ ही, डिज़ाइन के लिए ज़रूरी कंट्रास्ट रेशियो को बनाए रखें या सुलभता को बनाए रखें.

lch() के साथ बोनस यह है कि लाइटनेस, इंसानों के हिसाब से तय होती है. साथ ही, हम इसमें % बदलाव को महसूस कर सकते हैं. यह बदलाव, लगातार और साफ़ तौर पर % अलग होगा. उदाहरण के लिए, hsl() भरोसेमंद नहीं है.

अगर आपको कलर स्पेस और lch() के बारे में ज़्यादा जानना है, तो यहां और भी जानकारी दी गई है. यह सुविधा जल्द ही उपलब्ध होगी!

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

लिया वेरू

कलर-स्कीम के साथ अडैप्टिव फ़ॉर्म कंट्रोल

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

ऊपर, DevTools के स्टाइल पैनल से प्रॉपर्टी के असर को दिखाया गया है. डेमो में एचटीएमएल टैग का इस्तेमाल किया गया है. मेरी राय में, यह आम तौर पर एक बेहतर जगह है:

<meta name="color-scheme" content="dark light">

इस बारे में ज़्यादा जानने के लिए, थॉमस स्टाइनर का यह color-scheme लेख पढ़ें. डार्क चेकबॉक्स इनपुट के अलावा, और भी बहुत कुछ हासिल किया जा सकता है!

सीएसएस accent-color

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

input[type="checkbox"] {
  accent-color: var(--brand);
}

Linux पर Chromium का स्क्रीनशॉट, जिसमें गुलाबी रंग के चेकबॉक्स दिख रहे हैं

फ़िक्स्ड ग्रेडिएंट और फ़ोकस-विदिन के साथ कलर पॉप

रंगों का इस्तेमाल कम से कम करने पर, वे ज़्यादा उभरकर सामने आते हैं. इसके लिए, मुझे कलरफ़ुल यूज़र इंटरफ़ेस (यूआई) इंटरैक्शन का इस्तेमाल करना पसंद है.

ऊपर दिए गए वीडियो में, यूज़र इंटरफ़ेस के फ़ीडबैक और इंटरैक्शन की कई लेयर हैं. इनसे इंटरैक्शन को बेहतर बनाने में मदद मिलती है:

  • कॉन्टेक्स्ट को हाइलाइट करना.
  • यूज़र इंटरफ़ेस (यूआई) में यह जानकारी देना कि वैल्यू, रेंज में "कितनी भरी" है.
  • यूज़र इंटरफ़ेस (यूआई) से जुड़ा सुझाव, शिकायत या राय देना कि कोई फ़ील्ड इनपुट स्वीकार कर रहा है.

किसी एलिमेंट के साथ इंटरैक्ट करते समय सुझाव देने के लिए, सीएसएस :focus-within स्यूडो क्लास का इस्तेमाल करती है. इससे अलग-अलग एलिमेंट के दिखने का तरीका बदल जाता है. आइए, .fieldset-item को ब्रेकडाउन करें. यह बहुत दिलचस्प है:

.fieldset-item {
  ...

  &:focus-within {
    background: var(--surface2);

    & svg {
      fill: white;
    }

    & picture {
      clip-path: circle(50%);
      background: var(--brand-bg-gradient) fixed;
    }
  }
}

जब इस एलिमेंट के किसी चाइल्ड एलिमेंट में focus-within हो:

  1. .fieldset-item बैकग्राउंड को ज़्यादा कंट्रास्ट वाला रंग असाइन किया गया है.
  2. नेस्ट किए गए svg को सफ़ेद रंग से भरा गया है, ताकि कंट्रास्ट ज़्यादा हो.
  3. नेस्ट किया गया <picture> clip-path, पूरे सर्कल में फैल जाता है और बैकग्राउंड, चमकीले ग्रेडिएंट से भर जाता है.

पसंद के मुताबिक बनाई गई सीमा

यहां दिए गए एचटीएमएल इनपुट एलिमेंट के आधार पर, मैं आपको दिखाऊंगा कि मैंने इसके लुक को कैसे पसंद के मुताबिक बनाया:

<input type="range">

इस एलिमेंट के तीन हिस्से हैं, जिन्हें हमें पसंद के मुताबिक बनाना होगा:

  1. रेंज एलिमेंट / कंटेनर
  2. ट्रैक करना
  3. Thumb

रेंज एलिमेंट की स्टाइल

input[type="range"] {
  /* style setting variables */
  --track-height: .5ex;
  --track-fill: 0%;
  --thumb-size: 3ex;
  --thumb-offset: -1.25ex;
  --thumb-highlight-size: 0px;

  appearance: none;         /* clear styles, make way for mine */
  display: block;
  inline-size: 100%;        /* fill container */
  margin: 1ex 0;            /* ensure thumb isn't colliding with sibling content */
  background: transparent;  /* bg is in the track */
  outline-offset: 5px;      /* focus styles have space */
}

सीएसएस की शुरुआती कुछ लाइनें, स्टाइल के कस्टम हिस्से हैं. हमें उम्मीद है कि इन्हें साफ़ तौर पर लेबल करने से मदद मिलेगी. बाकी स्टाइल, ज़्यादातर रीसेट स्टाइल होती हैं. इनसे कॉम्पोनेंट के मुश्किल हिस्सों को बनाने के लिए, एक जैसा फ़ाउंडेशन मिलता है.

ट्रैक स्टाइल

input[type="range"]::-webkit-slider-runnable-track {
  appearance: none; /* clear styles, make way for mine */
  block-size: var(--track-height);
  border-radius: 5ex;
  background:
    /* hard stop gradient:
        - half transparent (where colorful fill we be)
        - half dark track fill
        - 1st background image is on top
    */
    linear-gradient(
      to right,
      transparent var(--track-fill),
      var(--surface1) 0%
    ),
    /* colorful fill effect, behind track surface fill */
    var(--brand-bg-gradient) fixed;
}

इसके लिए, आपको चटक रंग "दिखाना" होगा. इसके लिए, सबसे ऊपर हार्ड स्टॉप ग्रेडिएंट का इस्तेमाल किया जाता है. ग्रेडिएंट, फ़िल पर्सेंटेज तक पारदर्शी होता है. इसके बाद, यह ट्रैक के खाली हिस्से के रंग का इस्तेमाल करता है. इस खाली जगह के पीछे, एक रंग है जो पूरी चौड़ाई में फैला है. यह रंग, पारदर्शिता की वजह से दिखता है.

ट्रैक का फ़िल स्टाइल

फ़िल स्टाइल को बनाए रखने के लिए, मेरे डिज़ाइन में JavaScript की ज़रूरत है. सिर्फ़ सीएसएस वाली रणनीतियां भी हैं, लेकिन उनके लिए थंब एलिमेंट की ऊंचाई, ट्रैक के बराबर होनी चाहिए. मुझे इन सीमाओं के अंदर कोई तालमेल नहीं मिला.

/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')

/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
  const max = slider.getAttribute('max') || 10;
  const percent = slider.value / max * 100;

  return `${parseInt(percent)}%`;
};

/* on page load, set the fill amount */
sliders.forEach(slider => {
  slider.style.setProperty('--track-fill', rangeToPercent(slider));

  /* when a slider changes, update the fill prop */
  slider.addEventListener('input', e => {
    e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
  })
})

मुझे लगता है कि इससे विज़ुअल काफ़ी बेहतर हो गया है. स्लाइडर, JavaScript के बिना भी अच्छी तरह से काम करता है. --track-fill प्रॉपर्टी की ज़रूरत नहीं है. अगर यह मौजूद नहीं है, तो इसमें फ़िल स्टाइल नहीं होगी. अगर JavaScript उपलब्ध है, तो कस्टम प्रॉपर्टी को पॉप्युलेट करें. साथ ही, उपयोगकर्ता के किए गए किसी भी बदलाव पर नज़र रखें और कस्टम प्रॉपर्टी को वैल्यू के साथ सिंक करें.

ऐना ट्यूडर ने CSS-Tricks पर एक शानदार पोस्ट लिखी है. इसमें उन्होंने ट्रैक फ़िल के लिए, सिर्फ़ सीएसएस का इस्तेमाल करके समाधान बताया है. मुझे range एलिमेंट भी काफ़ी पसंद आया.

थंब स्टाइल

input[type="range"]::-webkit-slider-thumb {
  appearance: none; /* clear styles, make way for mine */
  cursor: ew-resize; /* cursor style to support drag direction */
  border: 3px solid var(--surface3);
  block-size: var(--thumb-size);
  inline-size: var(--thumb-size);
  margin-top: var(--thumb-offset);
  border-radius: 50%;
  background: var(--brand-bg-gradient) fixed;
}

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

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

::-webkit-slider-thumb {
  …

  /* shadow spread is initally 0 */
  box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);

  /* if motion is OK, transition the box-shadow change */
  @media (--motionOK) {
    & {
      transition: box-shadow .1s ease;
    }
  }

  /* on hover/active state of parent, increase size prop */
  @nest input[type="range"]:is(:hover,:active) & {
    --thumb-highlight-size: 10px;
  }
}

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

काश, चेकबॉक्स पर हाइलाइट इफ़ेक्ट लगाना इतना आसान होता…

क्रॉस ब्राउज़र सिलेक्टर

मुझे पता चला कि सभी ब्राउज़र पर एक जैसा लुक पाने के लिए, मुझे इन -webkit- और -moz- सिलेक्टर की ज़रूरत है:

input[type="range"] {
  &::-webkit-slider-runnable-track {}
  &::-moz-range-track {}
  &::-webkit-slider-thumb {}
  &::-moz-range-thumb {}
}

कस्टम चेकबॉक्स

यहां दिए गए एचटीएमएल इनपुट एलिमेंट के आधार पर, मैं आपको दिखाऊंगा कि मैंने इसके लुक को कैसे पसंद के मुताबिक बनाया:

<input type="checkbox">

इस एलिमेंट के तीन हिस्से हैं, जिन्हें हमें पसंद के मुताबिक बनाना होगा:

  1. चेकबॉक्स एलिमेंट
  2. इससे जुड़े लेबल
  3. हाइलाइट इफ़ेक्ट

चेकबॉक्स एलिमेंट

input[type="checkbox"] {
  inline-size: var(--space-sm);   /* increase width */
  block-size: var(--space-sm);    /* increase height */
  outline-offset: 5px;            /* focus style enhancement */
  accent-color: var(--brand);     /* tint the input */
  position: relative;             /* prepare for an absolute pseudo element */
  transform-style: preserve-3d;   /* create a 3d z-space stacking context */
  margin: 0;
  cursor: pointer;
}

transform-style और position स्टाइल, उस सूडो-एलिमेंट के लिए तैयार होते हैं जिसे हम बाद में हाइलाइट को स्टाइल करने के लिए पेश करेंगे. इसके अलावा, ज़्यादातर मामलों में यह मेरी निजी राय होती है. मुझे कर्सर को पॉइंटर के तौर पर रखना पसंद है. मुझे आउटलाइन ऑफ़सेट पसंद हैं. डिफ़ॉल्ट चेकबॉक्स बहुत छोटे हैं. अगर accent-color इस्तेमाल किया जा सकता है, तो इन चेकबॉक्स को ब्रैंड की कलर स्कीम में शामिल करें.

चेकबॉक्स लेबल

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

इनपुट
<input
  type="checkbox"
  id="text-notifications"
  name="text-notifications"
>
लेबल
<label for="text-notifications">
  <h3>Text Messages</h3>
  <small>Get notified about all text messages sent to your device</small>
</label>

अपने लेबल पर, एक for एट्रिब्यूट डालें, जो आईडी के हिसाब से चेकबॉक्स पर ले जाए: <label for="text-notifications">. अपने चेकबॉक्स पर, नाम और आईडी दोनों को दोगुना करें, ताकि यह पक्का किया जा सके कि यह अलग-अलग टूल और टेक्नोलॉजी, जैसे कि माउस या स्क्रीनरीडर से मिल जाए: <input type="checkbox" id="text-notifications" name="text-notifications">. :hover, :active, और अन्य टूल, कनेक्शन के साथ मुफ़्त में मिलते हैं. इससे आपके फ़ॉर्म के साथ इंटरैक्ट करने के तरीके बढ़ जाते हैं.

चेकबॉक्स हाइलाइट करने की सुविधा

मुझे अपने इंटरफ़ेस एक जैसे रखने हैं. साथ ही, स्लाइडर एलिमेंट में थंबनेल की एक अच्छी हाइलाइट है, जिसका इस्तेमाल मुझे चेकबॉक्स के साथ करना है. थंबनेल में box-shadow और इसकी spread प्रॉपर्टी का इस्तेमाल करके, शैडो को छोटा और बड़ा किया जा सकता था. हालांकि, यह इफ़ेक्ट यहां काम नहीं करता, क्योंकि हमारे चेकबॉक्स स्क्वेयर शेप में हैं और होने भी चाहिए.

मैंने स्यूडो एलिमेंट और सीएसएस की मदद से, विज़ुअल इफ़ेक्ट को हासिल किया:

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

input[type="checkbox"]::before {
  --thumb-scale: .01;                        /* initial scale of highlight */
  --thumb-highlight-size: var(--space-xl);

  content: "";
  inline-size: var(--thumb-highlight-size);
  block-size: var(--thumb-highlight-size);
  clip-path: circle(50%);                     /* circle shape */
  position: absolute;                         /* this is why position relative on parent */
  top: 50%;                                   /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
  left: 50%;
  background: var(--thumb-highlight-color);
  transform-origin: center center;            /* goal is a centered scaling circle */
  transform:                                  /* order here matters!! */
    translateX(-50%)                          /* counter balances left: 50% */
    translateY(-50%)                          /* counter balances top: 50% */
    translateZ(-1px)                          /* PUTS IT BEHIND THE CHECKBOX */
    scale(var(--thumb-scale))                 /* value we toggle for animation */
  ;
  will-change: transform;

  @media (--motionOK) {                       /* transition only if motion is OK */
    & {
      transition: transform .2s ease;
    }
  }
}

/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
  --thumb-scale: 1;
}

सर्कल स्यूडो-एलिमेंट बनाना आसान है, लेकिन इसे उस एलिमेंट के पीछे रखना मुश्किल था जिससे यह जुड़ा हुआ है. यहां देखें कि समस्या ठीक करने से पहले और बाद में, यह कैसा दिखता है:

यह एक छोटा इंटरैक्शन है, लेकिन विज़ुअल को एक जैसा बनाए रखने के लिए मेरे लिए ज़रूरी है. ऐनिमेशन को स्केल करने की तकनीक वही है जिसका इस्तेमाल हम अन्य जगहों पर करते रहे हैं. हम कस्टम प्रॉपर्टी को नई वैल्यू पर सेट करते हैं और सीएसएस को मोशन की प्राथमिकताओं के आधार पर ट्रांज़िशन करने देते हैं. इसकी मुख्य सुविधा translateZ(-1px) है. पैरंट ने एक 3D स्पेस बनाया और इस सूडो-एलिमेंट चाइल्ड ने z-स्पेस में खुद को थोड़ा पीछे रखकर, इसमें टैप किया.

सुलभता

इस YouTube वीडियो में, सेटिंग के इस कॉम्पोनेंट के लिए माउस, कीबोर्ड, और स्क्रीन रीडर के इंटरैक्शन के बारे में अच्छी तरह से बताया गया है. मैं यहां कुछ जानकारी बताऊंगा.

एचटीएमएल एलिमेंट के विकल्प

<form>
<header>
<fieldset>
<picture>
<label>
<input>

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

एचटीएमएल एट्रिब्यूट

हम उन एलिमेंट को छिपा सकते हैं जिनकी ज़रूरत स्क्रीन रीडर को नहीं होती. इस मामले में, स्लाइडर के बगल में मौजूद आइकॉन:

<picture aria-hidden="true">

ऊपर दिए गए वीडियो में, Mac OS पर स्क्रीनरीडर के फ़्लो को दिखाया गया है. ध्यान दें कि इनपुट फ़ोकस, एक स्लाइडर से सीधे अगले स्लाइडर पर कैसे जाता है. ऐसा इसलिए है, क्योंकि हमने उस आइकॉन को छिपा दिया है जो शायद अगले स्लाइडर पर जाने के रास्ते में रुकावट बन रहा था. इस एट्रिब्यूट के बिना, उपयोगकर्ता को रुकना होगा, सुनना होगा, और उस इमेज को पार करना होगा जो शायद उसे न दिखे.

एसवीजी, गणित के कई फ़ॉर्मूले का इस्तेमाल करके बनाया जाता है. चलिए, इसमें <title> एलिमेंट जोड़ते हैं, ताकि माउस को होवर करने पर टाइटल दिखे. साथ ही, गणित के फ़ॉर्मूले से क्या बनाया जा रहा है, इसके बारे में आसानी से पढ़ा जा सकने वाला कॉमेंट जोड़ते हैं:

<svg viewBox="0 0 24 24">
  <title>A note icon</title>
  <path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>

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

JavaScript

मैंने पहले ही बता दिया है कि ट्रैक में रंग भरने की सुविधा को JavaScript से कैसे मैनेज किया जा रहा था. इसलिए, अब <form> से जुड़े JavaScript को देखते हैं:

const form = document.querySelector('form');

form.addEventListener('input', event => {
  const formData = Object.fromEntries(new FormData(form));
  console.table(formData);
})

जब भी फ़ॉर्म में कोई बदलाव किया जाता है, तो कंसोल उसे एक ऑब्जेक्ट के तौर पर टेबल में लॉग करता है. इससे सर्वर पर सबमिट करने से पहले, फ़ॉर्म की समीक्षा करना आसान हो जाता है.

console.table() के नतीजों का स्क्रीनशॉट, जिसमें फ़ॉर्म का डेटा एक टेबल में दिखाया गया है

नतीजा

अब जब आपको पता चल गया है कि मैंने यह कैसे किया, तो आप इसे कैसे करेंगे?! इससे कॉम्पोनेंट आर्किटेक्चर काफ़ी मज़ेदार हो जाता है! अपने पसंदीदा फ़्रेमवर्क में स्लॉट के साथ पहला वर्शन कौन बनाएगा? 🙂

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

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

  • @tomayac ने चेकबॉक्स के लेबल के लिए, कर्सर घुमाने पर दिखने वाले एरिया के बारे में अपनी स्टाइल शेयर की है! इस वर्शन में, एलिमेंट के बीच होवर गैप नहीं है: डेमो और सोर्स.