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

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

ما التغييرات التي تنتمي إلى حالة المكوّن؟

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

لخاصية CSS مخصصة مثل --tile-size دور مختلف. فهي توفّر قيمة للتصريحات التي تشير إليها باستخدام var(). تشارك الخصائص المخصصة في التتالي وترث قيمها عادةً؛ وتسري عليها قواعد CSS حتى عندما يضبطها JavaScript. يحدّد مواصفات خصائص CSS المخصصة هذا العقد.

استخدم أداة اتخاذ القرار هذه قبل التحرير:

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

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

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

أنشئ معاينة مستقلة على جهاز Mac

استخدم محرر نصوص عاديًا لحفظ المستند الكامل التالي باسم tile-preview.html، ثم افتحه في Safari. أبقِ الامتداد .html. يتضمن المثال CSS وJavaScript الخاصين به، ويستخدم خطوط النظام، ويرسم بلاطة هندسية بسيطة من دون أصول خارجية.

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

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Tile preview</title>
  <style>
    body {
      font-family: system-ui, sans-serif;
      margin: 2rem;
      color: #222;
      background: #fff;
    }
    label { display: block; margin-block: 1rem; }
    .preview { padding: 24px; background: #eee; }
    .tile {
      width: 80px;
      height: 80px;
      border-radius: 0;
      width: var(--tile-size, 80px);
      height: var(--tile-size, 80px);
      border-radius: var(--tile-radius, 0);
      background-color: #547899;
    }
  </style>
</head>
<body>
  <h1>Tile preview</h1>
  <label>
    <input id="round" type="checkbox"> Round tile
  </label>
  <label>
    Tile size
    <input id="size" type="range" min="40" max="160"
           step="1" value="80">
  </label>
  <button id="reset" type="button">Reset choices</button>
  <p id="summary"></p>
  <div class="preview">
    <div id="tile" class="tile" aria-hidden="true"></div>
  </div>
  <script>
    const state = { rounded: false, size: 80 };
    const round = document.getElementById('round');
    const size = document.getElementById('size');
    const summary = document.getElementById('summary');
    const tile = document.getElementById('tile');
    const reset = document.getElementById('reset');

    function render() {
      round.checked = state.rounded;
      size.value = String(state.size);
      tile.style.setProperty('--tile-size', `${state.size}px`);
      tile.style.setProperty('--tile-radius', state.rounded ? '50%' : '0');
      summary.textContent = `Tile A: ${state.rounded ? 'round' : 'square'}, ${state.size}px.`;
    }

    function update(patch) {
      const next = { ...state, ...patch };
      if (typeof next.rounded !== 'boolean' ||
          !Number.isInteger(next.size) ||
          next.size < 40 || next.size > 160) {
        throw new RangeError('Use a boolean and a size from 40 to 160.');
      }
      Object.assign(state, next);
      render();
    }

    round.addEventListener('change', () => {
      update({ rounded: round.checked });
    });
    size.addEventListener('input', () => {
      update({ size: Number(size.value) });
    });
    reset.addEventListener('click', () => {
      update({ rounded: false, size: 80 });
    });
    render();
  </script>
</body>
</html>

واجهة الأنماط المستخدمة هنا موثقة: تكتب element.style.setProperty() تصريحًا مضمنًا، بما في ذلك خاصية مخصصة. وتُكتب أسماء الخصائص بصيغة CSS، مثل --tile-size. راجع مرجع MDN للدالة setProperty.

جرّب تحديد بلاطة مستديرة، وتحريك حجم البلاطة إلى قيمة مختلفة، ثم اختيار إعادة ضبط الاختيارات. ينبغي للإجراءين الأولين تحديث الشكل والوصف معًا؛ وينبغي لإعادة الضبط استعادة مربع بحجم 80 بكسل. في هذا البرنامج، إسناد قيمة إلى حقل في state وحده لا يستدعي render(). مرّر التغييرات عبر update() كي يحدث التحقق والعرض معًا.

تم التحقق من منطق التحديث والعرض في Node باستخدام عناصر تحكم وهمية وكائن نمط وهمي للقيم الأولية والقيم المتغيرة والأحجام غير الصالحة وإعادة الضبط. اجتازت هذه الفحوصات؛ لكنها لا تثبت طريقة العرض في المتصفح. استخدم الفحوصات المرئية أعلاه للتحقق من الملف في Safari.

متى ينبغي تجاوز تصريح CSS؟

لإجراء تغيير زخرفي دائم، عدّل ورقة الأنماط المحفوظة. على سبيل المثال، غيّر background-color في .tile إلى لون CSS آخر، أو عدّل الحشو في .preview. لا يتطلب أي من التغييرين حقل حالة جديدًا في هذا البرنامج، لأن أيًا منهما لا يمثّل اختيارًا.

لإجراء تجربة مؤقتة، فعّل مفتش Safari عبر Safari → Settings… → Advanced → Show features for web developers. افتح Develop → Show Web Inspector، أو اضغط Option-Command-I. هذه هي خطوات Mac الموثقة في دليل WebKit للمفتش.

مع فتح المثال، يغيّر المقطع الكامل التالي في وحدة التحكم لون البلاطة مؤقتًا، ثم يوفّر دالة تزيل هذا التجاوز:

const previewTile = document.getElementById('tile');
if (!previewTile) throw new Error('Open tile-preview.html first.');
previewTile.style.setProperty('background-color', '#8069a6');
function restoreTileColor() {
  previewTile.style.removeProperty('background-color');
}
// Run restoreTileColor() when finished comparing colors.

تتيح إزالة هذا التصريح المضمن للتتالي المتبقي تحديد اللون مجددًا. وهي لا تحذف تصريح اللون من ورقة الأنماط. ترد طريقة الإزالة في مرجع MDN للدالة removeProperty. للاحتفاظ بلون مختار بعد إعادة التحميل في هذا المثال، عدّل مصدر CSS واحفظه.

أبقِ التجاوزات المؤقتة بعيدة عن القيم التي يتولى العارض إدارتها. إذا غيّرت --tile-size يدويًا، فسيظل الوصف يعرض قيمة الحالة، وستستبدل دعوة render() التالية تجربتك. غيّر الحجم عبر عنصر التحكم أو دالة التحديث عندما تريد أن يتطابق المكوّن بأكمله.

لماذا قد يبدو أن التجاوز لا يفعل شيئًا؟

شخّص مسار القيمة قبل زيادة خصوصية المحدّد. قد يكون التصريح صالحًا لكنه يخسر في التتالي، أو قد يستهدف خاصية مخصصة لم يعد التصريح الفائز يستخدمها.

  1. تحقق من العنصر المستهدف. تأكد من تحديد العنصر الذي يعرض الشكل.
  2. تحقق من المدخل. يجب أن يكون الحجم في المثال عددًا صحيحًا بين 40 و160. تؤدي التحديثات غير الصالحة إلى طرح خطأ قبل تغيير الحالة.
  3. تحقق من الجهة المستهلكة للقيمة. تستخدم أبعاد البلاطة var(--tile-size). ويمكن لتصريح مباشر فائز width تجاوز تلك القيمة للعرض، بينما يظل الارتفاع يستخدمها.
  4. تحقق من الأولوية. قارن التصريحات المنطبقة والأهمية والطبقات والخصوصية.
  5. تحقق من التفاعل التالي. إذا اختفى التغيير بعد تحريك عنصر تحكم، فافحص ما تكتبه render().

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

ميّز أيضًا بين القيم المضمنة والقيم المحسومة. تعرض element.style التنسيق المضمن، لذا لا تعني قيمة مضمنة فارغة أن العنصر بلا تنسيق. تقرأ getComputedStyle() القيم المحسومة بعد تطبيق أوراق الأنماط النشطة. راجع مرجع MDN للخاصية style ومرجع getComputedStyle.

شغّل مقطع التشخيص الكامل التالي في وحدة تحكم صفحة المثال:

const inspectedTile = document.getElementById('tile');
if (!inspectedTile) throw new Error('Open tile-preview.html first.');
console.table({
  inlineSizeToken: inspectedTile.style.getPropertyValue('--tile-size'),
  inlineWidth: inspectedTile.style.getPropertyValue('width'),
  resolvedWidth: getComputedStyle(inspectedTile).width,
  resolvedHeight: getComputedStyle(inspectedTile).height
});

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

ما حدود المتصفح والموارد المهمة؟

تشير MDN إلى أن خصائص CSS المخصصة متاحة على نطاق واسع عبر المتصفحات منذ أبريل 2017. ولا يثبت ذلك دعمها في كل متصفح أقدم. يتضمن المثال تصريحات أبعاد عادية قبل تصريحات var()، كي يكون للبلاطة مظهر ثابت عند عدم توفر الخصائص المخصصة. راجع مرجع MDN للخصائص المخصصة.

لا يوفّر البديل الاحتياطي داخل var(--tile-size, 80px) توافقًا مع متصفح لا يستطيع تفسير الخصائص المخصصة. كما أنه لا يتحقق من صلاحية كل رمز مُعطى: فالقيمة المعرّفة مثل blue لا تصبح عرضًا صالحًا لمجرد وجود بديل احتياطي. يشرح دليل MDN للخصائص المخصصة هذه الحدود.

إذا كان المتصفح الأقدم المستهدف يفتقر إلى دعم الخصائص المخصصة، فالبديل المدعوم هو تعديل العارض ليكتب تصريحات مضمنة عادية لكل من width وheight وborder-radius باستخدام setProperty(). أبقِ التحقق من الحالة ومزامنة عناصر التحكم كما هما. يغيّر ذلك عقد العرض، لذا أزل عمليات الكتابة المتعارضة من العارض وتحقق من المتصفح المستهدف بدل افتراض تطابق الدعم.

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

المصادر