रिस्पॉन्सिव टेबल

बड़ी डेटा टेबल अक्सर छोटी स्क्रीन पर पढ़ने लायक नहीं रह जाती हैं. ऐसा इसलिए होता है, क्योंकि कॉलम ओवरफ़्लो हो जाते हैं या इतने छोटे हो जाते हैं कि उन्हें पढ़ा नहीं जा सकता. इस गाइड में बताया गया है कि स्क्रोल करते समय हेडर को दिखाने के लिए, स्टिकी पोज़िशनिंग का इस्तेमाल कैसे करें. साथ ही, जगह कम होने पर टेबल को मोबाइल-फ़्रेंडली "स्टैक किए गए" लेआउट में बदलने का तरीका भी बताया गया है.

रिस्पॉन्सिव टेबल का मुख्य काम, डेटा सेल और उनके हेडर के बीच के संबंध को बनाए रखना है.

  1. सिमैंटिक फ़ाउंडेशन: <thead>, <tbody>, और <th> एलिमेंट के साथ स्टैंडर्ड <table> एलिमेंट इस्तेमाल करें.
  2. स्टिकी कॉन्टेक्स्ट: कॉलम हेडर और लाइन हेडर, दोनों पर position: sticky लागू करें. इससे यह पक्का होता है कि उपयोगकर्ता किसी भी दिशा में कितना भी स्क्रोल करे, उसे डेटा का संदर्भ हमेशा दिखता रहे.
  3. अडैप्टिव ट्रांसफ़ॉर्मेशन: @media क्वेरी के बजाय @container क्वेरी का इस्तेमाल करें. इससे टेबल, पूरे व्यूपोर्ट के बजाय अपनी चौड़ाई के हिसाब से अडजस्ट हो जाती है. उदाहरण के लिए, जब टेबल को साइडबार या छोटे डैशबोर्ड विजेट में रखा जाता है.
  4. लेबल इंजेक्शन: स्टैक किए गए लेआउट में, <thead> को छिपा दिया जाता है. साथ ही, ::before स्यूडो-एलिमेंट और सीएसएस वैरिएबल का इस्तेमाल करके, हर सेल में ऐक्सेस किए जा सकने वाले हेडर इंजेक्ट किए जाते हैं.

लागू करने के चरण

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. स्टिकी हेडर कॉन्फ़िगर करना

स्क्रोल करने की सुविधा चालू करें और हेडर को स्टिकी बनाएं. स्टैकिंग ऑर्डर को मैनेज करने के लिए, लॉजिकल प्रॉपर्टी और साफ़ तौर पर ज़ेड-इंडेक्स वैल्यू का इस्तेमाल करें.

.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) ": ";
  }
}