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

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

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

डेमो

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

खास जानकारी

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

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

लेआउट

यह all CSS Grid होने वाला पहला जीयूआई चैलेंज डेमो है! यहां ग्रिड के लिए Chrome DevTools के साथ हाइलाइट किया गया हर ग्रिड दिया गया है:

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

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

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

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

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

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

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

हर इनपुट ग्रुप (.fieldset-item) वाले fieldset एलिमेंट में 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> के बीच का लॉजिकल लेआउट सिस्टम है.

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

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

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

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

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

ऑटो-फ़िट की कम से कम वैल्यू को दोहराएं

<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 ने इस बारे में एक शानदार लेआउट ब्लॉग पोस्ट पोस्ट की है. इसमें उन्होंने इसे रैम कहा है.

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

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

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

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

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

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

स्पेसिंग

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

: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 वेबपेज का स्क्रीनशॉट, जिसमें कलर 2: पर्सेप्शन एपिसोड दिखाया गया है
सीएसएस पॉडकास्ट पर, थीम के रंग (और ज़्यादा!) के बारे में जानें

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

: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 में है. हालांकि, आपको सीएसएस या एचटीएमएल में यह बताना होगा कि आपका डिज़ाइन इन कंट्रोल का इस्तेमाल करता है या नहीं.

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

<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. थंब

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

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 उपलब्ध है, तो कस्टम प्रॉपर्टी को वैल्यू के साथ सिंक करने के साथ-साथ, उपयोगकर्ता के बदलावों को भी देखते हुए भरें.

Ana Tudor के 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 काम करता है, तो इन चेकबॉक्स को ब्रैंड कलर स्कीम में लाएं.

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

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

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

SVG में काफ़ी डेटा जनरेट होता है. चलिए, माउस से कर्सर घुमाने के लिए, <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 को चेकबॉक्स लेबल के लिए होवर क्षेत्र की अपनी शैली के बारे में बताएं! इस वर्शन में एलिमेंट के बीच कोई होवर गैप नहीं है: डेमो और सोर्स.