table要素のcss操作が難しい

2024/08/24に公開

table要素をカスタマイズしたいことがあったが、CSSが思うようにハマらなかったのでそこで得た知見の備忘録。

tableを画面幅に応じて横スクロールさせる

  1. セルは親要素の幅に応じて自動伸縮するので、min-widthtext-wrap: nowrapを使ってセルが小さくなりすぎないようにする
  2. table要素をラッピングするdiv要素を作りoverflow-x: autoを指定
{/* overflowを入れる */}
<div className="overflow-x-auto">
  <table>
    <thead>
      {Array.from({length: 20}).map((_, i) => (
        {/* text-wrap: nowrapやmin-widthを入れて縮まないようにする */}
        <th key={i} className="text-nowrap">{ i + 1 }列目</th>
      ))}
    </thead>
  </table
<div>

tbody部分だけを縦スクロールさせる

  1. table要素には直接heightを指定できないため、ラッピング要素に固定値のheightを指定する
  2. ラッピング要素にoverflow: autoを適用
  3. thead要素にposition: stickytop: 0pxを指定する
{/* heightとoverflow: autoを入れる */}
<div className="h-[500px] overflow-auto">
  <table>
    {/* position: stickyとtop: 0px を入れる */}
    <thead className="sticky top-0">
      {Array.from({length: 20}).map((_, i) => (
        <th>{ i + 1 }列目</th>
      ))}
    </thead>
  </table
<div>

theadとtbodyにスペースを開ける

theadにmarginを直接指定できないが、下記の方法で対応できる。

擬似要素を使う

theadに擬似要素でmargin-bottomをつける

<div>
  <table>
    {/* 擬似要素でmargin-bottomを入れる */}
    <thead className="after:block after:content-[''] after:mb-10">
      <tr>
        {Array.from({ length: 20 }).map((_, i) => (
          <th key={i}>{ i + 1 }列目</th>
        ))}
      </tr>
    </thead>

    <tbody>
      {Array.from({ length: 200 }).map((_, i) => (
        <tr key={i}>
          {Array.from({ length: 20 }).map((_, i) => (
            <td key={i}>🥺🥺</td>
          ))}
        </tr>
      ))}
    </tbody>
  </table>
</div>

空行を入れる

<div>
  <table>
    <thead>
      <tr>
        {Array.from({ length: 20 }).map((_, i) => (
          <th key={i}>{ i + 1 }列目</th>
        ))}
      </tr>
    </thead>

    {/* 空のtrを入れる */}
    <tr className="h-10"></tr>

    <tbody>
      {Array.from({ length: 200 }).map((_, i) => (
        <tr key={i}>
          {Array.from({ length: 20 }).map((_, i) => (
            <td key={i}>🥺🥺</td>
          ))}
        </tr>
      ))}
    </tbody>
  </table>
</div>

行の特定の列だけを縦に結合する

  1. 縦結合したtdを1つのtrにする
  2. 1で結合した行分だけtrを作る
  3. 結合したtdのrowSapnに一行としたいtrの数を入れる
<table>
  <thead>
    <tr>
      {Array.from({ length: 3 }).map((_, i) => (
        <th key={i}>{ i + 1 }列目</th>
      ))}
    </tr>
  </thead>

  <tbody>
    {/* 1列目の縦2行を結合 */}
    <tr>
      {/* 1行に存在するtrの数をrowSpanに入れる */}
      <td rowSpan={3}>
        1列目
      </td>
    </tr>
    <tr>
      <td>2列目-上段</td>
      <td>2列目-下段</td>
    </tr>
    <tr>
      <td>3列目-上段</td>
      <td>3列目-下段</td>
    </tr>
  </tbody>
</table>

Discussion