🪐

Reactでwindowサイズに応じたUI全体の縮小比率の調整

2023/12/12に公開1

この記事はファンタアドベントカレンダー2023の12日目となっております!
本日誕生日であるエンジニア白木がお届けします!!

概要

本記事ではReactを用いてwindowサイズに応じたUI全体の縮小比率の調整を行い、どのような画面幅でも同じレイアウトの画面を常に表示する実装と活用サンプルをご紹介します。

技術スタック

  • React
  • TypeScript
    ※サンプルに一部型注釈があるだけなので、そこを削除すればJavaScriptのみでも問題ないです

スケール(縮小比率)を計算するためのカスタムフック

ブラウザウィンドウのサイズに基づいてスケール(縮小比率)を計算するため、Reactのカスタムフック(useWindowScale)を作成します。
このフックは、ウィンドウのサイズが変更された際に反応して、適切なスケール値を更新します。

ソースコード

const CONTENT_WIDTH = 1280;
const CONTENT_HEIGHT = 1024;

const useWindowScale = () => {
  const [scale, setScale] = useState(1);

  useEffect(() => {
    function handleResize() {
      const windowWidth = window.innerWidth;
      const windowHeight = window.innerHeight;

      const scaleX = windowWidth / CONTENT_WIDTH;
      const scaleY = windowHeight / CONTENT_HEIGHT;

      // 横幅と高さの縮小比率の中で最小のものを選ぶ
      const dynamicScale = Math.min(scaleX, scaleY);

      setScale(dynamicScale);
    }

    // 初回ロード時のサイズに基づいてスケーリング
    handleResize();

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  return { scale };
};

解説

  1. 定数 CONTENT_WIDTH と CONTENT_HEIGHT で基盤となる幅と高さを設定します。
  2. useState を使用して、scale という状態を初期化します。scaleはウィンドウのスケール(縮小比率)を保持します。
  3. useEffectを使用して、ウィンドウのサイズが変更されたときに実行される handleResize 関数を設定します。
  4. handleResize は、現在のウィンドウの幅と高さを取得し、CONTENT_WIDTH と CONTENT_HEIGHT に基づいてスケールを計算します。この比率は、ウィンドウの幅と高さの比率とのうち最小のものを選択します。
    5.ウィンドウのリサイズイベントリスナーに handleResize 関数を追加し、コンポーネントのアンマウント時にイベントリスナーを削除します。
  5. 最後に、計算された scale 値を返却しJSX内で利用します

簡単な利用サンプルコード

const Sample = () => {
  const { scale } = useWindowScale();

  const style: CSSProperties = {
    transform: `scale(${scale})`,
    transformOrigin: 'top left',
    width: `${CONTENT_WIDTH}px`,
    height: `${CONTENT_HEIGHT}px`
  };

  return (
    <div style={style}>
      <h1>コンテンツはウィンドウサイズに応じてスケール</h1>
    </div>
  );
};

解説
計算されたスケール比を利用して、スタイル(transform プロパティ)に適用します。これにより、コンポーネントのサイズはブラウザウィンドウのサイズに合わせて動的に調整することが可能になります。

実践的な使用例

実際に先ほど作成したuseWindowScaleなどを活用して、どのような画面幅でも同じレイアウトのUIを画面中央に表示させるということを試したのでご紹介します。

完成イメージ

完成イメージgif

実践的な利用サンプル


const Sample = () => {
  const { scale } = useWindowScale();

  const scalingStyle: CSSProperties = {
    width: `${CONTENT_WIDTH}px`,
    height: `${CONTENT_HEIGHT}px`,
    transform: `scale(${scale})`,
    transformOrigin: 'center center',
  };

  return (
    <>
      <div
        style={{
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          height: '100vh',
        }}
      >
        <div 
          style={{
            display: 'flex', 
            alignItems: 'center', 
            ...scalingStyle 
          }}
        >
          <div style={{ width: '200px', height: '100%' }}>
            <p>左サイドバー的な</p>
          </div>
          <div
            style={{ width: '880px', height: '100%', backgroundColor: 'gray' }}
          >
            <h1 style={{ fontSize: 60 }}>タイトル</h1>
            <h2 style={{ fontSize: 40 }}>サブタイトル</h2>
            <p style={{ fontSize: 40 }}>本文</p>
          </div>
          <div
            style={{
              width: '200px',
              height: '100%',
              backgroundColor: 'lightblue',
            }}
          >
            <p>右サイドバー的な</p>
          </div>
        </div>
      </div>
    </>
  );
};

解説

  • flexを活用して要素自体が常に中央に来るようにコントロールしています。
  • スケールの中心は (transformOrigin: 'center center') に設定されており、中央からの拡大縮小が行われます。

※ CSSスタイリングはサンプルなので、インラインCSSを利用しています

おわりに

今回は、ウィンドウのサイズに応じてコンテンツのスケール(縮小比率)を調整することで、どのような画面幅でも同じレイアウトを適応する方法について紹介しました。

同じような実装や方針で悩んでいる方の助けになれば幸いです。ここまで読んでいただきありがとうございました!

明日13日目の記事はUI/UXデザイナーの永田さんが、デザインチームで実施した「8分で交代!インタビュー練習会」について紹介してもらっています!ぜひご拝読ご一読いただければと思います!

ファンタラクティブテックブログ

Discussion