前言

之前写过 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. 如何解决 CentOS 7 官方 yum 仓库无法使用的问题

    一.背景介绍 2024 年 7 月 1 日,在编译基于 CentOS 7.6.1810 镜像的 Dockerfile 过程中,执行 yum install 指令时,遇到了错误:Could not re ...

  2. Python爬虫(5-10)-编解码、ajax的get请求、ajax的post请求、URLError/HTTPError、微博的cookie登录、Handler处理器

    五.编解码(Unicode编码) (1)GET请求 所提方法都在urllib.parse.路径下 get请求的quote()方法(适用于只提交一两个参数值) url='http://www.baidu ...

  3. 如何更好的使用 Windows

    如何更好的使用 Windows Microsoft 辅助功能和工具 键盘快捷方式,常用 ctrl+C 复制 ctrl+V 粘贴 ctrl+X 剪切 ctrl+Z 撤销 ctrl+Y 回退 alt+ta ...

  4. spring boot 快速入门(一)创建一个简单的Spring Boot项目

    1.什么是Spring Boot Spring Boot makes it easy to create stand-alone, production-grade Spring based Appl ...

  5. freemarker+minio实现页面静态化

    什么是页面静态化? 将原本动态生成的网页内容通过某种形式转化为html并存储在服务器上,当用户请求这些页面时就不需要执行逻辑运算和数据库读 优点: 性能:提高页面加载速度和响应速度,还可以减轻数据库. ...

  6. 【ECharts】02 饼图

    饼状图: <!-- 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main" style="width: 600px;he ...

  7. 强化学习:一种新的并行算法下的参数同步更新方式——半异步更新方式——( 同步、异步 -> 半异步 )

    Abstract: 并行算法下的参数同步方式一般有同步更新和异步更新两种方式,本文在此基础之上提出了一种新的参数同步方式--半异步更新方式. Introduction: 这里用神经网络举例子,也就是神 ...

  8. SSH如何通过proxy进行服务器连接

    openssh是什么这里不做解释,但凡是用过linux系统的一般都是会了解这个的,毕竟openssh都是系统自带的应用. openssh一般都是指linux上的客户端,很多linux系统自有客户端的s ...

  9. 白鲸开源CEO郭炜在2024 DataOps发展大会上获聘专家

    2024年5月15日,白鲸开源CEO郭炜在2024 DataOps发展大会上被正式聘任为DataOps专家,并获得了荣誉证书.本次大会由中国通信标准化协会主办,中关村科学城管委会提供支持,大数据技术标 ...

  10. spring手动事务控制

    在项目开发中需要用到手动事务进行控制.现说下遇到的问题以及解决方案: 如果程序需要使用嵌套事务,则需要在配置文件中添加一个配置属性,如下: <bean id="transactionM ...