بناء مكون زر

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

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

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

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

نظرة عامة

Browser Support

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

Source

تم تصميم العنصر <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 مجموعة من الأزرار. من الجيد أنّ أوراق الأنماط المتتالية يمكن أن تساعدنا في التعبير عن كل منها بوضوح.

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

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

التمرير والتركيز معًا

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

button:is(:hover, :focus) {
  
}
جرِّب عرضًا توضيحيًا!

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

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

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

ضمان تباين الألوان بشكل كافٍ

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

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

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

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

ظل الزر

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

--_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 box-shadow:

--_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 لكي لا تضطر النقرات إلى الانتظار ومراقبة احتمال حدوث نقرة مزدوجة، ما يجعل الأزرار تبدو أسرع:

: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 على none. تُعدّ أزرار ألوان التمييز (-webkit-tap-highlight-color) وقوائم السياق الخاصة بنظام التشغيل (-webkit-touch-callout) من الميزات الأخرى التي تركز بشكل كبير على الويب ولا تتوافق مع التوقعات العامة للمستخدمين بشأن الأزرار، لذا أزلتها أيضًا.

: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 إلى أن استوفت النتيجة المعايير في &quot;أدوات المطوّرين&quot; أو 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);
}

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

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

زر إدخال الملف هو حاوية لنطاق وزر. يمكن لملف 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 الزر لدفع نص span بعيدًا عن الزر، ما يؤدي إلى إنشاء بعض المساحة.

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

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

الخاتمة

بعد أن عرفت كيف فعلتُ ذلك، كيف ستفعل أنت ذلك؟ 🙂

لنستكشف الطرق المختلفة لإنشاء المحتوى على الويب.

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

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

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

الموارد