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

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

## 【コード】
### HTML
<details open><summary>HTML</summary>

```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>
```
</details>

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

### js
<details open><summary>javascript</summary>

```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();
    });
});
```
</details>

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

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

### CSS
<details open><summary>CSS</summary>

```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;
}
```

</details>

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

# おまけ
## IE5
### HTML
<details><summary>HTML</summary>

```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>
```
</details>

### js
<details><summary>javascript</summary>

```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();
    };
};
```
</details>

### CSS
<details><summary>CSS</summary>

```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;
}

```
</details>