Web production note

 【更新日 :

【JavaScript】スマホで画面に収まらないtableを横スクロールさせる

Category:
JavaScript

スマホで画面に収まらないtableを横スクロールに切り替えるJavaScriptサンプルです。

簡易的なものならCSSのみでも可能ですが、CMSでtableタグのみ動的に挿入される場合や、
tableごとに本来の幅でスクロールさせたい場合などに有効だと思います。

codepen

See the Pen Table formatting: horizontal scrolling on mobile Vanilla JS by web_nak (@web_walking_nak) on CodePen.

HTML・CSS

table要素が画面外へはみ出ても問題ないよう
エリア全体を覆う要素に overflow:hidden; を設定してください。

JavaScript

tableタグにclass is-no-scroll が付与されている場合は本処理の対象外になります。

//表組み スクロール切り替え
const tables = document.querySelectorAll('table');
if(tables.length > 0) {
  //スクロール処理を発火させるブレイクポイント
  const breakPoint = 767;
  //tableごとの処理
  tables.forEach((table) => {
    //tableに除外class "is-no-scroll" が付与されている場合は処理しない
    if(!table.classList.contains('is-no-scroll')) {
      //スクロール用div要素作成
      const inner = document.createElement('div');
      inner.classList.add('table-inner');
      const wrap = document.createElement('div');
      wrap.classList.add('table-wrap');

      //スクロール用div要素挿入
      table.parentNode.insertBefore(inner, table);
      inner.appendChild(table);
      inner.parentNode.insertBefore(wrap, inner);
      wrap.appendChild(inner);

      //スクロール発火フラグ
      let scrollFlg = false;
      //table widthの設定値を取得
      table.baseWidth = table.style.width;

      //スクロール関数
      const tableScroll = () => {
        //スクロールが発火していたら設定をリセット
        if(scrollFlg) {
          inner.removeAttribute('style');
          wrap.removeAttribute('style');
          table.style.width = table.baseWidth;
          scrollFlg = false;
        }
        //ブレイクポイント以下の場合のみ処理
        const winWidth = window.innerWidth;
        if(winWidth > breakPoint) {
          return;
        }

        //tableのベース幅を取得
        let tableWidth = table.offsetWidth;
        const wrapWidth = wrap.offsetWidth;

        //tableの幅がwrapの幅以上の場合は本来の幅をチェック
        if(wrapWidth <= tableWidth) {
          //tableに100%以外のwidth指定が入っている場合
          if(table.baseWidth !== '' && table.baseWidth !== '100%') {
            tableWidth = parseFloat(table.baseWidth) + 1;

          } else {
            table.baseWidth = table.style.width;
            table.style.width = 'auto';
            inner.style.width = '9999px';
            tableWidth = table.offsetWidth;
            inner.style.width = '';
            table.style.width = table.baseWidth;
            console.log(tableWidth,table.baseWidth);
          }
        }

        //tableがwrapの幅を超えている場合スクロール発火
        if(wrapWidth < tableWidth) {
          //wrapリセット
          wrap.removeAttribute('style');
          wrap.style.overflowX = 'hidden';

          //wrapの左右の余白を取得
          const wrapLeftMargin = wrap.getBoundingClientRect().left;
          const wrapRightMargin = winWidth - parseFloat(wrap.getBoundingClientRect().right);

          //wrapを画面幅いっぱいに広げる
          wrap.style.overflowX = 'scroll';
          wrap.style.marginLeft = '-' + wrapLeftMargin + 'px';
          wrap.style.marginRight = '-' + wrapRightMargin + 'px';

          //innerにtable本来の幅 + 左右余白を設定
          inner.style.boxSizing = 'content-box';
          inner.style.paddingLeft = wrapLeftMargin + 'px';
          inner.style.paddingRight = wrapRightMargin + 'px';
          inner.style.width = (tableWidth + 1) + 'px'; //少数点分の繰り上げ

          //スクロール発火フラグセット
          scrollFlg = true;
        }
      }

      //スクロール関数呼び出し
      tableScroll();

      //リサイズイベント
      let lastInnerWidth = window.innerWidth;
      window.addEventListener('resize', function() {
        //画面の横サイズが変わった時のみ発火
        if (lastInnerWidth !== window.innerWidth) {
          //スクロール関数呼び出し
          tableScroll();
          //横幅を保存
          lastInnerWidth = window.innerWidth;
        }
      });
    }
  });
}