ブラウザでコンテンツのアスペクト比を固定する方法

1, 事の経緯

今会社でブラウザゲー作ってる関係でゲームのアスペクト比を 16:9 に固定したいなって思ったんですよね。

そこでググッたらまあ天才な方々がやり方書いてあるのよ。大体は画像向けなんだけどちゃんとブロック要素に使えるものもあって助かった

<!DOCTYPE html>
<html>
 <head>
  <style>
   body {
    width: 100%;
   }
   #wrapper {
    width: 100%;
    position: relative;
   }
   #wrapper::before {
    display: block;
    content: "";
    padding-top: 50%;
   }
   #content {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    left: 0;
   }
  </style>
 </head>
 <body>
  <div id="wrapper">
   <div id="content">
   </div>
  </div>
 </body>
</html>

これがどういうものかと言うと、アスペクト比を固定したいコンテンツをラッピングして、それの擬似要素のpadding-topに、ラッパー要素の横幅の50%の大きさを適用するというもの。

パディングの大きさは固定したいアスペクト比の
縦 ÷ 横 × 100
でだしたもの。50%は 2:1の場合やね。

これによって横幅が100%に対して縦幅が横幅の50%で 2:1 が完成するという寸法。 

2, これじゃ役不足だった

確かにこれでアスペクト比はちゃんと固定される。しかしこれじゃ不十分。ちょっと考えればわかると思うがこれは横幅だけを考えたものなんだよね。これじゃ画面の縦幅が横幅の50%より小さかったりするとコンテンツが画面の外にはみ出しちゃう。ゲームを作る上でこれはいただけないしスクロールバー気持ち悪い。

ということでくっそ眠いし腹痛いしでなんやかんや2時間くらい悩んで編み出した、縦変化対応のアスペクト比固定がこれ。

<!DOCTYPE html>
<html>
 <head>
  <style>
   body {
    width: 100%;
   }
   #wrapper {
    width: 100%;
    position: relative;
    margine: 0 auto;
   }
   #wrapper-before {
    display: block;
   }
   #content {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    left: 0;
   }
  </style>
  <script>
   const xRatio = 16;
   const yRatio = 9;
   const padding = yRatio / xRatio;
   
   document.addEventListener("DOMContentLoaded", aspectLock()); 
   window.onresize = aspectLock();
   
   function aspectLock() {
    const wrapper = document.getElementById("wrapper");
    const before = document.getElementById("wrapper-before");
    let wrapperWidth = window.innerHeight / padding;
    wrapperWidth = wrapperWidth > window.innerWidth ? window.innerWidth : wrapperWidth;
    wrapper.setAttrobute("style", `width: ${wrapperWidth};`);
    before.setAttribute("sttle", `padding-top: ${padding * 100}px`);
   }
  </script>
 </head>
 <body>
  <div id="wrapper">
   <div id="wrapper-before"></div>
   <div id="content">
   </div>
  </div>
 </body>
</html>

こんな感じ。とりあえずパディングの値を計算して入れるために擬似要素じゃなくてdivを挿入。

縦サイズをピッタリに合わせるために、アスペクト比から計算した値を画面の縦幅から割って、比率にあったコンテンツの横幅を計算。その値が画面の横幅より大きかったら画面の横幅を挿入。その横幅から比率にあったコンテンツの縦幅を設定するために padding変数に入れた値を100倍してpadding-topに設定。

スタイルの方は、コンテンツの横幅が画面の横幅より小さくなることがあるので、wrapperにmargine: 0 auto を設定して左右中央揃え。必要に応じてbodyに背景色とか背景画像を設定したらいい感じになるかも。

こうすることで望み通りの挙動を得ることができた。

もっといい方法あったら教えて欲しいな。今回はこれで。またいつか


いいなと思ったら応援しよう!