نماذج متوافقة مع العلامة التجارية

ميزات الويب: accent-color

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

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

كيفية الإعداد

لتطبيق لون علامتك التجارية على عناصر التحكّم في النماذج:

  1. تحديد لون علامتك التجارية: اختَر لونًا يمثّل علامتك التجارية.
  2. تطبيق السمة accent-color: أضِف accent-color إلى العنصر أو عنصر حاوية (مثل body أو نموذج معيّن) في CSS.
  3. إتاحة الوضع الداكن (اختياري ولكن يُنصح به): استخدِم color-scheme لإعلام المتصفّح بأنّ موقعك الإلكتروني يتيح الوضع الداكن، واضبط accent-color إذا لزم الأمر للحصول على تباين أفضل.

مثال على الرمز البرمجي: عناصر تحكّم في النماذج متوافقة مع العلامة التجارية

:root {
  --brand-color: #6200ee;
}

/* Apply accent-color to the body or a specific container */
body {
  accent-color: var(--brand-color);
}

/* Optional: Adjust for dark mode if needed */
@media (prefers-color-scheme: dark) {
  :root {
    --brand-color: #bb86fc; /* A lighter shade for dark mode */
  }
}
<form>
  <!-- Checkbox -->
  <label for="subscribe">
    <input type="checkbox" id="subscribe" checked>
    Subscribe to newsletter
  </label>

  <!-- Radio Buttons -->
  <label for="plan-monthly">
    <input type="radio" id="plan-monthly" name="plan" value="monthly">
    Monthly
  </label>
  <label for="plan-yearly">
    <input type="radio" id="plan-yearly" name="plan" value="yearly" checked>
    Yearly
  </label>

  <!-- Range Slider -->
  <label for="volume">Volume:</label>
  <input type="range" id="volume" min="0" max="100" value="70">

  <!-- Progress Bar -->
  <label for="file">Upload Progress:</label>
  <progress id="file" max="100" value="70">70%</progress>
</form>

التنفيذ الاستراتيجي وأفضل الممارسات

  • يُفضَّل استخدام accent-color لتخصيص مظهر عناصر التحكّم في النماذج بسهولة بما يتوافق مع علامتك التجارية.
  • لا تثق في المتصفّح بشكل أعمى للتعامل مع التباين. من المفترض أن تحدّد المتصفّحات تلقائيًا لون تباين مؤهَّل، ولكن قد تفشل الأخطاء المعروفة في عمليات التنفيذ، مثل Safari (خطأ WebKit‏ 244233) وChrome على Android (خطأ Chromium‏ 343503163)، في عكس ألوان علامات الاختيار، ما يؤدي إلى ظهور عناصر تحكّم غير مرئية أو يصعب رؤيتها عند استخدام ألوان لا تتباين بشكل كافٍ مع الخلفية (مثل الألوان الفاتحة في الوضع الفاتح أو الألوان الداكنة في الوضع الداكن).
  • يجب الجمع بين accent-color وcolor-scheme: light dark لضمان ظهور عناصر التحكّم في النماذج بشكل جيد في كل من المظهرَين الفاتح والمظهر الداكن.
  • لا تستخدِم لونًا قريبًا جدًا من لون الخلفية، فعلى الرغم من أنّ المتصفّحات تحاول ضمان التباين، من الأفضل توفير لون ذي تباين أساسي جيد.
  • لا تفترض أنّ السمة accent-color تعمل على جميع عناصر النماذج. في الوقت الحالي، لا يغيّر هذا الخيار سوى لون عناصر checkbox وradio وrange وprogress.

استراتيجية الإجراءات الاحتياطية

بالنسبة إلى المتصفّحات التي لا تتيح استخدام accent-color، تعود عناصر التحكّم في النماذج إلى المظهر التلقائي للمتصفّح. لضمان اتساق العلامة التجارية بالكامل والموثوقية العالية في جميع البيئات، عليك تنفيذ استراتيجية احتياطية مخصّصة باستخدام أسلوب "الإدخال المخفي بصريًا" المحدّد.

التحسين المتدرّج باستخدام @supports not

يجب استخدام القاعدة @supports not لتطبيق أنماط احتياطية مخصّصة فقط عندما لا يكون accent-color متوافقًا. يضمن ذلك الاستفادة من بساطة accent-color للمتصفّحات الحديثة مع ضمان تجربة متّسقة للعلامة التجارية للمتصفّحات القديمة.

1. بنية HTML

