EduFlow

الوحدة 5 · التبنّي على نطاق واسع

الـ Theming لعلامات متعدّدة على نطاق واسع

17 دقراءة 4 دبيئة تجريب الكود

الدرس في لمحة

أضف علامة تجارية ثانية إلى نظام التصميم بطبقة علامة صغيرة بين الـ primitives والـ semantic tokens، وتحقّق من التباين لكل علامة، وحدّد ما يحقّ للعلامات تغييره وما لا يحقّ لها.

  1. 1ما يحقّ للعلامة تغييره
  2. 2طبقة العلامة
  3. 3التباين لكل علامة
  4. 4تسليم العلامات

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

بعد ثمانية أشهر من استحواذ Northwind على Tidewater، انتقل موقعها التسويقي إلى Northwind UI. جاء فريق علامة Tidewater ومعه دليل علامة من 60 صفحة، وخط serif، ولوحة ألوان فيروزية، وأزرار على شكل حبّة دواء (pill). وجاء أيضًا بقائمة من 23 «متطلّبًا للعلامة» في المكوّنات. كانت مهمّتنا أن نقول نعم للعلامة ولا لمعظم القائمة، وأن نجعل الأمرين يبدوان معقولين.

ما يحقّ للعلامة تغييره

رسم الحوار الأول حدًّا واضحًا. العلامة تغيّر الشخصية: لوحة الألوان، والخطوط، ونصف قطر الزوايا، وأسلوب الرسوم، ونبرة الكتابة. ولا تغيّر السلوك أو البنية: التعامل مع لوحة المفاتيح، وإدارة التركيز، وسُلّم المسافات، وشبكات التخطيط، والـ component APIs، وإمكانية الوصول. يمكن أن تكون أزرار Tidewater حبّات فيروزية بتسمية بخط serif. لكن لا يمكنها أن تغلق النوافذ عند النقر خارجها بينما لا تفعل نوافذ Northwind ذلك، لأن هذا قرار منتج لا قرار علامة.

من المتطلّبات الثلاثة والعشرين، تبيّن أن 15 منها بصرية وتناسب الـ tokens. وستة كانت طلبات سلوك، فمرّت عبر مراجعة الـ API كاقتراحات عادية للعلامتين معًا (قُبل اثنان منها، للعلامتين). وأُسقط اثنان.

طبقة العلامة

قدّم القسم 2 تدرّجًا للعلامة حتى يستطيع الوضع الداكن اختيار الدرجات. ولعلامة ثانية كاملة، يكبر ذلك التدرّج ليصبح طبقة خاصة بين الـ primitives والـ semantic tokens:

الـ primitives تضم لوحتي الأزرق والفيروزي وعائلتي خطوط. طبقة علامة Northwind تربط الـ brand tokens بالأزرق وInter؛ وطبقة علامة Tidewater تربطها بالفيروزي وGeorgia. الـ semantic tokens تشير إلى الـ brand tokens، والمكوّنات تشير إلى الـ semantic tokens. Primitives blue-* teal-* inter georgia العلامة: Northwind brand-600 → blue العلامة: Tidewater brand-600 → teal Semantic المكوّنات
طبقة العلامة تقع بين الـ primitives والـ semantic tokens

طبقة العلامة صغيرة عن قصد. في Northwind تضم 24 token: تدرّج ألوان من 50 إلى 900، وعائلة خط للعناوين وأخرى للمتن، ونصفا قطر، ولون لحلقة التركيز. الـ semantic tokens تشير إلى الـ brand tokens، والمكوّنات لا تعرف أبدًا أن هناك علامة أصلًا.

CSS
:root,
[data-brand] {
  --nw-color-action-bg: var(--nw-brand-600);
  --nw-color-action-text: var(--nw-white);
  --nw-font-heading: var(--nw-brand-font-heading);
  --nw-radius-control: var(--nw-brand-radius-control);
}

[data-brand="tidewater"] {
  --nw-brand-600: var(--nw-teal-600);
  --nw-brand-700: var(--nw-teal-700);
  --nw-brand-font-heading: Georgia, 'Times New Roman', serif;
  --nw-brand-radius-control: 999px;
  /* Tidewater's 600 fails contrast with white text: use the darker step. */
  --nw-color-action-bg: var(--nw-brand-700);
}

الـ selector المسمّى :root, [data-brand] مهمّ. تذكّر من درس الـ themes أن الـ custom property التي تحتوي var() تُحسب حيث عُرّفت. لو عُرّف --nw-color-action-bg على :root وحده، لحُسب مرة واحدة بتدرّج Northwind، ولورث قسم Tidewater في الصفحة نفسها أزرق Northwind. أما إعادة تعريف الروابط الدلالية على كل عنصر [data-brand] فتجعلها تُحسب داخل نطاق كل علامة. وهذا ما يسمح لصفحة المقارنة المشتركة في Northwind بعرض العلامتين جنبًا إلى جنب.

التباين لكل علامة

السطر الأخير في كتلة Tidewater هو المثير للاهتمام. لون الإجراء في Northwind هو الدرجة 600 من تدرّجها. أما 600 في Tidewater فأفتح، فيفشل نص الزر الأبيض فوقه:

JavaScript
function luminance(hex) {
  const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255)
    .map((v) => (v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4));
  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
function contrast(a, b) {
  const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
  return (hi + 0.05) / (lo + 0.05);
}

