بناء مكون زر

نظرة عامة أساسية حول كيفية إنشاء مكونات <button> متكيّفة مع الألوان ومتجاوبة وسهلة الاستخدام

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

يمكن التفاعل مع الأزرار باستخدام لوحة المفاتيح والماوس في المظهرَين الفاتح والداكن.

إذا كنت تفضّل الفيديو، يمكنك الاطّلاع على نسخة من هذه المشاركة على YouTube:

نظرة عامة

دعم المتصفح

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1-

المصدر

تم تصميم العنصر <button> لتفاعل المستخدم. يتم تنشيط حدث click من لوحة المفاتيح والماوس واللمس والصوت وغير ذلك، مع قواعد ذكية حول توقيته. وتتوفّر أيضًا بعض الأنماط التلقائية في كل متصفح، حتى تتمكّن من استخدامها مباشرةً بدون أي تخصيص. استخدِم color-scheme للموافقة على استخدام الزرَّين الفاتح والداكن المتوفّرين في المتصفّح أيضًا.

وهناك أيضًا أنواع مختلفة من الأزرار، ويظهر كل منها في النسخة السابقة من Codepen. إذا لم يكن لعنصر <button> نوع، سيتم تعديله ليناسب عنصر <form>، وسيتم تغييره إلى نوع الإرسال.

<!-- buttons -->
<button></button>
<button type="submit"></button>
<button type="button"></button>
<button type="reset"></button>

<!-- button state -->
<button disabled></button>

<!-- input buttons -->
<input type="button" />
<input type="file">

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

معاينة للمجموعة النهائية من جميع أنواع الأزرار، والتي تظهر في نموذج وليس في نموذج، مع إضافات رائعة لأزرار الأيقونات والأزرار المخصصة.
معاينة المجموعة النهائية من جميع أنواع الأزرار، معروضة في نموذج وليس في نموذج، مع إضافات رائعة لأزرار الرموز والأزرار المخصّصة

تحتوي الأزرار أيضًا على فئات صورية لكي تستخدمها لغة CSS في تحديد النمط. توفّر هذه الفئات عناصر CSS لضبط مظهر الزر: :hover عند تمرير الماوس فوق الزر، :active عند الضغط على الماوس أو لوحة المفاتيح، :focus أو :focus-visible للمساعدة في تصميم التكنولوجيا المساعِدة.

button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
معاينة المجموعة النهائية من جميع أنواع الأزرار في المظهر الداكن
معاينة المجموعة النهائية من جميع أنواع الأزرار في المظهر الداكن

Markup

بالإضافة إلى أنواع الأزرار التي تقدّمها مواصفات HTML، أضفت زرًا يتضمّن رمزًا وزرًا يتضمّن فئة مخصّصة btn-custom.

<button>Default</button>
<input type="button" value="<input>"/>
<button>
  <svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
    <path d="..." />
  </svg>
  Icon
</button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom">Custom</button>
<input type="file">

بعد ذلك، يتم وضع كل زر داخل نموذج لأغراض الاختبار. بهذه الطريقة، يمكنني التأكّد من تعديل أنماط الزر التلقائي بشكل مناسب، والذي يعمل كزر إرسال. وأغيّر أيضًا استراتيجية الرمز، من رسومات SVG مضمّنة إلى رسومات SVG مموّهة، لضمان عمل كليهما بشكل جيد.

<form>
  <button>Default</button>
  <input type="button" value="<input>"/>
  <button>Icon <span data-icon="cloud"></span></button>
  <button type="submit">Submit</button>
  <button type="button">Type Button</button>
  <button type="reset">Reset</button>
  <button disabled>Disabled</button>
  <button class="btn-custom btn-large" type="button">Large Custom</button>
  <input type="file">
</form>

إنّ مصفوفة التركيبات ضخمة جدًا في هذه المرحلة. بين أنواع الأزرار، والفئات الزائفة، ووجوده أو خارجه، هناك أكثر من 20 مجموعة من الأزرار. من الجيد أنّ CSS يمكن أن تساعدنا في توضيح كلٍّ من هذه العناصر بوضوح.

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

يمكن الوصول إلى عناصر الأزرار بشكل طبيعي، ولكن هناك بعض التحسينات الشائعة.

التمرير بمؤشر الماوس والتركيز معًا

