要素の幅や高さを指定する際に、vwやvhを使うと、ウィンドウサイズの変更に合わせて要素のサイズを自動で変更してくれるため、とても使い勝手が良い。
しかし、少し極端な操作をすると、vwやvhだけでは、上手く表示されない場合もある。
そんな極端なウィンドウサイズ変更操作を考慮しなくてもいい気がするが、場合によっては求められることもある。
ウィンドウサイズの変更を検知し、ウィンドウサイズと固定要素サイズから動的な要素のサイズを変更する。
動的な要素の作成(HTML)
<!-- サイズが静的な要素 -->
<ul class="stable1" id="stable1">
<li><button type="button" >ボタン1</button></li>
<li><button type="button" >ボタン2</button></li>
</ul>
<table class="stable2" id="stable2">
<thead>
<tr><th>項目1</th><th>項目2</th></tr>
</thead>
<tbody>
<tr><td>値1</td><td>値2</td><tr>
</tbody>
</table>
<!-- サイズが動的な要素 -->
<div class="active" id="active">
<img src="sample.png">
</div>
リストとテーブルはサイズが基本的に固定で、画像をウィンドウサイズに合わせて大きさを変更する。
CSSは以下のように設定する。
動的な要素の作成(CSS)
.active{
max-width: 60vw;
max-height: 65vh;
min-width: 300px;
min-height: 150px;
overflow: scroll;
}
リストやボタン、テーブルには特にCSSは設定しない。
max-widthとmax-heightを設定し、overflowにscrollを設定すると、画像が最大サイズ以上の場合、スクロールバーが出現する。
vwとvhでもウィンドウサイズの変更に合わせて要素の大きさを変更してくれるが、今回はウィンドウサイズの変更を検知して、JavaScriptでmax-widthとmax-heightを変更していく。
ウィンドウサイズ変更の検知
ウィンドウサイズ変更のイベントハンドラーには、resizeを使用する。
resizeはウィンドウサイズを変更している間、どんどんイベントが発生する。
実際に要素のサイズを変更する必要があるのは、ウィンドウサイズの変更完了後であることが多いため、ウィンドウサイズの変更中には、なるべくイベントが発生しないようにする。
ウィンドウサイズの変更中や変更完了後を区別して検知するイベントハンドラーはないため、setTimeoutを用いて行う。
処理は以下の通り。
var resizeFlg; //setTimeoutの待機中かを判定するフラグ
function windowResizeFunc(){
//resizeFlgに値が設定されている場合は、待ち時間中なのでリセットする
if (resizeFlg !== false) {
clearTimeout(resizeFlg);
}
//300ms待機後にリサイズ処理を実施する
resizeFlg = setTimeout( function() {
resizeElement(); //リサイズを実施する処理
}, 300);
window.addEventListener("resize", windowResizeFunc);
300ms秒間、ウィンドウサイズの変更がされない場合、resizeElement関数を呼び出して処理を行う。
各要素サイズの取得と変更
ウィンドウサイズと固定要素のサイズを取得し、動的な要素のサイズを設定する。
ウィンドウサイズの取得
ウィンドウサイズの取得方法は以下の通り。
const windowWidth = document.documentElement.clientWidth;
const windowHeight = document.documentElement.clientHeight;
ウィンドウサイズの取得には、欲しい個所によっていくつかの取得方法があるが、今回はclientWidth、clientHeightを使用する。
要素サイズの取得
要素サイズの取得は以下の通り。
//要素を取得してから、幅と高さを取得
let stable1 = document.getElementsById("stable1");
const stable1Width = stable1.getBoundingClientRect().width;
const stable1Height = stable1.getBoundingClientRect().height;
//メソッドチェーンで要素の幅と高さを取得
let stable2Width= document.getElementById("stable2")
.getBoundingClientRect().width;
let stable2Height= document.getElementById("stable2")
.getBoundingClientRect().height;
let active= document.getElementById("active");
stable1とstable2はCSSでwidthとheightを指定していないので、stable1.style.width等ではサイズを取得できないため、getBoundingClientRect()を使う。
・getBoundingClientRect https://developer.mozilla.org/ja/docs/Web/API/Element/getBoundingClientRect
なお、以下のようにすると、IDではなくクラス名等からも取得した要素のサイズを確認できる。
//要素を取得してから、幅と高さを取得
let stable1 = document.getElementByClassName("stable1");
const stable1Width = stable1[0].getBoundingClientRect().width;
const stable1Height = stable1[0].getBoundingClientRect().height;
//メソッドチェーンで要素の幅と高さを取得
let stable2Width= document.getElementsByClassName("stable2")[0]
.getBoundingClientRect().width;
let stable2Height= document.getElementsByClassName("stable2")[0]
.getBoundingClientRect().height;
要素取得の際に、IDとクラス名が混ざると保守性が下がるので、混在するならどちらかに統一する方が良い。
要素サイズの変更
ウィンドウサイズと固定要素のサイズから動的な要素サイズを設定する。
//要素のサイズ設定("px"の付け忘れに注意!)
active.style.width = ( windowWidth - stable1Width - stable2Width ) + "px";
active.style.height = ( windowHeight - stable1Height - stable2Height ) + "px";
getBoundingClientRect()の戻り値はnumberなので、最後に「px」を追加する必要がある。
意外な所でハマらないように注意!
vw、vhでも十分だと思うけども、画面サイズ変更に対して、より厳密にいきたい場合等は、こういう方法もありかもしれない。