0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IE互換モードでテーブルヘッダー固定する

Last updated at Posted at 2024-11-10

【目的】

EdgeのIEモードでも使えるテーブルのヘッダー固定したい
通常であればCSSでposition: sticky;などを使えば固定できるがIEモードに対応していないため工夫する必要がある。

【コード】

HTML

HTML
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="table-container">
        <div class="header-wrapper">
            <table>
                <thead>
                    <tr>
                        <th class="col3">列1</th>
                        <th class="col2">列2</th>
                        <th class="col1">列3</th>
                        <th class="col1">列4</th>
                        <th class="col1">列5</th>
                        <th class="col1">列6</th>
                        <th class="col1">列7</th>
                        <th class="col1">列8</th>
                        <th class="col1">列9</th>
                        <th class="col1">列10</th>
                    </tr>
                </thead>
            </table>
        </div>
        <div class="data-wrapper">
            <table>
                <tbody>
                    <tr>
                        <td class="col3">データ2</td>
                        <td class="col2">データ2</td>
                        <td class="col1">データ3</td>
                        <td class="col1">データ4</td>
                        <td class="col1">データ5</td>
                        <td class="col1">データ6</td>
                        <td class="col1">データ7</td>
                        <td class="col1">データ8</td>
                        <td class="col1">データ9</td>
                        <td class="col1">データ10</td>
                    </tr>
                    
                </tbody>
            </table>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="script.js"></script>
</body>
</html>

テーブルを2つ用意しそれぞれヘッダー用とデータ用にしている。
それぞれクラスを指定することで幅を調整できる。

js

javascript
$(function() {
    var $headerWrapper = $('.header-wrapper');
    var $dataWrapper = $('.data-wrapper');
    var $headerTable = $headerWrapper.find('table');
    var $dataTable = $dataWrapper.find('table');
    
    // スクロールバー幅を計算
    function getScrollbarWidth() {
        var outer = document.createElement('div');
        outer.style.visibility = 'hidden';
        outer.style.overflow = 'scroll';
        document.body.appendChild(outer);
        
        var inner = document.createElement('div');
        outer.appendChild(inner);
        
        var scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
        outer.parentNode.removeChild(outer);
        
        return scrollbarWidth;
    }

    // テーブルの幅を計算して設定
    function setTableWidth() {
        var totalWidth = 0;
        $headerWrapper.find('th').each(function() {
            totalWidth += $(this).outerWidth();
        });
        
        // スクロールバーの幅を考慮
        var scrollbarWidth = getScrollbarWidth();
        
        // ヘッダーテーブルとデータテーブルの幅を設定
        $headerTable.width(totalWidth);
        $dataTable.width(totalWidth);
        
        // データラッパーの幅がテーブル幅より小さい場合、
        // ヘッダーラッパーの右側にスクロールバー幅分のパディングを追加
        if (totalWidth > $dataWrapper.width()) {
            $headerWrapper.css('padding-right', scrollbarWidth);
        } else {
            $headerWrapper.css('padding-right', 0);
        }
    }

    // スクロール同期
    $dataWrapper.on('scroll', function() {
        var scrollLeft = $(this).scrollLeft();
        $headerTable.css('margin-left', -scrollLeft);
    });

    // 初期化
    setTableWidth();

    // ウィンドウリサイズ時
    $(window).on('resize', function() {
        setTableWidth();
    });
});

スクロールバーの幅をgetScrollbarWidthで取得し右端にスクロールしきってもヘッダーとデータ部分でズレが生じないように調整している。

getScrollbarWidthでヘッダーとデータのテーブル幅を合わせている。

CSS

CSS
.table-container {
    width: 600px;
    height: 400px;
    position: relative;
    overflow: hidden;
}

.header-wrapper {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 31px; /* ヘッダーの高さを固定 */
    overflow:hidden;
}

.data-wrapper {
    position: absolute;
    top: 31px;
    left: 0;
    right: 0;
    bottom: 0;
    overflow: auto;
}

/* テーブル設定 */
.header-wrapper table,
.data-wrapper table {
    table-layout: fixed;
    border-collapse: collapse;
    border-spacing: 0;
}

/* スクロールバー幅調整用の要素 */
.scroll-width-dummy {
    position: absolute;
    top: 0;
    left: 0;
    width: 100px;
    height: 100px;
    overflow: scroll;
    visibility: hidden;
}

/* セル設定 */
.header-wrapper th,
.data-wrapper td {
    padding: 5px;
    text-align: left;
    overflow: hidden;
    white-space: nowrap;
    border: 1px solid #000;
}

.header-wrapper th {
    background-color: #a3ccee;
    font-weight: bold;
}

/* 列幅設定 */
.header-wrapper .col1,
.data-wrapper .col1 {
    width: 100px;
    overflow-x: auto;
    -ms-overflow-style: -ms-autohiding-scrollbar;
}

.header-wrapper .col2,
.data-wrapper .col2 {
    width: 400px;
    overflow-x: auto;
    -ms-overflow-style: -ms-autohiding-scrollbar;
}

.header-wrapper .col3,
.data-wrapper .col3 {
    width: 30px;
    overflow-x: auto;
    -ms-overflow-style: -ms-autohiding-scrollbar;
}

各セルの横幅が設定値を超えた場合スクロールバーを表示できるように-ms-overflow-style: -ms-autohiding-scrollbar;を使っている。
これでoverflow: auto;のようにスクロールが必要なセルのみスクロールバーが表示される。

おまけ

IE5

HTML

HTML
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="table-container">
        <div id="header-wrapper" class="header-wrapper">
            <table>
                <thead>
                    <tr>
                        <th class="col1">列1</th>
                        <th class="col2">列2</th>
                        <th class="col3">列3</th>
                        <th class="col4">列4</th>
                        <th class="col5">列5</th>
                        <th class="col6">列6</th>
                        <th class="col7">列7</th>
                        <th class="col8">列8</th>
                        <th class="col9">列9</th>
                        <th class="col10">列10</th>
                    </tr>
                </thead>
            </table>
        </div>
        <div id="data-wrapper" class="data-wrapper">
            <table>
                <tbody>
                    <tr>
                        <td class="col1">データ1</td>
                          <td class="col2">データ2</td>
                        <td class="col3">データ3</td>
                        <td class="col4">データ4</td>
                        <td class="col5">データ5</td>
                        <td class="col6">データ6</td>
                        <td class="col7">データ7</td>
                        <td class="col8">データ8</td>
                        <td class="col9">データ9</td>
                        <td class="col10">データ10</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
    <script src="script.js"></script>
</body>
</html>

js

javascript
window.onload = function() {
    var headerWrapper = document.getElementById('header-wrapper');
    var dataWrapper = document.getElementById('data-wrapper');
    var headerTable = headerWrapper.getElementsByTagName('table')[0];
    var dataTable = dataWrapper.getElementsByTagName('table')[0];

    function setTableWidth() {
        var totalWidth = 0;
        var thElements = headerTable.getElementsByTagName('th');
        for (var i = 0; i < thElements.length; i++) {
            totalWidth += thElements[i].offsetWidth;
        }
        
        headerTable.style.width = totalWidth + 'px';
        dataTable.style.width = totalWidth + 'px';
        
        // ヘッダーのpaddingRightを設定
        var scrollbarWidth = getScrollbarWidth();
        if (totalWidth > dataWrapper.clientWidth) {
            headerWrapper.style.paddingRight = scrollbarWidth + 'px';
        } else {
            headerWrapper.style.paddingRight = '0';
        }
    }
    

    dataWrapper.onscroll = function() {
        headerTable.style.marginLeft = (-dataWrapper.scrollLeft) + 'px';
    };

    setTableWidth();

    window.onresize = function() {
        setTableWidth();
    };
};

CSS

CSS
.table-container {
    width: 600px;
    height: 400px;
    position: relative;
    overflow: hidden; /* 外側のコンテナは隠す */
}

.header-wrapper {
    position: absolute; /* ヘッダーを固定 */
    top: 31px;
    left: 0;
    right: 0;
    height: 31px;
    z-index: 10; /* ヘッダーを前面に表示 */
    background-color: #a3ccee; /* ヘッダーの背景色を指定 */
}

.data-wrapper {
    position: absolute;
    top: 60px; /* ヘッダーの下に配置 */
    left: 0;
    right: 0;
    bottom: 0;
    overflow-y: auto; /* 縦スクロール */
    overflow-x: auto; /* 横スクロールを有効にする */
    height: 350px; /* 明示的な高さを設定 */
    width: 100%; /* 幅を100%に設定 */
}


/* テーブル設定 */
.header-wrapper table,
.data-wrapper table {
    table-layout: fixed;
    border-collapse: collapse;
    width: 100%; /* 幅を100%に設定 */
}

/* セル設定 */
.header-wrapper th,
.data-wrapper td {
    padding: 5px;
    text-align: left;
    overflow: hidden;
    white-space: nowrap;
    border: 1px solid #000;
}

.header-wrapper th {
    font-weight: bold;
}

/* 列幅設定 */
.header-wrapper .col1,
.data-wrapper .col1 {
    width: 100px;
}

.header-wrapper .col2,
.data-wrapper .col2 {
    width: 400px;
}

.header-wrapper .col3,
.data-wrapper .col3 {
    width: 50px;
}

.header-wrapper .col4,
.data-wrapper .col4 {
    width: 70px;
}

.header-wrapper .col5,
.data-wrapper .col5 {
    width: 100px;
}

.header-wrapper .col6,
.data-wrapper .col6 {
    width: 100px;
}

.header-wrapper .col7,
.data-wrapper .col7 {
    width: 100px;
}

.header-wrapper .col8,
.data-wrapper .col8 {
    width: 100px;
}

.header-wrapper .col9,
.data-wrapper .col9 {
    width: 100px;
}

.header-wrapper .col10,
.data-wrapper .col10 {
    width: 100px;
}

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?