أريد تجميع :hover و:focus معًا باستخدام :is()، وهو عامل اختيار وظيفي زائف. يساعد هذا في ضمان أن تراعي واجهاتي دائمًا أنماط لوحة المفاتيح والتكنولوجيا المساعدة.

button:is(:hover, :focus) {
  
}
يمكنك تجربة الإصدار التجريبي.

حلقة تركيز تفاعلية

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

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

التأكّد من اجتياز اختبار تباين الألوان

هناك أربع مجموعات ألوان مختلفة على الأقل بين الألوان الفاتحة والداكنة تتطلّب مراعاة تباين الألوان: الزر وزر الإرسال وزر إعادة الضبط والزر غير مفعّل. يتم استخدام VisBug هنا لفحص جميع النتائج وعرضها في آنٍ واحد:

إخفاء الرموز عن المستخدمين الذين لا يمكنهم رؤيتها

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

<button>
  <svg … aria-hidden="true">...</svg>
  Icon Button
</button>
&quot;أدوات مطوري البرامج في Chrome&quot; تعرض شجرة تسهيل الاستخدام للزر تتجاهل الشجرة صورة الزر لأنّها تم ضبط aria-hidden على true.
أداة Chrome DevTools تعرض شجرة تسهيل الاستخدام للزر. تتجاهل الشجرة صورة الزر لأنّها تم ضبط aria-hidden على true

الأنماط

في هذا القسم التالي، أقوم أولاً بإنشاء نظام خاصية مخصصة لإدارة الأنماط التكيُّفية للزر. باستخدام هذه السمات المخصّصة، يمكنني البدء في اختيار العناصر وتخصيص مظهرها.

استراتيجية خاصة مخصّصة قابلة للتكيّف

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

button {
  --_bg-light: white;
  --_bg-dark: black;
  --_bg: var(--_bg-light);

  background-color: var(--_bg);
}

@media (prefers-color-scheme: dark) {
  button {
    --_bg: var(--_bg-dark);
  }
}

ما يعجبني هو أنّ المظهرَين الفاتح والداكن واضحان. يتم إلغاء الاتجاهات والتجريد في السمة --_bg المخصّصة، التي أصبحت الآن السمة "التفاعلية" الوحيدة، والسمة --_bg-light و--_bg-dark الثابتة. من الواضح أيضًا أنّ المظهر الفاتح هو المظهر التلقائي ولا يتم تطبيق المظهر الداكن إلا بشكل مشروط.

التحضير لتحقيق اتساق التصميم

أداة الاختيار المشتركة

يتم استخدام المحدد التالي لاستهداف جميع أنواع الأزرار المختلفة وهو مربك بعض الشيء في البداية. يتم استخدام :where() كي لا يتطلّب تخصيص الزر أيّ تحديد. وغالبًا ما تكون الأزرار مناسبة للسيناريوهات البديلة، وتضمن أداة اختيار :where() سهولة تنفيذ هذه المهمة. داخل ":where()"، يتم اختيار كل نوع من أنواع الأزرار، بما في ذلك ::file-selector-button، الذي لا يمكن استخدامه داخل :is() أو :where().

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  
}

سيتم تحديد نطاق جميع المواقع المخصّصة داخل أداة الاختيار هذه. حان الوقت لمراجعة جميع المواقع المخصّصة. هناك عدد غير قليل من الخصائص المخصّصة المستخدَمة في هذا الزر. سأصف كل مجموعة أثناء الشرح، ثم سأشارك سياقات الصور المظلمة والمنخفضة السرعة في نهاية القسم.

لون تمييز الزر

إنّ أزرار الإرسال والرموز هي مكان رائع لإضافة لمسة من الألوان:

--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);

لون نص الزر

إنّ ألوان نص الأزرار ليست بيضاء أو سوداء، بل هي نُسخ داكنة أو فاتحة من --_accent باستخدام hsl() مع الالتزام بتدرُّج اللون 210:

--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);

لون خلفية الزر

تتّبع خلفيات الأزرار نمط hsl() نفسه باستثناء أزرار المظهر الفاتح، والتي يتم ضبطها على اللون الأبيض لكي تبدو سطحها قريبة من المستخدِم أو أمام الأسطح الأخرى:

--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);

خلفية الزر

لون الخلفية هذا مخصص لجعل سطح يظهر خلف الأسطح الأخرى، وهو مفيد لخلفية إدخال الملف:

--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);

المساحة الفارغة حول الزر

