جدول البيانات
Data Table<table> + <th scope>
اسمه كمانالجدول، تيبل، داتا تيبل، جريد، شبكة بيانات، جدول قابل للفرز، table، HTML table، sortable table، data grid، grid view، tabular list
جدول البيانات عرض ثنائي المحور: الصفّ سجلّ واحد، والعمود صفة واحدة تتكرّر في كل السجلّات، ومعنى الخلية يأتي من تقاطع الاثنين. وهو أداة مقارنة قبل أن يكون أداة عرض، فالقيمة التي يحتاج القارئ إلى وزنها بغيرها تُوضع في عمود، وما لا يُقارَن يبقى في بطاقة أو قائمة. وهو ليس شبكة من عناصر <div> منسّقة بـ CSS Grid، فتلك ترسم الخطوط وتُسقِط العلاقة، ولا يعرف قارئ الشاشة أن «12,400» هي مبيعات صفّ «قميص قطن» ما لم يحمل كل مستوى دوره: role="table" ثم rowgroup ثم row ثم columnheader و rowheader و cell. وهو ليس data grid كذلك، لأن role="grid" يُعلن عنصر تحكّم فيه تركيز على مستوى الخلية يتنقّل بمفاتيح الأسهم، وينقل معظم قارئات الشاشة من وضع التصفّح إلى نقطة تركيز واحدة متجوّلة. وهو ليس جدول تخطيط، أي استعمال <table> لترتيب عناصر الصفحة، وذاك يحتاج role="presentation" حتى تخرج دلالات الصفوف والخلايا من شجرة الوصول. والسؤال الذي يحسم الاختيار قبل كتابة سطر واحد: هل ينتقل المستخدم بين الخلايا بالأسهم ويحرّر داخلها؟ إن كان الجواب لا، فترميز <table> العادي هو الجواب كلّه، و role="grid" فوقه ينزع سلوك لوحة المفاتيح من المتصفّح دون أن يضع بديلاً.
لو قلت عليه…
العيّنة الحيّة
تفاعل مع الديمو. كل الأجزاء حقيقية ومرقّمة.
| المنتج | المنطقة | آخر طلب | ||
|---|---|---|---|---|
| حقيبة ظهر | دبي | 21,900 | +11.8% | 2026-08-15 |
| قميص قطن | الرياض | 12,400 | +4.2% | 2026-08-12 |
| حذاء رياضي | القاهرة | 8,150 | -3.1% | 2026-08-09 |
تشريح العنصر: كل جزء واسمه
مرّر على أي سطر ليتحدّد مكانه في الديمو فوق.
برومبت البناء
سلوكه في الاتجاه من اليمين لليسار
الجزء ده حصري عندنا.
ترتيب الأعمدة
ينعكسترتيب الأعمدة يأتي من direction المحسوبة على صندوق الجدول نفسه: في RTL يُرسم أول عمود في الـ DOM عند اليمين، ويسير ما بعده يساراً. لا تعكس ترتيب <td> في الترميز لتصل إلى هذا الشكل، فالعكس اليدوي يفصل الخلية عن رأسها ويكسر scope وهو يبدو سليماً بالعين. وضبط dir على <tbody> أو على خلية واحدة لا يعيد ترتيب شيء، لأن الترتيب يُقرأ من الجدول وحده، فضع الاتجاه على <table> أو على ما يحيط به.
العمود المجمّد
ينعكسجمّد العمود بـ inset-inline-start: 0 لا بـ left: 0. مع left: 0 في العربية تلتصق الخلية بالحافّة اليسرى بينما عمودها معروض عند اليمين، فتستقرّ فوق أعمدة أخرى. والفاصل بينه وبين ما يمرّ تحته يكون border-inline-end، أما box-shadow فلا صيغة منطقية له إطلاقاً، فإن استعملته فوقّع إزاحته بمتغيّر اتجاه على هيئة calc(6px * var(--dir)) وأعطِ --dir القيمة -1 داخل [dir="rtl"].
سهم الفرز
لا ينعكسسهم الفرز رأسي: لأعلى للتصاعدي ولأسفل للتنازلي، والمحرفان ↑ U+2191 و ↓ U+2193 قيمة Bidi_Mirrored فيهما No فلا ينقلب أيّهما مع الصفحة، وكذلك لا يتغيّر معنى aria-sort، فـ ascending هو الأصغر أولاً في العربية كما في الإنجليزية. والقاعدة الشاملة [dir="rtl"] svg { transform: scaleX(-1) } تطال هذا السهم مع كل أيقونة أخرى في الرأس، فاقصر القلب على صنف تضعه على الأيقونات الأفقية وحدها. أما موضع السهم داخل خلية الرأس فينعكس لأنه يجلس عند النهاية المنطقية، فادفعه بـ margin-inline-start: auto أو بـ justify-content: flex-end في صفّ flex، ولا تكتب margin-left.
الأعمدة الرقمية
ينعكسالأرقام لا تنقلب، فمحارف 0-9 صنفها في bidi هو EN وتُرسم من اليسار إلى اليمين داخل السطر العربي؛ الذي ينقلب هو محاذاة العمود، فاكتب text-align: end لا text-align: right التي تلصق الأرقام بالحافّة التي يبدأ منها النصّ العربي وتبعدها عن رأسها. والفخّ في الإشارة لا في الرقم: محرف U+002D صنفه ES، وإن لم يقع بين رقمين صار محايداً فأخذ اتجاه الفقرة واستقرّ على الطرف المقابل للقيمة التي يخصّها، فتقرأ «3.1%» وناقصها بعيد عنها. لُفّ كل قيمة تحمل إشارة أو نسبة في <bdi> أو في عنصر بـ dir="ltr" حتى تلتصق الإشارة برقمها، وأضف font-variant-numeric: tabular-nums حتى تتحاذى الخانات رأسياً بين الصفوف.
التمرير الأفقي
ينعكسحاوية التمرير تبدأ عند بدايتها المنطقية، أي عند الحافّة اليمنى في العربية، فيظهر أول عمود بلا تدخّل منك. وقراءة هذا الموضع بالكود هي موضع اختلاف المحرّكات: Blink و Gecko تعطيان scrollLeft صفراً عند تلك البداية ثم تنزل القيمة إلى ما دون الصفر، بينما ظلّت WebKit تعطي قيمة موجبة تبدأ من الفرق بين scrollWidth و clientWidth عند الحافّة نفسها، فلا تقارن scrollLeft بصفر لتعرف أين وقف المستخدم، ومرّر إلى scrollBy إزاحة موقّعة بـ getComputedStyle(el).direction === "rtl" ? -1 : 1 لأن الإزاحة فيزيائية لا تعرف اتجاه الصفحة. وأعطِ الحاوية tabindex="0" مع role="region" واسماً مقروءاً عبر aria-labelledby: كروم يجعل حاويات التمرير قابلة للتركيز من تلقائه منذ الإصدار 127، لكن tabindex الصريح هو الجزء الوحيد الذي تضمنه بنفسك، وبدونه لا يملك مستخدم لوحة المفاتيح طريقة لتمرير الجدول.
أسماؤه في الكود
كل سطر هو كلمة مكتبة واحدة عن نفس الشيء. خد السطر اللي بيكلّم مشروعك.
شوف كمان
آخر تحديث · 2026-08-19