الجداول المتجاوبة

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

يتمثل جوهر الجدول المتجاوب في الحفاظ على العلاقة بين خلايا البيانات وعناوينها.

  1. الأساس الدلالي: استخدِم عناصر <table> العادية مع عناصر <thead> و<tbody> و<th>.
  2. السياق الثابت: يمكنك تطبيق السمة position: sticky على كلّ من عناوين الأعمدة وعناوين الصفوف. يضمن ذلك أنه بغض النظر عن مدى تمرير المستخدم في أي اتجاه، فلن يفقد أبدًا سياق ما تمثله البيانات.
  3. عمليات التحويل التكيُّفية: استخدِم طلبات البحث من النوع @container بدلاً من طلبات البحث من النوع @media. يتيح ذلك للجدول التكيّف استنادًا إلى عرضه الخاص (على سبيل المثال، عند وضعه في شريط جانبي أو تطبيق مصغّر ضيّق في لوحة البيانات) بدلاً من إطار العرض بأكمله.
  4. إدخال التصنيفات: في التنسيق المكدّس، يتم إخفاء <thead>، ويتم إدخال العناوين التي تسهّل الوصول إلى كل خلية باستخدام عناصر ::before الزائفة ومتغيّرات CSS.

خطوات التنفيذ

1. الترميز والتنسيق

نظِّم جدولك باستخدام عناوين دلالية عادية. استخدِم .table-wrapper للتعامل مع المحتوى الزائد وتوفير حاوية لطلبات البحث. أضِف سمة tabindex="0" إلى الحاوية لضمان أن يتمكّن المستخدمون الذين يستخدمون لوحة المفاتيح فقط من الانتقال في الجدول بشكل متّسق.

امنح الحاوية سمة role="region" لتوضيح الغرض منها. يجب توفير اسم العنصر الظاهر على واجهة المستخدم باستخدام السمة aria-labelledby (تشير إلى السمة id لعنصر حالي يقدّم شرحًا للجدول أو يسمّيه) أو السمة aria-label.

<div tabindex="0" role="region" aria-labelledby="employee-table-caption" class="table-wrapper">
  <table>
    <caption id="employee-table-caption">Current employee directory</caption>
    <thead>
      <tr>
        <th>Employee</th>
        <th>Role</th>
        <th>Status</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <!-- Row header remains sticky horizontally on desktop, 
             and becomes a sticky card header on mobile -->
        <th>Alex Rivera</th>
        <td>Engineer</td>
        <td>Active</td>
      </tr>
    </tbody>
  </table>
</div>

2. ضبط العناوين الثابتة

فعِّل التمرير واجعل العناوين ثابتة. استخدِم السمات المنطقية وقيم z-index الصريحة لإدارة ترتيب التكديس.

.table-wrapper {
  overflow: auto;
  max-inline-size: 100%;
  max-block-size: min(500px, 80vh);
  container-type: inline-size;
}

table {
  border-collapse: separate;
  border-spacing: 0;
}

/* Sticky column headers (desktop) */
thead {
  position: sticky;
  inset-block-start: 0;
  z-index: 1; /* Above sticky row headers */
}

/* Sticky row headers (desktop) */
tbody th {
  position: sticky;
  inset-inline-start: 0;
  background: white; /* Required to cover background during scroll */
}

3- تنسيق مكدَّس متجاوب

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

@container (width < 600px) {
  table, thead, tbody, tr, th, td {
    display: block;
  }

  thead {
    /* MANDATORY: Hide column header from layout and screen readers. */
    display: none
  }

  tr {
    margin-block-end: 1.5rem;
    border: 1px solid #ccc;
  }

  /* Sticky row headers at the top of each block/card */
  tbody th {
    position: sticky;
    inset-block-start: 0;
    z-index: 2;
    background: #eee;
  }

  /* Define column labels as CSS variables (often set via JS) */
  table {
    --label-1: "Employee";
    --label-2: "Role";
    --label-3: "Status";
  }

  /* Inject labels */
  td:nth-child(2)::before {
    /* MANDATORY: If using non-text content, provide the accessible name (after the /) which ensures screen readers hear the text alternative. */
    content: var(--label-2) ": ";
  }
  /* MANDATORY: Map the label for each column */
  td:nth-child(3)::before {
    content: var(--label-3) ": ";
  }
}