يتم ضبط المسافة حول النص في الزر باستخدام وحدة ch ، وهي طول نسبي لحجم الخط. يصبح هذا الأمر مهمًا عندما يتمكّن الزرّ الكبير من زيادة مقاييس font-size والزرّ بشكلٍ نسبي:

--_padding-inline: 1.75ch;
--_padding-block: .75ch;

حدود الزر

يتم تخزين نصف قطر حدود الزر في خاصيّة مخصّصة لكي تتمكّن مدخلات الملف من مطابقة الأزرار الأخرى. تتّبع ألوان الحدود نظام الألوان المتغيّرة المعمول به:

--_border-radius: .5ch;

--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);

تأثير تمييز الزر عند التمرير فوقه

تحدِّد هذه السمات سمة المقاس لعملية النقل عند التفاعل، ويتبع لون التمييز نظام الألوان التكيُّفية. سنتناول كيفية تفاعل هذه العوامل مع بعضها لاحقًا في هذه المشاركة، ولكن في النهاية يتم استخدامها لتحقيق box-shadow تأثير:

--_highlight-size: 0;

--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);

ظل نص الزر

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

--_ink-shadow-light: 0 1px 0 var(--_border-light);
--_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%);
--_ink-shadow: var(--_ink-shadow-light);

رمز الزر

الأيقونات بحجم حرفين بفضل الطول النسبي لوحدة ch مرة أخرى، مما سيساعد في تغيير حجم الرمز بشكل يتناسب مع نص الزر. يعتمد لون الرمز على --_accent-color للحصول على لون متوافق مع المظهر .

--_icon-size: 2ch;
--_icon-color: var(--_accent);

ظل الزر

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

--_shadow-color-light: 220 3% 15%;
--_shadow-color-dark: 220 40% 2%;
--_shadow-color: var(--_shadow-color-light);

--_shadow-strength-light: 1%;
--_shadow-strength-dark: 25%;
--_shadow-strength: var(--_shadow-strength-light);

باستخدام الألوان ونقاط القوة القابلة للتكيف، يمكنني تجميع عمقين من الظلال:

--_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%));

--_shadow-2: 
  0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)),
  0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%));

بالإضافة إلى ذلك، يضفي ظلال مربع 1px على الأزرار شكلاً ثلاثي الأبعاد بعض الشيء:

--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);

انتقالات الأزرار

باتباع نمط الألوان التكيُّفية، أقوم بإنشاء خاصيتين ثابتتين للاحتفاظ بخيارات نظام التصميم:

--_transition-motion-reduce: ;
--_transition-motion-ok:
  box-shadow 145ms ease,
  outline-offset 145ms ease
;
--_transition: var(--_transition-motion-reduce);

جميع المواقع معًا في أداة الاختيار

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  --_accent-light: hsl(210 100% 40%);
  --_accent-dark: hsl(210 50% 70%);
  --_accent: var(--_accent-light);

--_text-light: hsl(210 10% 30%); --_text-dark: hsl(210 5% 95%); --_text: var(--_text-light);

--_bg-light: hsl(0 0% 100%); --_bg-dark: hsl(210 9% 31%); --_bg: var(--_bg-light);

--_input-well-light: hsl(210 16% 87%); --_input-well-dark: hsl(204 10% 10%); --_input-well: var(--_input-well-light);

--_padding-inline: 1.75ch; --_padding-block: .75ch;

--_border-radius: .5ch; --_border-light: hsl(210 14% 89%); --_border-dark: var(--_bg-dark); --_border: var(--_border-light);

--_highlight-size: 0; --_highlight-light: hsl(210 10% 71% / 25%); --_highlight-dark: hsl(210 10% 5% / 25%); --_highlight: var(--_highlight-light);

--_ink-shadow-light: 0 1px 0 hsl(210 14% 89%); --_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%); --_ink-shadow: var(--_ink-shadow-light);

--_icon-size: 2ch; --_icon-color-light: var(--_accent-light); --_icon-color-dark: var(--_accent-dark); --_icon-color: var(--accent, var(--_icon-color-light));

--_shadow-color-light: 220 3% 15%; --_shadow-color-dark: 220 40% 2%; --_shadow-color: var(--_shadow-color-light); --_shadow-strength-light: 1%; --_shadow-strength-dark: 25%; --_shadow-strength: var(--_shadow-strength-light); --_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%)); --_shadow-2: 0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)), 0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%)) ;

