はじめに
本記事では、以下のようなリサイズ可能な 2 分割ビューレイアウトを JavaScript
で実装する方法を紹介します。
左側のエリアと右側のエリアの間に配置されたボーダーをドラッグすることで、エリアの幅を動的に調整できるレイアウトを実現しています。
実装
HTML
HTML
では、コンテナ要素(container
)の中に3つの子要素を配置しています。
<div class="container" id="container">
<div id="left-side" class="left-side"></div>
<div id="border" class="border"></div>
<div id="right-side" class="right-side"></div>
</div>
-
left-side
: 左側のエリア。 -
border
: 左右のカラムを分けるボーダー。ドラッグ操作で使用します。 -
right-side
: 右側のエリア。
CSS
<style>
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
position: relative;
display: flex;
width: 100vw;
}
.container .left-side {
position: relative;
height: 100vh;
overflow-y: scroll;
background-color: #fbfbfb;
}
.container .right-side {
flex: 1;
position: relative;
height: 100vh;
overflow-y: scroll;
background-color: #fff;
}
.container .border {
width: 8px;
margin: 0px -4px;
overflow: hidden;
position: relative;
z-index: 50;
cursor: col-resize;
}
.container .border::after {
content: "";
display: block;
position: absolute;
top: 0px;
left: 3px;
bottom: 0px;
width: 2px;
background: #f5f5f5;
}
</style>
ポイント
-
flex
レイアウト-
container
をフレックスボックスとして設定し、左右のエリアが横に並ぶようにしています。 -
right-side
にflex: 1;
を設定することで、右側のエリアが残りの幅を柔軟に占有します。
-
-
border
のスタイリング- 幅
8px
のドラッグ可能なエリアを作成します。 - カーソルを
col-resize
に設定して、ドラッグ可能であることを示します。
- 幅
JavaScript
JavaScript
では、ボーダーのドラッグ操作に応じて left-side
の幅を動的に変更します。
<script>
let isScrubbing = false;
let mousePosition = { x: null };
const sectionMinWidth = 150 // px
const leftSide = document.getElementById('left-side');
leftSide.style.width = '50%';
document.getElementById('border').addEventListener('pointerdown', () => isScrubbing = true);
document.addEventListener('pointermove', handlePointerMove);
document.addEventListener('pointerup', () => isScrubbing = false);
document.addEventListener('pointerleave', () => isScrubbing = false);
function handlePointerMove(e) {
if(!isScrubbing) return;
mousePosition = { x: e.pageX };
if(
!mousePosition.x ||
mousePosition.x > (window.innerWidth - sectionMinWidth) ||
mousePosition.x < sectionMinWidth
) return;
leftSide.style.width = mousePosition.x + 'px';
}
</script>
動作の流れ
-
初期設定
ページ読み込み時に、left-side
の幅を画面の50%
に設定します。
ボーダーにドラッグの開始イベント(pointerdown
)を設定します。 -
ドラッグ中の処理
マウスカーソルのx
座標を取得し、それに応じてleft-side
の幅を更新します。
左右エリアの最小幅を150px
に制限することで、エリアが極端に小さくなるのを防ぎます。 -
ドラッグ終了時の処理
マウスボタンを離したときやカーソルが画面外に移動したときに、ドラッグ状態(isScrubbing
)を終了します。
おまけ
左右のエリアに文字列がある場合、ドラッグ時に文字を選択してしまうことがあります。user-select
を none
にすることで防ぐことができます。
const container = document.getElementById('container');
document.getElementById('border').addEventListener('pointerdown', handlePointerDown);
function handlePointerDown(e) {
isScrubbing = true;
container.style.userSelect = 'none';
container.style.MozUserSelect = 'none';
container.style.WebkitUserSelect = 'none';
container.style.msUserSelect = 'none';
};
document.addEventListener('pointerup', handlePointerEnd);
document.addEventListener('pointerleave', handlePointerEnd);
function handlePointerEnd(e) {
isScrubbing = false;
container.style.userSelect = 'unset';
container.style.MozUserSelect = 'unset';
container.style.WebkitUserSelect = 'unset';
container.style.msUserSelect = 'unset';
};