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组件核心特性是自动图片优化,导致异常尺寸的原因有两点:
- 自动适配与压缩:组件会根据当前设备的设备像素比(DPR)、容器尺寸自动生成并加载适配的低分辨率图片(默认优先加载更小的优化版本),此时
naturalWidth获取的是优化后图片的宽度,而非原始图片的真实宽度。 - 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在服务端或构建阶段提前获取图片原始元数据,避免客户端获取的不确定性:
- 安装依赖:
npm install sharp
- 创建工具函数获取图片尺寸:
// 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 } }
- 在组件中使用(以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
相关产品推荐
相关产品推荐

