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

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

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

डेमो

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

खास जानकारी

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

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

लेआउट

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

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

सिर्फ़ गैप के लिए

सबसे सामान्य लेआउट:

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 अलाइनमेंट शॉर्टहैंड का इस्तेमाल किया गया है, ताकि बच्चों को एक और दो कॉलम वाले लेआउट, दोनों में वर्टिकल और हॉरिज़ॉन्टल तौर पर बीच में रखा जा सके.

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

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

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

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

अगर इसकी तुलना ऊना के लेआउट से की जाए, तो इसमें तीन खास बदलाव किए गए हैं:

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

Evan Minto ने अपने ब्लॉग पर 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);
    }
  }
}

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

एलसीएच?

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

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

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

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

Lea Verou

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

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

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

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

जब इस एलिमेंट के किसी चाइल्ड में फ़ोकस-विदिन होता है:

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

इनमें से ज़्यादातर स्टाइल, एक अच्छा सर्कल बनाने के लिए होती हैं. यहां आपको फिर से बैकग्राउंड का फ़िक्स्ड ग्रेडिएंट दिखता है. यह थंब, ट्रैक, और उनसे जुड़े SVG एलिमेंट के डाइनैमिक रंगों को एक जैसा बनाता है. मैंने इंटरैक्शन के लिए स्टाइल को अलग-अलग किया है, ताकि होवर हाइलाइट के लिए इस्तेमाल की जा रही 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 को धन्यवाद! इस वर्शन में, एलिमेंट demo और source के बीच कोई होवर गैप नहीं है.