【目的】
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;
}