前言

之前写过 HTML & CSS – Responsive Image 响应式图片 (完整版), 里面解释了原理和一些具体做法, 但是并不是以真实场景作为例子带入.

由于 RWD Image 挺复杂, 所以特地再写一篇以实战的角度来解释.

建议先阅读之前的相关文章:

CSS – RWD (Responsive Web Design) 概念篇

CSS – 屏幕, 打印, 分辨率, 物理像素, 逻辑像素, Retina, DPI, PPI 是什么?

HTML & CSS – Responsive Image 响应式图片 (完整版)

屏幕 Resolution Research

RWD 的要求是在不同的屏幕尺寸下自适应设计. 那么第一步就是要先搞清楚, 到底屏幕尺寸有哪些.

市场虽然已经有了 standard 的 Breakpoint (Bootstrap 和 Tailwind CSS 各一个版本), 但是这种全世界通用的尺寸, 不一定适合所有项目.

更何况这个 Breakpoint 是 for RWD Design 而不是 RWD Image.

如果网站已经有访问数据, 那么可以直接从 Google Analytics 里面查看, 用户使用的设备尺寸. 如果网站还没有数据, 那么可以通过 statcounter 查看

电脑屏幕 resolution:

新加坡:

马来西亚:

1920 x 1080 是 desktop 用的屏幕. DPR (device pixel ratio) = 1

1280 x 720   是 laptop 1920 x 1080 的屏幕但是 display resolution 调成了 150%. 所以它的 DPR = 1.5 (1280 是逻辑像素, 1920 是物理像素)

1536 x 864   是 laptop 1920 x 1080 的屏幕但是 display resolution 调成了 125%. 所以它的 DPR = 1.25 (1536 是逻辑像素, 1920 是物理像素)

1366 x 768   是 laptop 1366 x 768 的屏幕, 这个是廉价屏幕, 所以它物理像素本来就很少 (不是高清)

1440 x 900   是 MacBook 苹果电脑 2880 x 1800 的屏幕但是 display resolution 调成了 200%. 所以它的 DPR = 2 (1440 是逻辑像素, 2880 是物理像素)

2560 x 1440 我不清楚, 1600 x 900 是廉价的 desktop 屏幕 (这 2 个太少了, 我就不打算支持了)

手机屏幕 resolution:

新加坡:

马拉西亚

414 x 896 是 iPhone (XR, XS Max, 11, 11 Pro Max), DPR = 2 和 3 都有 (看机型)

390 x 844 是 iPhone (12, 12 Pro), DPR = 3

375 x 812 是 iPhone (X, 11 Pro), DPR = 3

428 x 926 是 iPhone 12 Pro Max, DPR = 3

360 x 800 是 LG, Samsung, Hua Wei, DPR = 2, 3 ,4

360 x 780 是 iPhone 12 mini 和各种 Android 机, DPR = 2, 3, 4

393 x 873 是 Xiaomi, DRP = 2.75

平板屏幕 resolution:

我只关注 iPad

768 x 1024 是 iPad 6th gen portrait, DPR = 2

810 x 1080 是 iPad 7th gen portrait (到目前的 9th 都是), DPR = 2

1024 x 768 是 iPad 6th gen landscape, DPR = 2

1080 x 810 是 iPad 7th gen landscape (到目前的 9th 都是), DPR = 2

尺寸资料来源

尺寸资料是从这里这里这里获取的.

Intrinsic Size & Rendered Size

图片有两个尺寸, 一个是 Intrinsic size (固有尺寸), 另一个是 Rendered size (显示尺寸).

使用 Chrome dev tool 就可以看见了

Intrinsic size 指的是这张图的 physical dimensions pixel (物理像素). 它不会受 CSS style 影响

Rendered size 指的是这张图最终显示出来的 dimension pixel (逻辑像素). 它会受 CSS style 影响

例子说明:

<img src="https://via.placeholder.com/3200x1800" />

一张 3200 x 1800 的图放到 img 里, width heght 默认是 auto

这时 intrinsic 和 rendered size 都是一样的, 3200 x 1800, 因为 width height auto 的意思是显示完整的图片.

但如果加上 CSS width: 300px

intrinsic size 依然是 3200 x 1800 (它不受 CSS 影响), 但是 rendered size 就变成了 300 x 168.75.

因为 CSS 声明了 width 是 300px 而 height auto 则表示图片按照原始比例缩小, height 就变成了 168.75

按比例缩小的算法是 new height = new width * old height / old width (我的背法是 新的 乘于对角 然后 除)

The Problem

intrinsic 大于 rendered 就表示浪费了带宽. (SEO performance 会扣分)

intrinsic 小于 rendered 就表示图片太小, 图片会变蒙 (失真)

除了上面这种同比例缩小的情况, 不同比例也会导致 intrinsic != rendered size

举例:

原图 320 x 180

CSS width: 160px; height: 180px; object-fit: cover;

最终图片只显示了 horizontal 中间的部分.

