إنشاء أحد مكونات الإعدادات

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

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

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

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

نظرة عامة

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

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

التنسيقات

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

حدود ملونة وتراكبات لمساحة التباعد تساعد في عرض كل المربّعات التي تشكّل تنسيق الإعدادات

للاستخدام في حالة عدم توفّر بيانات

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

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

أُطلق على هذا التنسيق اسم "فقط للفراغ" لأنّه يستخدم الشبكة فقط لإضافة فراغات بين الكتل.

تستخدِم خمسة تنسيقات هذه الاستراتيجية، وإليك جميعها:

تصاميم شبكات رأسية مميّزة بخطوط خارجية ومملوءة بالفراغات

يستخدم عنصر fieldset، الذي يحتوي على كل مجموعة إدخال (.fieldset-itemgap: 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 اختصار alignment ليكون بالإمكان توسيط العناصر الثانوية عموديًا وأفقيًا في تنسيقات الأعمدة الواحدة والاثنين.

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

تكرار الحد الأدنى والحد الأقصى للضبط التلقائي

يستخدم <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 3 دوالّ CSS: repeat() وminmax() و min(). نشرت Una Kravets مقالًا رائعًا في مدوّنتها عن التنسيق، ووصفته باسم RAM.

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

  • نمرر دالة min() إضافية.
  • نحدّد align-items: flex-start.
  • هناك أسلوب max-width: 89vw.

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

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

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

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

Lea Verou

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

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

يوضّح المثال أعلاه تأثير الموقع من لوحة "الأنماط" في أدوات مطوّري البرامج. يستخدم الإصدار التجريبي علامة 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. 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 */
}

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

/* 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 من تأليف أنا تودور، توضّح حلّاً يعتمد على 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-styleposition وبخلاف ذلك، أستخدم بشكل أساسي عناصر أسلوبية بسيطة مستندة إلى رأيي الشخصي. أفضّل أن يكون المؤشر عبارة عن مؤشر، وأفضّل موضعات الخطوط الخارجية، وتكون مربّعات الاختيار التلقائية صغيرة جدًا، وإذا كان 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. لاحِظ كيف يتم نقل تركيز إدخال مباشرةً من شريط تمرير إلى آخر. ويعود السبب في ذلك إلى أنّنا أخفينا الرمز الذي ربما كان نقطة توقف في الطريق إلى شريط التمرير التالي. بدون هذه السمة، يحتاج المستخدم إلى التوقف والاستماع إلى الصورة التي قد لا يتمكّن من رؤيتها والانتقال إلى ما بعدها.

ملف 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()، حيث يتم عرض بيانات النموذج في جدول

الخاتمة

الآن بعد أن عرفت كيف فعلت ذلك، كيف ستفعل ذلك؟ وهذا يُعدّ ميزة رائعة في بنية المكوّنات. من سيُنشئ الإصدار الأول الذي يتضمّن خانات في إطار العمل المفضّل لديه؟ 🙂

لننوّع أساليبنا ونتعرّف على جميع الطرق لإنشاء تطبيقات على الويب. أنشئ عرضًا توضيحيًا، وأرسِل إلينا روابط على Twitter، وسنضيفه إلى قسم ريمكسات من إنشاء المنتدى أدناه.

الريمكسات التي أنشأها المستخدمون

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