--_shadow-depth-light: hsl(210 14% 89%); --_shadow-depth-dark: var(--_bg-dark); --_shadow-depth: var(--_shadow-depth-light);

--_transition-motion-reduce: ; --_transition-motion-ok: box-shadow 145ms ease, outline-offset 145ms ease ; --_transition: var(--_transition-motion-reduce); }

تظهر الأزرار التلقائية بالمظهر الفاتح والداكن جنبًا إلى جنب.

التعديلات على المظهر الداكن

تصبح قيمة النمطَين الثابتَين -light و-dark واضحة عند ضبط مظهر المظهر الداكن:

@media (prefers-color-scheme: dark) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_bg: var(--_bg-dark);
    --_text: var(--_text-dark);
    --_border: var(--_border-dark);
    --_accent: var(--_accent-dark);
    --_highlight: var(--_highlight-dark);
    --_input-well: var(--_input-well-dark);
    --_ink-shadow: var(--_ink-shadow-dark);
    --_shadow-depth: var(--_shadow-depth-dark);
    --_shadow-color: var(--_shadow-color-dark);
    --_shadow-strength: var(--_shadow-strength-dark);
  }
}

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

التعديلات التي تقلّل من الحركة

إذا كان هذا المستخدم الزائر يوافق على استخدام ميزة "التنقّل"، يمكنك منح إذن --_transition لمحاولة var(--_transition-motion-ok):

@media (prefers-reduced-motion: no-preference) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_transition: var(--_transition-motion-ok);
  }
}

بعض الأنماط المشتركة

يجب ضبط خطوط الأزرار والمدخلات على inherit لكي تتطابق مع بقية خطوط الصفحة، وإلا سيضبط المتصفّح أسلوبها. وينطبق ذلك أيضًا على letter-spacing. يؤدي ضبط line-height على 1.5 إلى ضبط حجم مربّع الرسالة لإعطاء النص بعض المساحة أعلاه وأسفله:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  /* …CSS variables */

  font: inherit;
  letter-spacing: inherit;
  line-height: 1.5;
  border-radius: var(--_border-radius);
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة

أزرار التصميم

ضبط أداة الاختيار

المحدد input[type="file"] ليس جزءًا من الزر في الإدخال، العنصر الزائف ::file-selector-button، لذا أزلت input[type="file"] من القائمة:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  
}

تعديلات المؤشر واللمس

أولاً، أضبط أسلوب المؤشر على pointer، ما يساعد الزر في الإشارة إلى مستخدمي الماوس بأنّه تفاعلي. بعد ذلك، أضِف touch-action: manipulation لجعل النقرات لا تحتاج إلى الانتظار وملاحظة نقرة مزدوجة محتملة، ما يجعل استخدام buttons أسرع:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  cursor: pointer;
  touch-action: manipulation;
}

الألوان والحدود

بعد ذلك، خصّصت حجم الخط والخلفية والنص وألوان الحدود باستخدام بعض الخصائص المخصّصة التكيُّفية التي تم إنشاؤها سابقًا:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  font-size: var(--_size, 1rem);
  font-weight: 700;
  background: var(--_bg);
  color: var(--_text);
  border: 2px solid var(--_border);
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة.

الظلال

تم تطبيق بعض الأساليب الرائعة على الأزرار. text-shadow هو رمز متوافق مع المظهر الفاتح والداكن، ما يخلق مظهرًا لطيفًا لنص الزر الذي يظهر بشكل جميل على أعلى الخلفية. بالنسبة إلى box-shadow، يتمّ تخصيص ثلاثة ظلال. الخيار الأول، --_shadow-2، هو ظل مربّع عادي. الظل الثاني هو خدعة للعين تجعل الزر يبدو منيفًا قليلاً. الظل الأخير مخصّص لتمييز المؤشر، وهو يبدأ بحجم 0، ولكن سيتم منحه حجمًا لاحقًا وسيتم نقله ليبدو كأنّه يكبر من الزر.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  box-shadow: 
    var(--_shadow-2),
    var(--_shadow-depth),
    0 0 0 var(--_highlight-size) var(--_highlight)
  ;
  text-shadow: var(--_ink-shadow);
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة.

التنسيق