تأكَّد من أنّ التصنيفات تلتف حول النص في <span> للسماح بأدوات اختيار العناصر الشقيقة في CSS:

<label for="subscribe-fallback">
  <input type="checkbox" id="subscribe-fallback" class="visually-hidden" checked>
  <span>Subscribe to newsletter</span>
</label>

2. الخيار الاحتياطي لخدمة مقارنة الأسعار (CSS)

تطبيق الأنماط المخصّصة ضمن مجموعة @supports not:

/* Fallback for older browsers without accent-color */
@supports not (accent-color: var(--brand-color)) {
  /* Visually hide the native input using the canonical accessible recipe */
  form input[type="checkbox"].visually-hidden {
    position: absolute !important;
    clip-path: inset(50%) !important;
    overflow: hidden !important;
    width: 1px !important;
    height: 1px !important;
    margin: -1px !important;
    padding: 0 !important;
    border: 0 !important;
    white-space: nowrap !important;
  }

  /* Style the wrapper label */
  label {
    position: relative;
    padding-left: 2rem;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
  }

  /* Custom box for checkbox */
  input[type="checkbox"] + span::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 1.2rem;
    height: 1.2rem;
    border: 2px solid #ccc;
    background: white;
    border-radius: 4px;
    box-sizing: border-box;
    transition: all 0.2s ease;
  }

  /* Ensure custom checkbox shows focus for keyboard users */
  input[type="checkbox"]:focus-visible + span::before {
    outline: 2px solid #000;
    outline-offset: 2px;
  }

  /* Checked State */
  input[type="checkbox"]:checked + span::before {
    background-color: var(--brand-color, #6200ee);
    border-color: var(--brand-color, #6200ee);
  }

  /* Checkmark (Unicode) */
  input[type="checkbox"]:checked + span::after {
    content: "✓";
    position: absolute;
    left: 0.25rem;
    top: 50%;
    transform: translateY(-50%);
    color: white;
    font-weight: bold;
    font-size: 0.9rem;
  }

  /* Fallback for Range Slider */
  input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    background: transparent;
  }

  /* Webkit (Chrome, Safari, Edge) */
  input[type="range"]::-webkit-slider-runnable-track {
    width: 100%;
    height: 8px;
    /* Use gradient to show progress for a static value (e.g., 70%) or update with JS */
    background: linear-gradient(to right, var(--brand-color, #6200ee) 70%, #ccc 70%);
    border-radius: 4px;
  }

  input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    height: 16px;
    width: 16px;
    border-radius: 50%;
    background: var(--brand-color, #6200ee);
    cursor: pointer;
    margin-top: -4px; /* Center vertically */
  }

  /* Firefox */
  input[type="range"]::-moz-range-track {
    width: 100%;
    height: 8px;
    background: #ccc;
    border-radius: 4px;
  }

  input[type="range"]::-moz-range-thumb {
    height: 16px;
    width: 16px;
    border-radius: 50%;
    background: var(--brand-color, #6200ee);
    cursor: pointer;
  }

  /* Firefox specific progress bar */
  input[type="range"]::-moz-range-progress {
    background-color: var(--brand-color, #6200ee);
    height: 8px;
    border-radius: 4px;
  }

  /* Fallback for Progress Bar */
  progress {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    border: none;
    background: #ccc;
    height: 8px;
    border-radius: 4px;
  }

  progress::-webkit-progress-bar {
    background-color: #ccc;
    border-radius: 4px;
  }

  progress::-webkit-progress-value {
    background-color: var(--brand-color, #6200ee);
    border-radius: 4px;
  }

  progress::-moz-progress-bar {
    background-color: var(--brand-color, #6200ee);
    border-radius: 4px;
  }
}

تقدُّم النطاق الديناميكي في Webkit Fallback

لجعل شريط التقدّم يتحرّك مع زرّ التمرير في شريط التمرير في متصفّحات Webkit (بدون accent-color)، يمكنك استخدام متغيّر CSS وكمية صغيرة من JavaScript.

  1. تعديل CSS: استخدِم متغيّر CSS لنقطة توقّف التدرج:

    input[type="range"]::-webkit-slider-runnable-track {
      background: linear-gradient(to right, var(--brand-color) var(--progress, 0%), #ccc var(--progress, 0%));
    }
    
  2. إضافة JavaScript: عدِّل المتغيّر في حدث input:

if (!CSS.supports('accent-color')) {
  const slider = document.getElementById('volume');
  slider.addEventListener('input', (e) => {
    e.target.style.setProperty('--progress', `${e.target.value}%`);
  });
}