Webのあれこれ

アイキャッチアイコン320pxサイズにはもう悩まない!等倍縮小の方法を、JS / React / Next.jsそれぞれ解説

カテゴリ: React / Next.js

  • 作成日:2022/09/20
  • 更新日:2022/10/03

目次

    「デザインカンプどおりに作成したけど、375px ~ 320pxでめっちゃずれる〜😭」なんてことはありませんか?
    Web制作では特にあるあるだと思います。
    現在は、スマホの画面も大きくなり360px未満のデバイスを使っている人は少数派になってきています。
    その割には、細かい調整で疲弊しがちなレスポンシブ対応を "viewport" をいじって楽に、見栄え良くしましょう!!
    vanilla JavaScript / React / Next.jsそれぞれ解説していきます。

    作成イメージ

    指定したサイズ以下になると、等倍縮小します。



    JavaScriptで対応

    Web制作では、バニラJavascript or jQueryで書くことがほとんどなので以下のコードでOKです。

    main.js

    const setViewport = () => {
      const standardWidth = 375; // 基準サイズ
      const innerWidth = window.innerWidth; // デバイス幅
      const metaViewport = document.querySelector('meta[name="viewport"]');
      const valueWidth = innerWidth < standardWidth
      ? `width=${standardWidth}, user-scalable=no, target-densitydpi=device-dpi`
      : "width=device-width, initial-scale=1";
      metaViewport.setAttribute("content", valueWidth);
    };
    
    document.addEventListener("DOMContentLoaded", () => {
      setViewport(); // 実行
    });
    
    


    イベント部分を、変えれば jQueryでも可能です。
    また、呼び出す側でサイズを指定することもできます。

    main.js

    const setViewport = (setWidth) => {
      const standardWidth = setWidth || 375; // 基準サイズ
      // 以下略
    };
    
    document.addEventListener("DOMContentLoaded", () => {
      setViewport(360); // 引数を入力すると適用/未入力だと上記で指定したサイズ(375px)
    });



    Reactで対応

    Reactでは、 react-router-dom でルーティング設定をします。
    さらに、HTMLのメタ情報を書き換えるために react-helmet-async をインストールします。

    npm i react-helmet-async @types/react-helmet-async react-router-dom


    App.tsx内で、HelmetProviderでRouterを囲って使用できるようにします。
    Router.tsxファイルは、特に変更する箇所がないため割愛します。

    App.tsx

    <HelmetProvider>
      <Router />
    </HelmetProvider>


    これで、準備は完了したためメインの記述をしていきます。
    コードを整理するために、ロジック部分はカスタムフックを作成して書いていきましょう!
    まずsrc配下にhooksフォルダを作成してその中に、useViewport.tsを作成します。

    useViewport.ts

    import { useLayoutEffect, useState } from 'react'
    
    const standardWidth = 375  // 基準サイズ
    
    const getViewport = ({ width }: { width: string }) => {
      return `width=${width},maximum-scale=1.0`
    }
    
    export const useViewport = () => {
      const [viewport, setViewport] = useState(
        'width=device-width,initial-scale=1.0,maximum-scale=1.0'
      )
    
      useLayoutEffect(() => {
        setViewport(
          getViewport({
            width: `${
              window.outerWidth > standardWidth ? 'device-width' : standardWidth
            }`,
          })
        )
      }, [])
    
      return { viewport }
    }
    
    


    componentsフォルダの中に、Head.tsxを記述します。
    タイトルとviewportの値を、変更します。

    Head.tsx

    import React, { FC, memo } from 'react'
    import { Helmet } from 'react-helmet-async'
    import { useViewport } from '../../hooks/useViewPort'
    
    export const Head: FC<{title: string}> = memo(({ title }) => {
      const { viewport } = useViewport() // viewportを取り出す
    
      return (
        <Helmet>
          <meta name="viewport" content={viewport} />
          <title>{title ?? 'デフォルトのタイトル'}</title>
        </Helmet>
      )
    })


    タイトルはページごとに変えれるように、propsを受け取るようにしています。
    余談ですがタイトルを動的に変更する際は、以下のようにpropsを渡せばOKです。

    Hoge.tsx

    const Hoge = () => {
      return (
        <>
        <Head title={'Hogeページタイトル'} />
          <p>Hoge~~</p>
        </>
      )
    }
    export default Hoge


    ⚠︎OGPなどの情報は動的に変更できないため、変更したい場合はNext.jsやGatsby.jsを使用します。
    これで、使えるようになります🎉


    Next.jsで対応

    Next.jsもReactの書き方とほぼ同じですが、Dynamic Routesが使えるためとても簡単です。
    パッケージも必要ありません。
    Reactと同じように、src配下にhooksフォルダを作成してその中に、useViewport.tsを作成します(↑Reactのコード参照)。
    次に、componentsフォルダの中にSeo.tsxを記述します。
    Seo.tsx

    import { NextPage } from 'next'
    import Head from 'next/head'
    import { useViewport } from '../hooks/useViewPort'
    
    const Seo: NextPage<{ ogpTitle: string }> = ({ ogpTitle }) => {
      const { viewport } = useViewport() // viewportを取り出す
    
      return (
        <Head>
          <meta name="viewport" content={viewport} />
          <title>{ogpTitle ?? 'デフォルトのタイトル'}</title>
        </Head>
      )
    }
    
    export default Seo


    Next.jsではOGP情報など自由に動的変更できるため、細かく設定可能です。
    当ブログでも記事ごとにOGP画像を自動生成しているので気になる方は、Githubのソースコードをご覧ください。


    おわり

    画面サイズとのバランスを考慮すると、360px~375pxを基準として設定するのが望ましいかと思います。
    スニペットにまとめておけば、案件ごとにコピペで対応できるためとても便利です!!
    また、方法はいくつかあるので使いやすいようにアレンジしてみてください🙌

    この記事へのコメント

    この記事にはまだコメントがありません。

    お気軽にコメント残してください📝

    © 2022 wadeenOpenMojiis licensed underCC BY-SA 4.0