

再谈图片懒加载中的宽高比盒子与布局抖动
source link: https://blog.ichr.me/post/lazyload-ratiobox/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

再谈图片懒加载中的宽高比盒子与布局抖动
我绝对不会告诉你这篇文章新建文件夹于 4 月 4 日;我绝对不会解释为什么半年不写更新博客。
早在两年前,我曾发过一篇 在 Hexo 中实现图片懒加载 的文章,借助 srcset
实现了更好的效果。但是在那篇文章里提到一个问题——加载原图时引发的布局抖动——也一直搁置着没有解决,毕竟想着我网站的图片总是东一份西一份,不是很好计算占位空间。

但其实也不是没有办法,例如 probe-image-size 等项目都很好的实现在不下载整张图片的前提下获取图片尺寸数据。
既然借口没了……
分配占位空间以对抗布局抖动,我之前一只采用的是取巧的方案——直接取封面图的长宽比,这样至少主页等位置能够避免抖动了,但是访客浏览时间最长的页面——文章页——依然有存在抖动的可能。
过了两年多,终归还是让我耐不住开始考虑更优的解决方案了。
其实「网站的图片总是东一份西一份」并非「不是很好计算占位空间」的理由,毕竟早就有在线的图片尺寸获取方案。主要是在图片不算少的网站中,每次构建都重新获取一次图片尺寸未免太浪费时间。就算你不在乎,你的自动部署 CI 可能就要撑爆额度来向你抗议了。而我的博客全部用 Markdown 存储原始内容、由 Hexo 管理生成页面,暂且也没发现什么方便的缓存方案。
诶?既然使用 Markdown 存储原始内容,那为什么不直接修改 Markdown 原始文件呢?
一开始,为了顺应 Hexo 管理,我试图将脚本写进 Hexo 的 Script 里,这样也能更方便的调用一系列 hexo-
组件。但是半天只有同步写法可以正常运行,一旦使用异步写法,就会在脚本尚未执行结束是 Hexo 便开始构建,导致不希望的结果。故放弃,把脚本写在最外面并用 npm 运行吧。
// package.json
"scripts": {
+ "size": "node ./imageSize/index.js",
- "build": "npx hexo cl && npx hexo g && node ./minify/minify.js"
+ "build": "npx hexo cl && node ./imageSize/index.js && npx hexo g && node ./minify/minify.js"
},
然后安装组件:
npm i probe-image-size markdown-it
# yarn add probe-image-size markdown-it
probe-image-size
就是上文提到的在线获取图片尺寸的工具。装 markdown-it
是因为 GitHub 上没看懂 Hexo 外如何调用 hexo-renderer-marked
。
借助 hexo-fs
先扫描出 source
文件夹下所有 .md
文件:
//./imageSize/index.js
fs.listDir(path.join(__dirname + '/../source'), (err, list) => {
if (err) console.log(err);
for (dir of list) {
if (!dir.endsWith('.md')) continue;
handle(path.join(__dirname + '/../source/' + dir)).catch(err => console.log(err));
}
});
async function handle(dir) {}
然后是处理函数,里面自己读注释吧:
//./imageSize/index.js
async function handle(dir) {
let content = await fs.readFile(dir).catch((err) => console.log(err));
let content_md = markdown.render(content);
// 无图片,直接结束
if (!content_md.match(/<img(.*?)src="(.*?)"(.*?)>/gi)) return;
let list = [], sizes = {};
// 扫出所有 **没有设定尺寸** 的图片链接
content_md.match(/<img(.*?)src="(.*?)"(.*?)>/gi).forEach((item) => {
item.replace(/<img(.*?)src="(.*?)"(.*?)>/gi, (str, p1, p2, p3) => {
// 确定之前没有过设定尺寸,否则便不用再获取一次了
if (!p1.match(/style\=\"(.*?)width\:(.*?)\"/gi) && !p3.match(/style\=\"(.*?)width\:(.*?)\"/gi)) list.push(p2);
return '';
});
});
// 去重,确定有需要处理的图片,否则结束
list = Array.from(new Set(list));
if (!list) return;
// 用 probe-image-size 获取图片尺寸并用对象保存
// 这里不能用 `forEach`,否则不能 `await` 了
for (img of list) {
let size = await probe(img).catch((err) => console.log(img + '\n' + err));
if (size.width) sizes[img] = `style="width: ${size.width + size.wUnits}; aspect-ratio: ${size.width + ' / ' + size.height}"`;
}
// 替换 Markdown 原文件
content = content.replaceAll(/\!\[(.*?)\]\((.*?)\)/gi, str => {
let str_md = markdown.renderInline(str);
str_md = str_md.replace(/<img(.*?)src="(.*?)"(.*?)>/gi, (mth, m1, m2, m3) => {
if (sizes[m2]) return mth.replace(`src="${m2}"`, `src="${m2}" ${sizes[m2]}`);
return str;
});
return str_md;
});
content = content.replaceAll(/<img(.*?)src="(.*?)"(.*?)>/gi, (str, p1, p2, p3) => {
if (sizes[p2]) return str.replace(`src="${p2}"`, `src="${p2}" ${sizes[p2]}`);
return str;
});
// 写出,保存
await fs.writeFile(dir, content, (err) => {
if (err) console.log(err);
});
}
其实想过既然已经引入额外脚本,不如去实现些更厉害的功能,譬如懒加载前先生成的虚化缩略图。但是由于一开始思路限制在修改源 Markdown 文件,这番修改后可能会使源文件可读性很差,遂放弃。
Recommend
-
67
前言 本例是在React中实现,不过改一改通过原生js也很好实现,另外兼容性也做到了IE9。(IE8讲道理也是可以的)。 首先看一下需要实现的需求: 要拖动图中的白色横条调整绿色和蓝色区域的高度,要拖
-
68
在搭建 UI 的过程中,经常会出现要求约束宽高比的需求。 比如,把照片变成 16:9 或者 4:3 ,这个时候你会怎么做? 是动态设置?还是写死宽高? 为此,Flutter 为我们提供了可以约束宽高比的控件 Aspe...
-
47
为了提高代码的兼容性,我们有时需要判断当前系统的平台,然后做一些适配。比如,我们在使用 StatusBar 做导航栏的时候,在 iOS 平台下根视图的位置默认情况下是占据状态栏的位置的,我们通常希望状态栏下面...
-
25
帮忙看看,读取图片的宽高和实际的宽高是相反的-CSDN论坛解决Android通过BitmapFactory获取图片宽高度相反的问题使用上述代码,在图片未旋转的情况下得到的结...
-
9
1. 文本组件(Text) 概述: 文本(Text)是用来显示字符串的组件,在界面上显示为一块文本区域。仅仅作为展示数据使用,用户不能在App中修改文本组件中的内容。 Text组件是最基本的组件,后面还会学习其他的子类组件,比如But...
-
6
V2EX › JavaScript 使用 onload 给改边图片宽高无效 aglsv · 8 小时 46 分钟前 · 617 次点击
-
2
浅谈DOM常见属性_位置/宽高更新日期: 2022-02-28阅读量: 49标签: dom分享扫一扫分享
-
5
在
-
4
在响应式网页设计中,保持一致的纵横比(称为纵横比)对于防止布局累积偏移至关重要。 随着在 Chromium 88、Firefox 87 和 Safari Technology Preview 版本中引入纵横比属性“aspect-ratio”,让我们有了更简洁的方法来实现。padding-top的实现在没有...
-
5
Css实现图片宽高自适应等比例缩放的方式和使用场景更新日期: 2023-03-17阅读: 47标签:
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK