0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js で blur 画像が滑らかに切り替わらない問題を解決した話

Posted at

経緯

参考図書

参考図書の学習において、ブログ記事でアイキャッチ画像に Plaiceholder を使った blur 表示 を導入していました。
local の画像も外部 URL の画像も対応させて、next/imageplaceholder="blur" で表示する予定です。

しかし、いざブラウザで確認すると…

  • blur は表示される
  • でも通常画像に滑らかに切り替わらない

という現象に遭遇しました。

原因の特定

最初は getPlaiceholder で生成した blurDataURL が正しくないのかと思い、コンソールで確認しました。
しかし、base64 はちゃんと入っていました。

次に Image コンポーネント周りを見直して気づいたのがこちら:

<Image
  src={eyecatch.url}
  layout="responsive"
  width={eyecatch.width}
  height={eyecatch.height}
  sizes="{min-width: 1152px} 1152px, 100px" // ←ここ
  placeholder="blur"
  blurDataURL={eyecatch.blurDataURL}
/>

sizes の指定を {} で囲んでいた ため、Next.js は文字列として認識せず、正しくレスポンシブサイズを計算できていませんでした。
結果、blur が残ったまま通常画像に切り替わらない状態になっていたようです。

解決方法

単純ですが、{} を外して文字列として渡すだけで解決しました。

<Image
  src={eyecatch.url}
  layout="responsive"
  width={eyecatch.width}
  height={eyecatch.height}
  sizes="(min-width: 1152px) 1152px, 100px" // ←修正
  placeholder="blur"
  blurDataURL={eyecatch.blurDataURL}
/>

⇩全体コード

import Image from 'next/image';
import path from 'path';
import { getPlaiceholder } from 'plaiceholder';
import { eyecatchLocal } from 'lib/constants';
import { getPostBySlug } from 'lib/api';
import { extractText } from 'lib/extract-text';

export const getStaticProps = async () => {
    const slug = 'micro';
    const post = await getPostBySlug(slug);
    const description = extractText(post.content);
    const eyecatch = post.eyecatch ?? eyecatchLocal;

    const imagePath = eyecatch.url.startsWith('/')
        ? path.join(process.cwd(), 'public', eyecatch.url.replace(/^\//, ''))
        : eyecatch.url;

    const { base64 } = await getPlaiceholder(imagePath);
    eyecatch.blurDataURL = base64;

    return {
        props: {
            title: post.title,
            publish: post.publishDate,
            content: post.content,
            eyecatch: eyecatch,
            categories: post.categories,
            description: description,
        },
    };
};

const PostPage = ({ title, content, eyecatch, description }) => {
  return (
    <article>
      <h1>{title}</h1>

      {/* アイキャッチ画像 */}
      <Image
        src={eyecatch.url}
        alt={title}
        layout="responsive"
        width={eyecatch.width}
        height={eyecatch.height}
        sizes="(min-width: 1152px) 1152px, 100px" // ← {} を外して文字列に
        placeholder="blur"
        blurDataURL={eyecatch.blurDataURL} // ← しっかり base64 が入っている
      />

      <div dangerouslySetInnerHTML={{ __html: content }} />
    </article>
  );
};

export default PostPage;

まとめ

  • Next.js のImagesizes を渡すときは 文字列として渡す
  • {} で囲むとオブジェクト扱いになり、ブラウザで正しく解釈されない
  • blur 画像から通常画像への切り替えが効かない場合は、まずここを疑うと早い
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?