السحب للإظهار

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

توفّر السمة scroll-initial-target في CSS طريقة تعريفية تستند إلى CSS فقط لتنفيذ هذا النمط. من خلال ضبط السمة scroll-initial-target: nearest على عنصر المحتوى الرئيسي، سيتم عرض حاوية الانتقال مع إخفاء المحتوى المخفي عن العرض. في السابق، كان المطوّرون يعتمدون على JavaScript (Element.scrollIntoView()) أو معرّفات أجزاء عناوين URL (#content-id) لتحقيق ذلك، وكلاهما لهما قيود ويصعب تنفيذهما.

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

لتنفيذ نمط السحب للكشف:

  1. التأكّد من توفّر حاوية قابلة للتمرير: يجب أن يكون العنصر المستهدَف داخل حاوية قابلة للتمرير (عنصر يتضمّن قائمة كاملة تسمح بالتمرير، مثل overflow: auto). يمكن أن يكون هذا العنصر أي عنصر رئيسي، بما في ذلك عنصر الجذر <html>.
  2. تحديد العنصر المخفي: ضع المحتوى الذي تريد إخفاءه (مثل شريط البحث) كأول عنصر فرعي داخل حاوية الانتقال. سيتم إخفاء هذا العنصر من العرض عند التحميل الأولي.
  3. تحديد المحتوى الرئيسي: ضع عنصر المحتوى الرئيسي مباشرةً بعد العنصر المخفي. هذا هو العنصر الذي يجب أن يراه المستخدم أولاً.
  4. استهداف المحتوى الرئيسي: طبِّق السمة scroll-initial-target: nearest على عنصر المحتوى الرئيسي لكي يتم عرض حاوية الانتقال مع الانتقال إلى المحتوى الرئيسي، ما يؤدي إلى إخفاء العنصر الذي يظهر فوقه.
  5. إضافة محاذاة مواضع التمرير: لضمان ظهور العنصر المخفي دائمًا بشكل كامل أو إخفائه بالكامل (وعدم بقائه في حالة تمرير جزئي)، أضِف scroll-snap-type: y mandatory إلى حاوية التمرير وscroll-snap-align: start إلى كل من العنصر المخفي وعنصر المحتوى الرئيسي.
/**
 * ANCESTOR: Define the scroll container.
 * Scroll snapping ensures the search bar is always
 * either fully visible or fully hidden.
 */
.scroll-container {
  height: 100vh;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
}

/**
 * HIDDEN ELEMENT: The search bar hidden above the fold on load.
 * It has scroll-snap-align so it snaps into place when pulled down.
 */
.search-bar {
  height: 60px;
  scroll-snap-align: start;
}

/**
 * MAIN CONTENT + TARGET: The element the user sees first.
 * scroll-snap-align makes it a valid snap point.
 * scroll-initial-target tells the browser to scroll here on
 * initial render, hiding the search bar above it.
 */
.main-content {
  scroll-snap-align: start;
  scroll-initial-target: nearest;
}

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

  • يُرجى استخدام scroll-initial-target: nearest عندما تريد لفت انتباه المستخدم إلى جزء معيّن من منطقة قابلة للتمرير عند التحميل وإخفاء وحدات واجهة المستخدم المحيطية عمدًا، مثل شريط البحث في أعلى الصفحة.
  • لا تخلط بين هذا وبين التركيز على أدوات تسهيل الاستخدام. تنقل هذه السمة إطار العرض المرئي فقط، ولا تنقل تركيز لوحة المفاتيح. يجب إدارة السمة element.focus() يدويًا إذا كان الهدف هو أن تكون نقطة البداية لمستخدمي لوحة المفاتيح.
  • لا تستخدِم هذه السمة إذا كنت بحاجة إلى صورة متحركة سلسة لـ "التمرير" عند التحميل، لأنّ هذه السمة منفصلة وتضبط الموضع على الفور أثناء مرحلة التنسيق.
  • لا تضبط السمة scroll-initial-target على عناصر متعددة ضمن الحاوية نفسها القابلة للتمرير. إذا حدّدت عناصر متعددة السمة scroll-initial-target: nearest، يختار المتصفّح العنصر الذي يظهر أولاً في ترتيب شجرة نموذج العناصر في المستند.
  • يجب مراعاة التسلسل الهرمي للأولوية: يحظى كلّ من جزء من عنوان URL (مثل example.com/#top) والسمة scroll-start على مستوى الحاوية بالأولوية على scroll-initial-target.

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

بالنسبة إلى المتصفّحات التي لا تتوافق مع واجهة برمجة التطبيقات هذه بعد، استخدِم إجراءً احتياطيًا في JavaScript. يُرجى العِلم أنّه عند سحب المحتوى للكشف عنه، يجب ربط المحتوى الرئيسي بـ start (أعلى) الحاوية.

/**
 * Progressive Enhancement Fallback
 */
document.addEventListener("DOMContentLoaded", () => {
  // Check for native CSS support
  if (!CSS.supports("scroll-initial-target", "nearest")) {
    const targetContent = document.querySelector('.main-content.target');
    if (targetContent) {
      // Use behavior: "instant" to mimic the native CSS behavior
      // 'block: start' should match your CSS 'scroll-snap-align' (or expected top position)
      targetContent.scrollIntoView({ behavior: 'instant', block: 'start' });
    }
  }
});