یه جدول قابل‌فهم برای همه، نه فقط برای چشم

تو درس‌های قبل این فصل، تک‌تک تگ‌های جدول رو دیدیم: table، tr، td، th، thead، tbody، tfoot، caption، colgroup و col. تو این درس می‌خوایم همه‌ی این‌ها رو از یه زاویه‌ی دیگه مرور کنیم: از دید کاربری که جدول رو نمی‌بینه، بلکه می‌شنوه. این درس یه‌جورایی جمع‌بندی نکات دسترسی‌پذیری‌ایه که تو درس‌های قبل پراکنده بهشون اشاره کردیم.

چالش اصلی: جدول برای صفحه‌خوان چیه؟

وقتی یه کاربر بینا به یه جدول نگاه می‌کنه، در کسری از ثانیه می‌فهمه چند تا ستون و سطر داره، کدوم سلول به کدوم عنوان مربوطه، و رابطه‌ی بین داده‌ها چیه؛ همه‌ی این‌ها رو با یه نگاه کلی می‌گیره. اما یه صفحه‌خوان نمی‌تونه «یه نگاه کلی» بندازه؛ باید سلول به سلول، خطی‌خطی جلو بره. به همین دلیل، ساختار درست و معنایی جدول برای این کاربران حیاتیه؛ بدون ساختار درست، جدول برای صفحه‌خوان به یه دسته عدد و متن بی‌ربط تبدیل می‌شه.

مرور نکته‌ی اول: استفاده‌ی درست از th به‌جای td

<!-- اشتباه: عنوان‌ها با td نوشته شدن -->
<tr>
  <td>محصول</td>
  <td>قیمت</td>
</tr>

<!-- درست -->
<tr>
  <th>محصول</th>
  <th>قیمت</th>
</tr>

همون‌طور که تو درس ۶-۱ گفتیم، صفحه‌خوان فقط از طریق تگ th می‌فهمه یه سلول نقش عنوان داره؛ اگه از td استفاده کنی، حتی با وجود ظاهر بصری پررنگ، صفحه‌خوان هیچ تفاوتی بین اون و بقیه‌ی سلول‌های داده حس نمی‌کنه.

مرور نکته‌ی دوم: ویژگی scope

<tr>
  <th scope="col">ماه</th>
  <th scope="col">فروش</th>
</tr>

ویژگی scope دقیقاً مشخص می‌کنه یه سربرگ، مربوط به یه ستونه یا یه سطر. تو جدول‌های ساده‌ای که فقط یه سطر سربرگ دارن (مثل اکثر مثال‌های این فصل)، صفحه‌خوان‌های مدرن معمولاً می‌تونن این رابطه رو حدس بزنن؛ اما تو جدول‌های پیچیده‌تر (با چند سطح سربرگ یا سلول‌های ادغام‌شده)، نوشتن صریح scope عملاً ضروریه.

مرور نکته‌ی سوم: caption به‌جای عنوان جدا

<table>
  <caption>لیست قیمت محصولات فروشگاه</caption>
  <!-- ... -->
</table>

همون‌طور که تو درس ۶-۴ دیدیم، caption بلافاصله پس از ورود صفحه‌خوان به جدول خونده می‌شه؛ این کار به کاربر نابینا کمک می‌کنه قبل از شروع شنیدن داده‌ها، بفهمه اصلاً موضوع این جدول چیه.

نکته‌ی جدید: پیچیدگی جدول‌های با colspan و rowspan

تو درس ۶-۳ دیدیم که colspan و rowspan امکان ادغام سلول‌ها رو می‌دن. این ویژگی از نظر بصری خیلی مفیده، اما برای صفحه‌خوان چالش‌برانگیزتره؛ چون رابطه‌ی بین یه سلول ادغام‌شده و سلول‌های اطرافش، پیچیده‌تر از یه جدول ساده‌ی شبکه‌ایه. به همین خاطر، تو جدول‌های با ادغام سلول، رعایت دقیق scope و حتی گاهی استفاده از ویژگی‌های پیشرفته‌تر (مثل headers که ارتباط دقیق‌تری بین هر td و th مرتبطش برقرار می‌کنه) اهمیت بیشتری پیدا می‌کنه.

<table>
  <tr>
    <th id="jan">فروردین</th>
    <th id="feb">اردیبهشت</th>
  </tr>
  <tr>
    <td headers="jan">۱۲۰</td>
    <td headers="feb">۱۵۰</td>
  </tr>
</table>

تو این مثال، به‌جای scope، از ترکیب id روی th و headers روی td استفاده شده؛ هر td دقیقاً مشخص می‌کنه به کدوم id از th ها مرتبطه. این روش برای جدول‌های خیلی پیچیده که scope به‌تنهایی کافی نیست (مثلاً وقتی یه سلول به چند سربرگ مختلف هم‌زمان مرتبطه)، دقت بیشتری فراهم می‌کنه.

نکته‌ی مهم: هیچ‌وقت از جدول برای چیدمان صفحه استفاده نکن

