Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

发现 Next.js 对图片加载做了挺多优化的 #68

Open
findxc opened this issue Feb 14, 2022 · 1 comment
Open

发现 Next.js 对图片加载做了挺多优化的 #68

findxc opened this issue Feb 14, 2022 · 1 comment

Comments

@findxc
Copy link
Owner

findxc commented Feb 14, 2022

最近在学习 Next.js ,看文档才发现它的 Image 组件默默给图片加载做了好多优化,详见 Basic Features: Image Optimization | Next.js ,下面一起来看下具体有哪些优化点以及背后的实现吧。

图片下载完之前支持先展示一个模糊效果

给 Image 组件设置 placeholder='blur' 后,在图片下载完之前会先展示一个模糊效果,这样用户体验会比显示为空白好点。

Next.js 是怎么实现的呢?它给图片加了一个背景图片的样式,以及加上了 filter: blur(20px); 来形成模糊效果,然后原图加载完之后删掉这些样式即可。如果说你的图片没有透明度,那么背景样式不删也是可以的,因为图片会覆盖在背景上。

背景图片来自于 blurDataURL ,网络图片需要手动设置,而本地图片是 Webpack 打包时通过 next-image-loader.js 插件来生成的,打印一下你 import 的图片就能发现。

本地图片没设置宽高也不会有布局偏移问题

如果图片没设置宽高,在图片加载完后,图片之后的内容位置会偏移,如下所示。

Next.js 默认处理了这个问题,它是通过渲染一个额外的透明 svg 来实现的占位。

相关源码见 next.js/image.tsx ,代码中的 sizerSvgUrl 就是透明 svg 图。

默认加上 srcset 属性来适配不同 devicePixelRatio 的屏幕

Image 组件对应的 img 元素默认会加上 srcset 属性,定义一倍图和二倍图的地址,这样 devicePixelRatio 为不同值的时候就会去加载不同的图片。

相关源码见 next.js/image.tsx ,代码中的 imgAttributes 对象中就会有 srcSet 。如果你好奇为啥没有考虑 3x 图, 这里的注释 有解释。

默认会返回压缩后的图片

如果浏览器支持 WebP 格式的图片,那么 Next.js 默认会把原图转为 WebP 后再返回。需要注意这个转换是有损压缩,图片质量会有一定下降,默认转换的 quality 是 75 。

PS:之前写过一篇 关于 WebP 格式的图片 ,文章末尾有图片质量的比较。

再就是 Next.js 返回的图片的尺寸是根据实际需要来的。比如原图是 1000px 宽,然后前端设置图片的宽为 500px ,那么在 devicePixelRatio 为 1 的屏幕上只用展示一倍图,那返回的图片实际宽度就只有 500px 。

可以手动设置属性 unoptimized 为 true 来不设置 srcset ,这样就不会适配 devicePixelRatio 也不会压缩图片了,会直接返回原图。

这些处理是 Next.js 在服务端进行处理的,当请求 /_next/image 的数据时,就会走到 next.js/image-optimizer.ts 里面去,去使用第三方工具 sharp 或者 squoosh 来处理图片。

支持懒加载

Image 的 loading 属性默认值是 lazy ,图片默认会懒加载,然后默认是距离视窗小于 200px 时会加载,可以通过 lazyBoundary 属性来自定义。

补充一下, img 元素原生也支持 loading=lazy 来设为懒加载,在 Chrome 下测试发现图片距离视窗小于约 1200px 时就会加载了,这个距离会不会有点远 😂 。这个距离是浏览器控制的,我们也改不了。

Next.js 中相关源码见 next.js/image.tsx ,是基于 Intersection Observer API 实现的。

支持给图片设置优先级

设置属性 priority 为 true 表示希望优先加载这个图片,这样页面会有一个 preload 的 link 标签来进行预处理。

相关源码见 next.js/image.tsx

总结

以上就是 Next.js 对图片加载做的优化了。如果自己的项目不是 Next.js 又比较重视图片加载,可以参考这些方向去自行优化。

@Qyokizzzz
Copy link

请问我希望Image的宽高是百分数,要如何设置

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants