إنشاء مكوّن "الإعدادات"

نظرة عامة أساسية حول كيفية إنشاء مكوّن إعدادات يتضمّن أشرطة تمرير ومربّعات اختيار

في هذه المشاركة، أريد أن أشارك أفكاري حول إنشاء مكوّن "الإعدادات" على الويب، وهو مكوّن سريع الاستجابة ويتوافق مع إدخالات الأجهزة المتعددة ويعمل على جميع المتصفحات. جرِّب العرض التوضيحي.

العرض التوضيحي

إذا كنت تفضّل مشاهدة فيديو أو معاينة واجهة المستخدم/تجربة المستخدم لما نعمل على إنشائه، إليك جولة إرشادية أقصر على YouTube:

نظرة عامة

لقد قسّمت جوانب هذا المكوّن إلى الأقسام التالية:

  1. التنسيقات
  2. Color
  3. إدخال نطاق مخصّص
  4. إدخال مربّع اختيار مخصّص
  5. اعتبارات تسهيل الاستخدام
  6. JavaScript

التنسيقات

هذا هو أول عرض توضيحي لتحدي واجهة المستخدم الرسومية يعتمد بالكامل على شبكة CSS. في ما يلي كل شبكة مميّزة باستخدام أدوات مطوّري البرامج في Chrome للشبكة:

مخططات تفصيلية ملوّنة وتراكبات تباعد الفجوات التي تساعد في عرض جميع المربّعات التي تشكّل تصميم الإعدادات

للمسافة فقط

التنسيق الأكثر شيوعًا:

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);
  }
}
Border trick
.grid {
  display: grid;

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

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

التفاف الشبكة الطبيعي

كان التصميم الأكثر تعقيدًا هو تصميم الماكرو، أي نظام التصميم المنطقي بين <main> و<form>.

توسيط المحتوى الملتف

توفّر كلّ من Flexbox وGrid إمكانات align-items أو align-content، وعند التعامل مع العناصر الملتفّة، ستوزّع عمليات محاذاة التنسيق content المساحة بين العناصر الفرعية كمجموعة.

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

يستخدم العنصر الرئيسي place-content: center اختصار المحاذاة لكي تتم محاذاة العناصر الفرعية عموديًا وأفقيًا في كل من التنسيقات ذات العمود الواحد والعمودين.

شاهِد في الفيديو أعلاه كيف يبقى "المحتوى" في المنتصف، حتى بعد التفاف النص.

تكرار 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 ثلاث دالات CSS، وهي repeat() وminmax() وmin(). كتبت Una Kravets مشاركة رائعة في مدونتها حول التنسيق، وأطلقت عليها اسم RAM.

هناك 3 إضافات خاصة في تصميمنا، إذا قارنته بتصميم Una:

  • نمرّر دالة min() إضافية.
  • نحدّد قيمة align-items: flex-start.
  • يتوفّر نمط max-width: 89vw.

تتوفّر معلومات مفصّلة عن الدالة الإضافية min() في مدونة Evan Minto ضمن المشاركة Intrinsically Responsive CSS Grid with minmax() and min()، وأنصحك بقراءتها. يتم استخدام flex-start تصحيح المحاذاة لإزالة تأثير التمديد التلقائي، حتى لا يحتاج العناصر الفرعية في هذا التصميم إلى أن تكون متساوية في الارتفاع، بل يمكن أن يكون لها ارتفاعات طبيعية. يتضمّن فيديو YouTube شرحًا سريعًا لهذه الإضافة.

يستحق max-width: 89vw شرحًا موجزًا في هذه المشاركة. إليك التنسيق مع تطبيق النمط وبدونه:

ماذا يحدث؟ عند تحديد القيمة max-width، يتم توفير سياق أو تحديد حجم صريح أو تحديد حجم نهائي لخوارزمية التنسيق لمعرفة عدد مرات التكرار التي يمكن أن تتناسب مع المساحة.auto-fit على الرغم من أنّه يبدو واضحًا أنّ المساحة "بعرض كامل"، يجب توفير حجم محدد أو حجم أقصى وفقًا لمواصفات شبكة CSS. لقد قدّمتُ حجمًا أقصى.

إذًا، لماذا 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 وبنية المستوى 5 من ‎ @media. في ما يلي مثال على مجموعة أنماط التنسيق <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);
    }
  }
}

شبكة تتضمّن محتوى في المنتصف، مع مساحة متروكة معتدلة تلقائيًا (كما هو الحال على الأجهزة الجوّالة) ولكن مع توفّر المزيد من مساحة إطار العرض، يتم توزيعها عن طريق زيادة المساحة المتروكة. يبدو أنّ CSS لعام 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؟

بدون الخوض في تفاصيل نظرية الألوان، يمكن القول إنّ 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 تدرّج لوني: لون رمادي داكن جدًا بلا لون. بعد ذلك، في طلب البحث عن الوسائط للوضع الفاتح، يتم عكس قيمة السطوع إلى 90% باستخدام --surface1: lch(90 0 0);. وهذه هي الفكرة الأساسية للاستراتيجية. ابدأ بتغيير درجة السطوع بين المظهرَين فقط، مع الحفاظ على نسب التباين التي يتطلبها التصميم أو ما يمكن أن يحافظ على إمكانية الوصول.

الميزة الإضافية في lch() هي أنّ السطوع يركّز على الإنسان، ويمكننا أن نشعر بالرضا عن تغيير % فيه، لأنّ هذا التغيير سيكون واضحًا ومستمرًا بمقدار %. hsl() على سبيل المثال ليس موثوقًا.

يمكنك الاطّلاع على مزيد من المعلومات حول مساحات الألوان وlch() إذا كنت مهتمًا بذلك. سنطرحها قريبًا.

لا يمكن لـ CSS الوصول إلى هذه الألوان على الإطلاق في الوقت الحالي. أكرّر: لا يمكننا الوصول إلى ثلث الألوان في معظم الشاشات الحديثة. وهذه ليست أي ألوان، بل هي الألوان الأكثر سطوعًا التي يمكن أن تعرضها الشاشة. تظهر مواقعنا الإلكترونية باهتة لأنّ أجهزة الشاشات تطوّرت بشكل أسرع من مواصفات CSS وعمليات التنفيذ في المتصفحات.

ليا فيرو

عناصر التحكّم التكيّفية في النماذج مع نظام الألوان

تتضمّن العديد من المتصفّحات عناصر تحكّم في المظهر الداكن، مثل Safari وChromium حاليًا، ولكن عليك تحديد ذلك في CSS أو HTML لكي يستخدم تصميمك هذه العناصر.

يوضّح المثال أعلاه تأثير السمة من لوحة "الأنماط" في &quot;أدوات مطوّري البرامج&quot;. يستخدم العرض التوضيحي علامة HTML، والتي أعتقد أنّها بشكل عام موقع أفضل:

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

يمكنك الاطّلاع على كل التفاصيل في هذه color-schemeالمقالة التي كتبها توماس شتاينر. هناك الكثير من المزايا التي يمكن الاستفادة منها بدلاً من مربّعات الاختيار المخادعة.

CSS accent-color

حدثت نشاطات حديثة حول accent-color على عناصر النماذج، وهي عبارة عن نمط CSS واحد يمكنه تغيير لون الصبغة المستخدَم في عنصر الإدخال في المتصفحات. يمكنك الاطّلاع على مزيد من المعلومات حول هذا الموضوع هنا على GitHub. لقد أدرجته في أنماط هذا المكوّن. بما أنّ المتصفّحات تتيح ذلك، ستكون مربّعات الاختيار متوافقة مع المظهر الذي يتضمّن لمسات من اللونَين الوردي والأرجواني.

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

لقطة شاشة من Chromium على Linux لمربّعات اختيار وردية

صور مع تأثير البقع الملونة وتدرّجات ثابتة والتركيز داخل الصورة

تكون الألوان أكثر جاذبية عند استخدامها باعتدال، وأحد الطرق التي أفضّلها لتحقيق ذلك هي من خلال التفاعلات الملوّنة في واجهة المستخدم.

يتضمّن الفيديو أعلاه العديد من طبقات الملاحظات والتفاعلات في واجهة المستخدم، ما يساعد في إضفاء طابع شخصي على التفاعل من خلال:

  • تسليط الضوء على السياق
  • تقديم ملاحظات واجهة المستخدم حول "مدى امتلاء" القيمة في النطاق
  • تقديم ملاحظات لواجهة المستخدم تفيد بأنّ الحقل يقبل الإدخال

لتقديم ملاحظات عند التفاعل مع أحد العناصر، تستخدم CSS الفئة الصورية :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 المتداخل ليصبح دائرة كاملة، ويتم ملء الخلفية بتدرّج ثابت ساطع.

نطاق مخصّص

سأعرض لك كيفية تخصيص مظهر عنصر إدخال HTML التالي:

<input type="range">

يتضمّن هذا العنصر 3 أجزاء يجب تخصيصها:

  1. عنصر النطاق / الحاوية
  2. Track
  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 */
}

تتضمّن الأسطر القليلة الأولى من CSS الأجزاء المخصّصة من الأنماط، وآمل أن يساعدك تصنيفها بوضوح. أما بقية الأنماط، فهي في معظمها أنماط إعادة ضبط، وذلك لتوفير أساس متسق لإنشاء الأجزاء المعقّدة من المكوّن.