const pairs = { 'northwind blue-600': '#1f5ae0', 'tidewater teal-600': '#0d9488', 'tidewater teal-700': '#0f766e' };
for (const [name, bg] of Object.entries(pairs)) {
  const ratio = contrast(bg, '#ffffff');
  console.log(`${name} + white text: ${ratio.toFixed(2)}:1 ${ratio >= 4.5 ? 'pass' : 'FAIL'}`);
}

لذا تربط Tidewater الدور الدلالي نفسه بدرجة مختلفة. ولهذا لا تكتفي طبقة العلامة بتبديل لوحات الألوان عشوائيًا: فالربط الدلالي لكل علامة مصمَّم ومفحوص. وفحص التباين في خط الإنتاج لدى Northwind يمرّ على كل زوج موثّق في كل علامة وكل theme، وقد التقط هذه المشكلة قبل أن يرى فريق العلامة زرًا واحدًا.

تسليم العلامات

كل واجهة تحمّل ما تحتاجه. المواقع التسويقية تضع data-brand على <html> ولا تحمّل إلا ملف CSS الخاص بعلامتها، الذي يولّده خط الإنتاج من primitives + brand-tidewater + semantic. أما تطبيق الـ dispatch، الذي يعرض العلامتين في شاشات الإدارة، فيحمّل الكتلتين. وفي Figma تعيش البنية نفسها في المجموعات الممتدّة، فيرى مصمّمو Tidewater المتغيّرات الدلالية المشتركة بقيم علامتهم.

وكل علامة تضاعف أيضًا مصفوفة الاختبار. مع علامتين ونظامي ألوان ومستويي كثافة، يُعرض كل مكوّن أساسي في ثماني تركيبات في المجموعة البصرية من القسم 4. يبدو ذلك مكلفًا حتى تتذكّر البديل: مصمّم في Tidewater يكتشف في الإنتاج أن حلقة التركيز في الوضع الداكن غير مرئية على الفيروزي. الآلات مراجِعون رخيصون للتركيبات؛ والبشر لا ينظرون إلا إلى الفروقات.

في التمرين تضيف Tidewater إلى صفحة تظهر فيها العلامتان جنبًا إلى جنب. وبعدها تقيس هل يُستخدم كل هذا فعلًا.

أهم النقاط

  • العلامة تغيّر الشخصية (تدرّج الألوان، والخطوط، والأشكال) عبر مجموعة صغيرة من brand tokens؛ أما السلوك والمسافات وإمكانية الوصول فتبقى مشتركة.
  • ضع طبقة للعلامة بين الـ primitives والـ semantic tokens، حتى تربط كل علامة الأسماء الدلالية نفسها بلوحة ألوانها الخاصة.
  • يجب فحص التباين لكل علامة على حدة، وقد تحتاج علامة درجة مختلفة من تدرّجها للدور الدلالي نفسه.
  • حين يمكن أن تظهر العلامات جنبًا إلى جنب، أعد تعريف الروابط الدلالية تحت الـ selector الخاص بالعلامة حتى تُحسب داخل نطاق كل علامة.

قراءات إضافية

تحقّق من فهمك

3 أسئلة

السؤال 1 من 3

يطلب فريق علامة Tidewater أن يُغلق الـ Dialog الخاص بها حين ينقر الناس خارجه، بينما لا يفعل ذلك Dialog الخاص بـ Northwind. كيف يجب أن يستجيب النظام؟

السؤال 2 من 3

نسبة التباين لنص أبيض على teal-600 الخاص بـ Tidewater هي 3.74:1. ماذا يجب أن يكون ربط Tidewater لـ --nw-color-action-bg؟

السؤال 3 من 3

في صفحة المقارنة المشتركة بين العلامتين، تبقى أزرار قسم Tidewater بأزرق Northwind، رغم أن [data-brand="tidewater"] يحدّد --nw-brand-600 بشكل صحيح. ما الناقص؟

تدريب

بيئة تجريب الكود

أضف Tidewater إلى صفحة المقارنة

صفحة المقارنة المشتركة تعرض العلامتين جنبًا إلى جنب، كلٌّ منهما في قسم له data-brand خاص به. أضف علامة Tidewater دون لمس قواعد المكوّنات:

  • العناوين تستخدم مجموعة خطوط Georgia ‏(--nw-font-georgia)،
  • الأزرار على شكل حبّة (نصف قطر 999px)،
  • خلفية الزر هي --nw-teal-700، لأن teal-600 يفشل في التباين مع النص الأبيض،
  • يجب أن يبقى قسم Northwind تمامًا كما هو.

حاليًا الطبقة الدلالية معرّفة على :root وحده. فكّر أين تُحسب قيمها.

<div class="compare">
  <section data-brand="northwind" id="nw">
    <h2 class="nw-heading">Northwind Dispatch</h2>
    <button class="nw-button" type="button">Start trial</button>
  </section>
  <section data-brand="tidewater" id="tw">
    <h2 class="nw-heading">Tidewater Freight</h2>
    <button class="nw-button" type="button">Get a quote</button>
  </section>
</div>جارٍ تحميل المحرّر…

Ctrl/⌘ + Enter للتشغيل · يعمل في بيئة معزولة داخل متصفّحك. لا شيء يغادر جهازك.

المعاينة

الـ console

(لا مخرجات)

الفحوص

  • قسم Northwind يحتفظ بزرّه الأزرق ونصف القطر 6px وعناوين Inter
  • عناوين Tidewater تستخدم Georgia
  • أزرار Tidewater على شكل حبّة (نصف قطر 999px)
  • أزرار Tidewater تستخدم teal-700 مع نص أبيض
  • لا توجد قاعدة تستهدف المكوّنات بحسب العلامة