2
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?

JavaScriptAdvent Calendar 2024

Day 19

【簡単!】リサイズ可能な 2 分割ビューレイアウトを JavaScript で実装

Posted at

はじめに

本記事では、以下のようなリサイズ可能な 2 分割ビューレイアウトJavaScript で実装する方法を紹介します。

demo

左側のエリアと右側のエリアの間に配置されたボーダーをドラッグすることで、エリアの幅を動的に調整できるレイアウトを実現しています。

実装

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-sideflex: 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>

動作の流れ

  1. 初期設定
    ページ読み込み時に、left-side の幅を画面の 50% に設定します。
    ボーダーにドラッグの開始イベント(pointerdown)を設定します。
  2. ドラッグ中の処理
    マウスカーソルの x 座標を取得し、それに応じて left-side の幅を更新します。
    左右エリアの最小幅を 150px に制限することで、エリアが極端に小さくなるのを防ぎます。
  3. ドラッグ終了時の処理
    マウスボタンを離したときやカーソルが画面外に移動したときに、ドラッグ状態(isScrubbing)を終了します。

おまけ

左右のエリアに文字列がある場合、ドラッグ時に文字を選択してしまうことがあります。user-selectnone にすることで防ぐことができます。

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';
};
2
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
2
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?