rendered size: 160 x 180 (160px 的 width 浪费了)

The Solution

RWD Image 要解决的问题就是这些. 它的思路很简单, 就是通过 media query 去判断当前屏幕.

然后换一张合适的图片, 尽可能让图片 intrinsic 和 rendered 一致, 既不失真也不浪费带宽

有几个维护成本需要被考虑:

1. 这个方案是拿空间换时间, 准备多张不同尺寸的图片并不容易. 而且浪费 disk space.

2. RWD Image 是不依赖 CSS 渲染的, 也就是说, 虽然 rendered size 是 CSS 搞出来的. 但是当我们在做 RWD Image 时却无法依赖 CSS

需要直接给出最终的数字. CSS 可以写 100%, 但 RWD 不能写 100%, 它只能依据不同尺寸的屏幕 hardcode 写 rendered 多少 px.

这是因为 browser 在处理 img srcset 或者 picture source srcset 时是没有去解析或依赖 CSS style 的.

3. Google Lighthouse 会有一些评分标准, intrinsic 和 redered size 差太远就会报 error 了, 比如差了 4 KiB

简单案例 img + srcset + size

HTML

<header>Header</header>
<main>
<img src="https://via.placeholder.com/3200x1800" />
<img src="https://via.placeholder.com/3200x1800" />
</main>

CSS Style

header {
font-size: 2rem;
padding-block: 1rem;
text-align: center;
background-color: crimson;
color: white;
}
main {
display: grid;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
img {
max-width: 100%;
}
}

header 只是为了美而已.

效果

中间的 2 张图, 在不同的屏幕尺寸下, 它们的 dimension 都不一样.

每一个 rendered size 和 intrinsic size 也都不一致.

图片准备

我挑出几个 size 来准备 for example 就好.

Android (360w, DPR: 2, 3, 4)

rendered size 最好的获取方式是用 dev tool 去查看 (如果 CSS 很简单的话, 也可以自己算)

rendered size = 360 x 202.5

2x = 720 x 406 (注: 这里微差的算法因人而异, 我的做法是 202.5 ceil to 203 then x2 = 406)

3x = 1080 x 609 (注: 203 x 3 = 609)

4x = 1440 x 812

iPhone (414w, DRP: 2, 3)

rendered size = 414 x 232.88

2x = 828 x 466

3x = 1242 x 699

iPad (810w, DPR: 2)

rendered size = 397 x 223.31

2x = 794 x 448

图片的比例都是 16:9. 一共 6 张图 width: 720, 1080, 1440, 828, 1242, 794.

srcset + size

所有图片的比例都是一样的 16:9 只是 dimension 不同, 这个属于 Resolution switching: Different sizes and different resolutions, 不是 Art direction 所以不需要用 picture element 也可以解决.

<img
srcset="
https://via.placeholder.com/720x406 720w,
https://via.placeholder.com/1080x609 1080w,
https://via.placeholder.com/1440x812 1440w,
https://via.placeholder.com/828x466 828w,
https://via.placeholder.com/1242x699 1242w,
https://via.placeholder.com/794x448 794w,
https://via.placeholder.com/3200x1800 3200w
"
sizes="(max-width: 360px) 360px, (max-width: 414px) 414px, (max-width: 810px) 397px, 3200px"
src="https://via.placeholder.com/3200x1800"
width="3200"
height="1800"
/>

srcset 把所有图片列出来. 720w 是 phisical pixel.

sizes 的匹配顺序是 if else 哦, 第一个进到了就不会往下走了, 所以合理的匹配方式是使用 max-width 也就是 <= 360px, <=414px, <=810px

(max-width: 810px) 397px 的意思是当 viewport <= 810px 的时候, 图片的 rendered size 是 397px.

810 是 iPad 所以它的 RDP 是 2, rendered size 397px x 2 = 794px. 所以最终会去 srcset 里面找 794px 的图作为显示.

width dynamic 写法

上面这种写法是完全 hardcode 的, 当 media 是多少, image rendered size 是多少 px

其实也可以写成 dynamic 的 比如

<img
sizes="(max-width: 414px) 100vw, (max-width: 810px) calc((100vw - 1rem) / 2), 3200px"
/>

这个和上面是完全等价的效果.

当 viewport 414px 时, width 时 100vw

当 viewport 810px 时, width = vw 扣掉中间的 gutter (1rem) 然后 50% 就是 image rendered size

注意 : 不能写 % 哦, calc 可以但 min(), max() 函数是不支持的哦

一个比较好的管理方式是, follow RWD 的 Breakpoint 然后里面写 dynamic 算法 depend on vw. 然后准备几张图. 大概一个间隔就可以了.

虽然这做法无法到达 100% rendered size 和 intrinsic 一致, 但是 trade-off 到很合理. 维护也比较容易.

具体做法是这样的, 把所有 rendered size 列出来, 然后每间隔 100px 就保留一张图, 然后 media <= 639 就 100vw.

复杂案例 picture > source

HTML & CSS – 实战 RWD Image 响应式图片的更多相关文章

  1. 【读书笔记《Bootstrap 实战》】3.优化站点资源、完成响应式图片、让传送带支持手势

    A.优化站点资源 速度很重要.用户很关心.我们的站点必须加载够快,否则用户就会走人.SEO 也很重要.我们的站点必须加载够快,否者搜索排名就会下降. 明白了这样,我们就来清点一下 [Bootstrap ...

  2. CSS 与 HTML5 响应式图片

    什么是响应式图片? 响应式图片是指:用户代理根据输出设备的分辨率不同加载不同类型的图片,不会造成带宽的浪费.同时,在改变输出设备类型或分辨率时,能及时加载对应类型的图片. CSS3 响应式图片 对于很 ...

  3. CSS与HTML5响应式图片

    随着 Retina 屏幕的逐渐普及,网页中对图片的适配要求也越来越高.如何让图片在放大了两倍的 Retina 屏幕显示依然清晰,曾经一度困扰着网页开发者,好在 CSS3 与 HTML5 已经着力在改变 ...

  4. 【Bootstrap】3.优化站点资源、完成响应式图片、让传送带支持手势

    A.优化站点资源 速度很重要.用户很关心.我们的站点必须加载够快,否则用户就会走人.SEO 也很重要.我们的站点必须加载够快,否者搜索排名就会下降. 明白了这样,我们就来清点一下 [Bootstrap ...

  5. web响应式图片设计实现

    .header { cursor: pointer } p { margin: 3px 6px } th { background: lightblue; width: 20% } table { t ...

  6. 继续送假期干货——响应式图片工具smartImg

    中午看<众妙之门>看到一个响应式图片处理工具(点此查看)的介绍,然后就心血来潮想着不妨自己写一个基于JQ的吧,于是就又有了这么一个干货给大家. smartImg 的全部文件可以从我的Git ...

  7. bootstrap-内联表单 水平(横向)表单 响应式图片 辅助类 [转]

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  8. 如何使用 HTML5 的picture元素处理响应式图片

    来自: http://www.w3cplus.com/html5/quick-tip-how-to-use-html5-picture-for-responsive-images.html 图片在响应 ...

  9. bootstrap中如何让响应式图片(img-responsive)水平居中

    我们在用bootstrap排版内容的时候,有的时候在内容中需要图片水平居中对齐. 一般情况下,我们的图片都使用了 .img-responsive 类来实现响应式图片.如果需要实现响应式图片水平居中,那 ...

  10. 响应式图片srcset学习

    响应式图片srcset全新释义sizes属性w描述符 先转再看

随机推荐

  1. el-config-provider

    el-config-provider是Element Plus库中的一个组件,用于提供全局的配置.它是Element Plus在2.0版本中引入的新组件. el-config-provider组件的作 ...

  2. oeasy教您玩转vim - 48 - # ed由来

    ​ 范围控制 回忆上节课内容 我们这次研究了mark的定义和使用 mb定义 'b跳转 可以对marks,查询删除 三种marks 小写 本文件内 大写 跨文件 数字 配置文件中 甚至可以在行编辑中,使 ...

  3. 强烈推荐:18.3k star,推荐一款简单易用的HTTP请求流量录制回放工具:Goreplay

    在软件开发和测试过程中,我们经常需要对应用程序的网络请求进行录制和回放,以便进行性能分析.压力测试或者模拟复杂的网络环境.今天,我要向大家推荐一款简单易用的 HTTP 请求流量录制回放工具:Gorep ...

  4. C#实现单例模式的6种方法

    介绍 单例模式是软件工程学中最富盛名的设计模式之一.从本质上看,单例模式只允许被其自身实例化一次,且向外部提供了一个访问该实例的接口.通常来说,单例对象进行实例化时一般不带参数,因为如果不同的实例化请 ...

  5. ABC354

    A link 模拟整个过程即可. 点击查看代码 #include<bits/stdc++.h> #define int long long using namespace std; sig ...

  6. bloom效果

    搜索 复制

  7. telegraf 常用命令总结

    本文为博主原创,转载请注明出处: Telegraf 是一个灵活的服务器代理,用于收集和报告指标.它支持插件驱动,这意味着你可以根据需要添加或修改功能. 1.使用telegraf --help 查看te ...

  8. 10、SpringMVC之处理Ajax请求

    创建名为spring_mvc_ajax的新module,过程参考9.1节和9.5节 10.1.SpringMVC处理Ajax请求 10.1.1.页面请求示例 <input type=" ...

  9. 【Java】讲讲StreamAPI

    预设场景: 从Mybatis调用Mapper得到的用户集合 List<UserDTO> userList = new ArrayList<>(); 常用的几种API用法示例: ...

  10. 【Phoenix】4.14.1-Hbase-1.3版本 安装

    Phoenix 版本 会附带Hbase版本,要根据安装的Hbase版本下载Phoenix 下载Phoenix wget http://archive.apache.org/dist/phoenix/a ...