تو درس ۶-۱ به این نکته اشاره کردیم، اما از دید دسترسی‌پذیری ارزش تکرار داره: استفاده از table برای چیدمان کلی صفحه (مثل قرار دادن منو و محتوای اصلی کنار هم) یه روش کاملاً قدیمی و مضره. وقتی صفحه‌خوان به یه «جدول» می‌رسه، انتظار داره با داده‌های جدولی واقعی مواجه بشه (مثل قیمت، تاریخ، آمار)؛ اگه به‌جاش یه چیدمان صفحه رو با عنوان‌های عجیب و بی‌معنی سلول به سلول بشنوه، کاملاً گیج می‌شه. برای چیدمان صفحه، همیشه باید از CSS استفاده کرد.

جدول‌های خیلی بزرگ و طولانی

برای جدول‌هایی که خیلی طولانی هستن (مثلاً صدها سطر)، کاربر صفحه‌خوان معمولاً یه قابلیت داره که بتونه سریع بین سربرگ‌های ستون‌ها جابه‌جا بشه یا مستقیم به یه سطر خاص بپره، به‌جای اینکه مجبور باشه از اول تا آخر جدول رو خطی گوش کنه. این قابلیت فقط زمانی درست کار می‌کنه که ساختار thead/tbody (درس ۶-۲) و th/scope به‌درستی رعایت شده باشن.

یه چک‌لیست کامل برای جدول‌های قابل‌دسترس

  • آیا از th برای تمام عنوان‌های ستون یا سطر استفاده شده، نه td؟
  • آیا ویژگی scope (یا در موارد پیچیده، id/headers) برای هر th مشخص شده؟
  • آیا جدول یه caption گویا داره که موضوع کلی رو معرفی می‌کنه؟
  • آیا از table فقط برای داده‌های واقعاً جدولی استفاده شده، نه چیدمان صفحه؟
  • آیا سلول‌های ادغام‌شده (colspan/rowspan) به‌شکلی نوشته شدن که رابطه‌شون با بقیه‌ی جدول گنگ نباشه؟

یه مثال کامل و کاملاً قابل‌دسترس

<table>
  <caption>نمرات پایانی دانش‌آموزان ترم جاری</caption>
  <thead>
    <tr>
      <th scope="col">نام دانش‌آموز</th>
      <th scope="col">ریاضی</th>
      <th scope="col">علوم</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">علی محمدی</th>
      <td>۱۸</td>
      <td>۱۹</td>
    </tr>
    <tr>
      <th scope="row">سارا احمدی</th>
      <td>۱۷</td>
      <td>۲۰</td>
    </tr>
  </tbody>
</table>

تو این مثال، هم caption داریم، هم thead و tbody جدا شدن، هم عنوان ستون‌ها با scope="col" مشخص شدن، هم عنوان هر سطر (اسم دانش‌آموز) با scope="row" مشخص شده. یه صفحه‌خوان می‌تونه با شنیدن هر عدد، دقیقاً بفهمه این عدد مربوط به کدوم دانش‌آموز و کدوم درسه.

چند اشتباه رایج

  • استفاده از جدول برای چیدمان کلی صفحه به‌جای داده‌ی واقعی جدولی.
  • ساختن جدول‌های بزرگ بدون caption، thead/tbody یا scope مشخص.
  • تکیه‌ی بیش‌ازحد به ظاهر بصری (مثل پررنگی th) و فراموش‌کردن اینکه صفحه‌خوان فقط به ساختار معنایی HTML توجه می‌کنه، نه ظاهر نهایی صفحه.

بهترین روش‌ها

  • همیشه چک‌لیست بالا رو قبل از انتشار نهایی هر جدول مرور کن.
  • تو جدول‌های پیچیده با ادغام سلول، از ترکیب id و headers استفاده کن، نه فقط scope ساده.
  • هیچ‌وقت table رو برای چیدمان صفحه استفاده نکن؛ فقط برای داده‌ی واقعاً جدولی.

نکته‌ی سئو

جدول‌های ساختاریافته و قابل‌دسترس، غیر از کمک به کاربران کم‌بینا، به موتورهای جستجو هم کمک می‌کنند داده‌های جدولی را دقیق‌تر تحلیل کنند؛ این دو هدف (دسترسی‌پذیری و سئو) در جدول‌ها معمولاً کاملاً هم‌راستا هستند و یک ساختار خوب، هر دو را همزمان تأمین می‌کند.

نکته‌ی دسترسی‌پذیری

رعایت کامل اصول این درس، تفاوت میان یک جدول قابل‌استفاده و یک جدول کاملاً گیج‌کننده را برای میلیون‌ها کاربر صفحه‌خوان در سراسر دنیا رقم می‌زند؛ این موضوع را نباید یک جزئیات فنی کم‌اهمیت در نظر گرفت.

جمع‌بندی

دسترسی‌پذیری جدول‌ها حاصل جمع تمام نکاتی است که در این فصل دیدیم: استفاده‌ی درست از th و scope، وجود caption گویا، تفکیک thead/tbody/tfoot، و پرهیز از استفاده‌ی نادرست از table برای چیدمان صفحه. برای جدول‌های پیچیده با سلول‌های ادغام‌شده، ترکیب id و headers دقت بیشتری نسبت به scope ساده فراهم می‌کند.