أعطيت الزر تنسيق flexbox، تحديدًا تنسيق inline-flex ليناسب محتواه. بعد ذلك، أتوسّط النص وأحاذي العناصر الفرعية عموديًا وأفقيًا في الوسط. سيساعد هذا الأيقونات وعناصر الأزرار الأخرى على المحاذاة بشكل صحيح.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  display: inline-flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة

المسافات

لتباعد الأزرار، استخدمت gap لمنع الأشقاء من اللمس والخصائص المنطقية للمساحة المتروكة حتى تعمل التباعد على الأزرار في جميع تنسيقات النص.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  gap: 1ch;
  padding-block: var(--_padding-block);
  padding-inline: var(--_padding-inline);
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة

تجربة المستخدم في اللمس والماوس

يتناول هذا القسم التالي بشكل أساسي مستخدمي الأجهزة التي تعمل باللمس على الأجهزة الجوّالة. تُستخدم السمة الأولى، user-select، لجميع المستخدمين وهي تمنع النص الذي يبرز نص الزر. ويظهر ذلك بشكلٍ ملحوظ في الغالب على الأجهزة التي تعمل باللمس عند النقر مع الاستمرار على زر معيّن وتمييز نظام التشغيل لنص الزر.

لقد وجدتُ بشكل عام أنّ هذه الإضافة لا تنطبق على تجربة المستخدم بسبب الأزرار في التطبيقات المضمَّنة، لذلك يمكنني إيقافها عن طريق ضبط السمة user-select على "بدون". إنّ ألوان التمييز (-webkit-tap-highlight-color) وقوائم السياقات لنظام التشغيل (-webkit-touch-callout) هي ميزات أخرى تركّز على الويب ولا تتوافق مع توقعات مستخدمي buttons بشكل عام، لذا أزيلها أيضًا.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

الانتقالات

يتمّ تعيين المتغيّر --_transition التكيُّفي إلى سمة transition:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  transition: var(--_transition);
}

عند التمرير فوق الزر، بدون أن يضغط عليه المستخدم، يمكنك تعديل حجم تمييز الظل لإضفاء مظهر جميل للتركيز يبدو أنّه يكبر من داخل الزر:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
):where(:not(:active):hover) {
  --_highlight-size: .5rem;
}

عند التركيز على الزر، يمكنك زيادة انحراف مخطط التركيز عن الزر، ما يمنحه أيضًا مظهرًا جميلاً للتركيز يبدو أنّه يكبر من داخل الزر:

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

الرموز