أنماط المقاطع الصوتية

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 للحفاظ على نمط التعبئة. تتوفّر استراتيجيات تستخدم CSS فقط، ولكنها تتطلّب أن يكون عنصر الإبهام بنفس ارتفاع المسار، ولم أتمكّن من إيجاد توافق ضمن هذه الحدود.

/* 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 من آنا تيودور، توضّح حلاً يعتمد على CSS فقط لملء المسار. لقد وجدت أيضًا عنصر 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 {}
}

مربّع اختيار مخصّص

سأعرض لك كيفية تخصيص مظهر عنصر إدخال HTML التالي:

<input type="checkbox">

يتضمّن هذا العنصر 3 أجزاء يجب تخصيصها:

  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 لتكبير الظل وتصغيره. ومع ذلك، لا يمكن استخدام هذا التأثير هنا لأنّ مربّعات الاختيار لدينا مربّعة ويجب أن تكون كذلك.

تمكّنت من تحقيق التأثير المرئي نفسه باستخدام عنصر صوري وكمية كبيرة من CSS المعقّد:

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

إنشاء عنصر زائف على شكل دائرة هو عمل مباشر، ولكن وضعه خلف العنصر الذي تم ربطه به كان أكثر صعوبة. في ما يلي مثال على النص قبل التعديل وبعده:

هذا التفاعل الصغير مهم بالنسبة إليّ للحفاظ على التناسق المرئي. تقنية تغيير حجم الرسوم المتحركة هي نفسها التي استخدمناها في مواضع أخرى. نضبط خاصية مخصّصة على قيمة جديدة ونسمح بانتقال CSS إليها استنادًا إلى إعدادات الحركة المفضّلة. الميزة الأساسية هنا هي translateZ(-1px). أنشأ العنصر الرئيسي مساحة ثلاثية الأبعاد، واستفاد العنصر الثانوي الزائف من هذه المساحة من خلال وضع نفسه في الخلف قليلاً في المساحة z.

تسهيل الاستخدام

يقدّم فيديو YouTube عرضًا توضيحيًا رائعًا لطريقة التفاعل مع هذا المكوّن من الإعدادات باستخدام الماوس ولوحة المفاتيح وقارئ الشاشة. سأذكر بعض التفاصيل هنا.

خيارات عناصر HTML

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

يحتوي كلّ من هذه الإشعارات على تلميحات ونصائح لأداة التصفّح التي يستخدمها المستخدم. تقدّم بعض العناصر تلميحات حول التفاعل، وتتيح بعضها التفاعل، وتساعد بعضها في تشكيل شجرة تسهيل الاستخدام التي يتنقّل فيها قارئ الشاشة.

سمات HTML

يمكننا إخفاء العناصر غير الضرورية لقارئات الشاشة، مثل الرمز بجانب شريط التمرير:

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

بالإضافة إلى ذلك، استخدمنا ما يكفي من ترميز HTML الواضح، ما يتيح إجراء اختبارات النموذج بشكل جيد جدًا باستخدام الماوس ولوحة المفاتيح وأذرع التحكّم في ألعاب الفيديو وبرامج قراءة الشاشة.

JavaScript

لقد سبق أن شرحتُ كيفية إدارة لون التعبئة للمسار من خلال JavaScript، لذا دعونا نلقي نظرة على JavaScript المرتبط بـ <form> الآن:

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

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

في كل مرة يتم فيها التفاعل مع النموذج وتغييره، تسجّل وحدة التحكّم النموذج كعنصر في جدول لتسهيل مراجعته قبل إرساله إلى الخادم.

لقطة شاشة لنتائج console.table()، حيث تظهر بيانات النموذج في جدول

الخاتمة

بعد أن عرفت كيف فعلت ذلك، كيف كنت ستتصرف؟ وهذا يؤدي إلى إنشاء بنية مكونات ممتعة. مَن سيتمكّن من إنشاء الإصدار الأول الذي يتضمّن مواضع إعلانية في إطار العمل المفضّل لديه؟ 🙂

لنستكشف الطرق المختلفة لإنشاء مواقع إلكترونية على الويب. يمكنك إنشاء أغنية تجريبية ومشاركة رابطها معي عبر تويتر، وسأضيفها إلى قسم ريمكسات من إنشاء المنتدى أدناه.

ريمكسات من إنشاء المنتدى

  • @tomayac على أسلوبه في ما يتعلّق بمساحة التمرير فوق تصنيفات مربّعات الاختيار! لا يتضمّن هذا الإصدار أي فجوة عند التمرير بين العنصرَين: العرض التوضيحي والمصدر.