<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Layout with Fixed Horizontal Scroll</title>
<style>
body {
margin: 0;
font-family: sans-serif;
}
/* ============================
1. 上部ヘッダー(sticky)
============================*/
header {
position: sticky;
top: 0;
height: 100px;
background: #333;
color: #fff;
display: flex;
align-items: center;
padding-left: 20px;
z-index: 1000;
}
/* ============================
2. 左ナビ + コンテンツ
============================*/
.layout {
display: flex;
height: calc(100vh - 100px);
}
.side-nav {
width: 200px;
background: #f4f4f4;
border-right: 1px solid #ddd;
padding: 20px;
box-sizing: border-box;
position: sticky;
top: 100px; /* ヘッダー分 */
height: calc(100vh - 100px);
}
.content {
flex: 1;
position: relative;
padding: 20px;
box-sizing: border-box;
overflow-y: auto;
}
/* ============================
3. コンテンツ内テーブル
============================*/
.table-area {
position: relative;
padding-bottom: 20px; /* fake scrollbar 分 */
}
/* 実スクロール部分 */
.real-scroll {
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
border: 1px solid #ccc;
}
/* コンテンツ内で固定される横スクロールバー */
.fake-scroll {
position: sticky;
bottom: -20px;
left: 0;
right: 0;
height: 16px;
overflow-x: auto;
overflow-y: hidden;
background: #fff;
transition: opacity 0.25s ease;
}
.fake-scroll.hide {
opacity: 0;
pointer-events: none;
}
.fake-scroll > div {
height: 1px;
width: 1px; /* JSで同期 */
}
table {
border-collapse: collapse;
}
td, th {
border: 1px solid #ccc;
padding: 8px;
white-space: nowrap;
}
</style>
</head>
<body>
<header>
HEADER(100px sticky)
</header>
<div class="layout">
<nav class="side-nav">
左ナビ(固定)
</nav>
<main class="content">
<h2>コンテンツ</h2>
<div class="table-area">
<div class="real-scroll" id="real">
<table id="big-table">
<tbody>
<script>
for (let r = 0; r < 30; r++) {
document.write("<tr>");
for (let c = 0; c < 30; c++) {
document.write(`<td>R${r+1}C${c+1}</td>`);
}
document.write("</tr>");
}
</script>
</tbody>
</table>
</div>
<div class="fake-scroll" id="fake"><div></div></div>
</div>
</main>
</div>
<script>
const real = document.getElementById("real");
const fake = document.getElementById("fake");
const fakeInner = fake.firstElementChild;
function syncWidth() {
fakeInner.style.width = real.scrollWidth + "px";
}
syncWidth();
window.addEventListener("resize", syncWidth);
// スクロール同期
fake.addEventListener("scroll", () => {
real.scrollLeft = fake.scrollLeft;
});
real.addEventListener("scroll", () => {
fake.scrollLeft = real.scrollLeft;
});
const content = document.querySelector('.content');
const fakeBar = document.querySelector('.fake-scroll');
content.addEventListener('scroll', () => {
const scrollBottom = content.scrollTop + content.clientHeight;
const contentHeight = content.scrollHeight;
if(contentHeight - scrollBottom < 40) {
fakeBar.classList.add('hide');
} else {
fakeBar.classList.remove('hide')
}
})
</script>
</body>
</html>
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme