You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 13中使用next/image获取图片原始尺寸异常求助

Next.js 13 next/image 获取图片原始尺寸异常问题

问题描述

在Next.js 13中使用next/image组件获取图片原始尺寸时,返回值约为原始尺寸的39%,Chrome、Safari等多款浏览器及多张图片测试均存在该问题,但原生<img>标签可正常获取原始尺寸。

测试代码对比

next/image 测试代码

import Image from 'next/image'
import { useRef, useEffect } from 'react'

const refTest = useRef(null)

// try1
useEffect(() => {
  if (refTest) {
    console.log(refTest.current.naturalWidth)
  }
}, [refTest])

// try2
const handleImageLoad = () => {
  if (refTest.current) {
    console.log(refTest.current.naturalWidth)
  }
}

return (
  <div style={{ position: 'relative', width: '100%', height: '500px' }}>
    <Image ref={refTest} src="/images/test.jpg" alt="test image" fill onLoad={handleImageLoad} />
  </div>
)

结果:返回值约为原始尺寸的39%

原生<img>测试代码

import { useRef, useEffect } from 'react'

const refTest = useRef(null)

useEffect(() => {
  if (refTest) {
    console.log(refTest.current.naturalWidth)
  }
}, [refTest])

return <img ref={refTest} src="/images/test.jpg" />

结果:返回原始尺寸

问题原因

Next.js 13的next/image组件核心特性是自动图片优化,导致异常尺寸的原因有两点:

  1. 自动适配与压缩:组件会根据当前设备的设备像素比(DPR)、容器尺寸自动生成并加载适配的低分辨率图片(默认优先加载更小的优化版本),此时naturalWidth获取的是优化后图片的宽度,而非原始图片的真实宽度。
  2. fill属性布局影响:使用fill属性时,组件会将图片缩放到容器尺寸,内部<img>元素会被添加内联样式控制显示尺寸,进一步混淆了原始尺寸的获取。

解决方法

1. 禁用图片优化(仅调试或特殊场景使用)

通过unoptimized属性关闭Next.js的图片优化,让组件直接加载原始尺寸的图片:

import Image from 'next/image'
import { useRef } from 'react'

const refTest = useRef(null)

const handleImageLoad = () => {
  if (refTest.current) {
    console.log(refTest.current.naturalWidth) // 此时将获取原始尺寸
  }
}

return (
  <div style={{ position: 'relative', width: '100%', height: '500px' }}>
    <Image 
      ref={refTest} 
      src="/images/test.jpg" 
      alt="test image" 
      fill 
      onLoad={handleImageLoad}
      unoptimized // 禁用自动优化
    />
  </div>
)

注意:该方法不推荐生产环境使用,会失去Next.js图片优化的性能收益。

2. 提前声明原始尺寸(推荐)

若提前知晓图片原始尺寸,直接在next/image组件上指定width和height属性,组件会基于该尺寸优化,同时可直接复用声明的尺寸作为原始尺寸:

import Image from 'next/image'

// 假设图片原始尺寸为1920x1080
const originalWidth = 1920
const originalHeight = 1080

return (
  <div style={{ position: 'relative', width: '100%', height: '500px' }}>
    <Image 
      src="/images/test.jpg" 
      alt="test image" 
      width={originalWidth}
      height={originalHeight}
      fill
      objectFit="cover" // 根据需求调整图片适配方式
    />
    <p>原始宽度:{originalWidth}</p>
  </div>
)

3. 服务端/构建时获取原始尺寸(生产环境推荐)

使用图片处理库sharp在服务端或构建阶段提前获取图片原始元数据,避免客户端获取的不确定性:

  1. 安装依赖:
npm install sharp
  1. 创建工具函数获取图片尺寸:
// utils/getImageSize.js
import sharp from 'sharp'
import fs from 'fs/promises'
import path from 'path'

export async function getImageSize(imagePath) {
  const fullPath = path.join(process.cwd(), 'public', imagePath)
  const metadata = await sharp(fullPath).metadata()
  return { 
    width: metadata.width, 
    height: metadata.height 
  }
}
  1. 在组件中使用(以App Router为例):
// app/page.js
import Image from 'next/image'
import { getImageSize } from '@/utils/getImageSize'

export default async function Page() {
  const { width: originalWidth } = await getImageSize('/images/test.jpg')
  
  return (
    <div style={{ position: 'relative', width: '100%', height: '500px' }}>
      <Image 
        src="/images/test.jpg" 
        alt="test image" 
        fill
        objectFit="cover"
      />
      <p>原始宽度:{originalWidth}</p>
    </div>
  )
}

4. 客户端通过隐藏原生<img>获取尺寸(折中方案)

若必须在客户端动态获取原始尺寸,可添加隐藏的原生<img>元素加载原始图片,通过它获取真实尺寸:

import Image from 'next/image'
import { useRef, useEffect, useState } from 'react'

export default function Page() {
  const [originalWidth, setOriginalWidth] = useState(0)
  const hiddenImgRef = useRef(null)

  useEffect(() => {
    if (hiddenImgRef.current) {
      hiddenImgRef.current.onload = () => {
        setOriginalWidth(hiddenImgRef.current.naturalWidth)
      }
    }
  }, [])

  return (
    <>
      <div style={{ position: 'relative', width: '100%', height: '500px' }}>
        <Image 
          src="/images/test.jpg" 
          alt="test image" 
          fill
          objectFit="cover"
        />
      </div>
      {/* 隐藏的原生img用于获取原始尺寸 */}
      <img 
        ref={hiddenImgRef} 
        src="/images/test.jpg" 
        style={{ display: 'none' }} 
        alt=""
      />
      <p>原始宽度:{originalWidth}</p>
    </>
  )
}

内容的提问来源于stack exchange,提问作者seungdo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 00:09:58