لمعالجة الرموز، يحتوي المحدّد على أداة اختيار :where() مضافة لعناصر SVG التابعة مباشرةً أو العناصر التي تحتوي على السمة المخصّصة data-icon. يتم ضبط حجم الرمز باستخدام السمة المخصّصة باستخدام السمتَين المنطقيتَين "مضمّن" و"مربّع". تم ضبط لون الخط، بالإضافة إلى drop-shadow ليتطابق مع text-shadow. تم ضبط flex-shrink على 0 وبالتالي لا يتم ضغط الرمز أبدًا. أخيرًا، اخترت رموزًا مسطّحة وأضفت إليها هذه الأنماط باستخدام fill: none وround لرؤوس الخطوط ووصلاتها:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
) > :where(svg, [data-icon]) {
  block-size: var(--_icon-size);
  inline-size: var(--_icon-size);
  stroke: var(--_icon-color);
  filter: drop-shadow(var(--_ink-shadow));

  flex-shrink: 0;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة

تخصيص أزرار الإرسال

أردت إرسال الأزرار للحصول على مظهر تم الترويج له قليلاً، وقد حققت ذلك من خلال جعل لون نص الأزرار هو لون التمييز:

:where(
  [type="submit"], 
  form button:not([type],[disabled])
) {
  --_text: var(--_accent);
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة

تخصيص أزرار إعادة الضبط

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

:where([type="reset"]) {
  --_border-light: hsl(0 100% 83%);
  --_highlight-light: hsl(0 100% 89% / 20%);
  --_text-light: hsl(0 80% 50%);
  --_text-dark: hsl(0 100% 89%);
}

فكّرتُ أيضًا أنّه من الجيد أن يتطابق لون مخطّط التركيز مع لون التمييز الأحمر. يتم تعديل لون النص من الأحمر الداكن إلى الأحمر الفاتح. أجعل لون المخطط يطابق هذا مع الكلمة الرئيسية currentColor:

:where([type="reset"]):focus-visible {
  outline-color: currentColor;
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة

تخصيص الأزرار غير المفعّلة

من الشائع جدًا أن يكون التباين اللوني للأزرار غير النشطة ضعيفًا أثناء محاولة تخفيف ظهور الزر غير النشط. لقد اختبرت كل مجموعة من الألوان وتأكّدت من اجتيازها، مع تعديل قيمة الإضاءة في HSL إلى أن اجتازت النتيجة في DevTools أو VisBug.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
)[disabled] {
  --_bg: none;
  --_text-light: hsl(210 7% 40%);
  --_text-dark: hsl(210 11% 71%);

  cursor: not-allowed;
  box-shadow: var(--_shadow-1);
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة.

تخصيص أزرار إدخال الملفات

زر إدخال الملف هو حاوية لعنصر span وزر. يمكن لأسلوب CSS تنسيق حاوية الإدخال قليلاً، بالإضافة إلى الزر المُدمَج، ولكن ليس العنصر. يتم منح الحاوية max-inline-size لكي لا تكبر أكثر مما ينبغي، بينما سيسمح inline-size: 100% بتصغيرها وملاءمتها للحاويات الأصغر حجمًا. يتم ضبط لون الخلفية على لون تكيُّفي يكون أغمق من الأسطح الأخرى، بحيث يظهر خلف زر اختيار الملف.

:where(input[type="file"]) {
  inline-size: 100%;
  max-inline-size: max-content;
  background-color: var(--_input-well);
}

تم منح زرّ اختيار الملفات وأزرار نوع الإدخال تحديدًا appearance: none لإزالة أي أنماط يوفّرها المتصفّح ولم يتم استبدالها بأنماط الأزرار الأخرى.

:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
  appearance: none;
}

أخيرًا، تتم إضافة هامش إلى inline-end الزرّ لدفع نص النطاق بعيدًا عن الزرّ، ما يخلق بعض المساحة.

:where(input[type="file"])::file-selector-button {
  margin-inline-end: var(--_padding-inline);
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة

استثناءات خاصة للمظهر الداكن

أعطيتُ أزرار الإجراءات الأساسية خلفية داكنة لنص أعلى تباينًا، مما يمنحها مظهرًا أكثر ترويجًا قليلاً.

@media (prefers-color-scheme: dark) {
  :where(
    [type="submit"],
    [type="reset"],
    [disabled],
    form button:not([type="button"])
  ) {
    --_bg: var(--_input-well);
  }
}

لقطة شاشة تعرض الأزرار بعد تطبيق الأنماط السابقة

إنشاء الأسعار المتغيرة

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

زرّ حيوي

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

.btn-custom {
  --_bg: linear-gradient(hsl(228 94% 67%), hsl(228 81% 59%));
  --_border: hsl(228 89% 63%);
  --_text: hsl(228 89% 100%);
  --_ink-shadow: 0 1px 0 hsl(228 57% 50%);
  --_highlight: hsl(228 94% 67% / 20%);
}

يظهر الزرّ المخصّص بالإضاءة والداكنة. وهو أزرق نابض بالحياة مثل أزرار الإجراءات الأساسية المعتادة.

زر كبير

يتمّ الحصول على نمط الزرّ هذا من خلال تعديل السمة المخصّصة --_size. تكون عناصر الحشو وعناصر المساحة الأخرى نسبية لهذا الحجم، ويتم تغيير حجمها تناسبيًا مع الحجم الجديد.

.btn-large {
  --_size: 1.5rem;
}

يظهر الزر الكبير بجانب الزر المخصّص، أي أكبر بـ 150 مرة تقريبًا.

زر الرمز

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

[data-icon="cloud"] {
  --icon-cloud: url("https://api.iconify.design/mdi:apple-icloud.svg") center / contain no-repeat;

  -webkit-mask: var(--icon-cloud);
  mask: var(--icon-cloud);
  background: linear-gradient(to bottom, var(--_accent-dark), var(--_accent-light));
}

يظهر زر يتضمّن رمزًا في المظهرَين الفاتح والداكن.

الخاتمة

الآن بعد أن عرفت كيف فعلت ذلك، كيف يمكنك‽ 🙂

لننوّع أساليبنا ونتعرّف على جميع الطرق لإنشاء تطبيقات على الويب.

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

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

ما مِن عناصر للاطّلاع عليها هنا حتى الآن.

الموارد