除了使用媒体查询和现代 CSS 布局(如 flexbox 和 grid)来创建响应式网站之外,我们还可以做一些被忽视的事情来完善响应式网站。在本文中,我们将深入探讨一系列工具(围绕 HTML 和 CSS),从响应式图像到相对较新的 CSS 函数,这些函数无论我们是否使用媒体查询,都自然有效。
事实上,当与这些功能结合使用时,媒体查询更像是补充,而不是完整方法。让我们看看它是如何工作的。
真正响应式的图像
还记得我们以前可以简单地将 width: 100%
添加到图像并称之为结束吗?当然,这仍然有效,并且确实会使图像变得很小,但它也带来了一些缺点,其中最显著的是
- 图像可能会压缩到失去其焦点。
- 较小的设备仍然会下载完整的图像。
在 Web 上使用图像时,我们必须确保它们在分辨率和大小方面进行了优化。原因是确保我们拥有适合设备的图像分辨率,这样我们不会为较小的屏幕下载非常大且重的图像,从而最终降低网站的性能。
简单来说,我们确保将更大的高分辨率图像发送到更大的屏幕,而将较小的低分辨率图像发送到较小的屏幕,从而提高性能和用户体验。
HTML 提供 <picture>
元素,该元素允许我们根据添加的媒体查询指定将要呈现的确切图像资源。如前所述,与其将一个图像(通常是大型高分辨率版本)发送到所有屏幕尺寸并将其缩放至视窗宽度,不如指定一组图像,以便在特定情况下提供服务。
<picture>
<source media="(max-width:1000px)" srcset="picture-lg.png">
<source media="(max-width:600px)" srcset="picture-mid.png">
<source media="(max-width:400px)" srcset="picture-sm.png">
<img src="picture.png" alt="picture"">
</picture>
在这个例子中,picture.png
是全尺寸图像。从那里,我们定义了图像的下一个最大版本,picture-lg.png
,并且尺寸按降序排列,直到最小版本,picture-sm.png
。请注意,我们仍然在这个方法中使用媒体查询,但实际上是 <picture>
元素本身驱动着响应式行为,而不是在 CSS 中定义断点。
媒体查询适当地添加,以根据图像的大小进行缩放
- 视窗大小为 1000 像素及以上的设备会得到
picture.png
。 - 视窗大小介于 601 像素和 999 像素之间的设备会得到
picture-lg.png
。 - 视窗大小介于 401 像素和 600 像素之间的设备会得到
picture-sm.png
。 - 任何小于 400 像素的设备会得到
picture-sm.png
。
有趣的是,我们还可以通过在 URL 后面使用图像密度(例如 1x、2x、3x 等)来标记每个图像。如果我们制作了彼此成比例的不同图像(我们确实做到了),这将起作用。这使浏览器能够根据屏幕的像素密度以及视窗大小来确定要下载哪个版本。但请注意,我们最终定义了多少个图像
<picture>
<source media="(max-width:1000px)" srcset="picture-lg_1x.png 1x, picture-lg_2x.png 2x, picture-lg_3x.png 3x">
<source media="(max-width:600px)" srcset="picture-mid_1x.png 1x, picture-mid_2x.png 2x, picture-mid_3x.png 3x">
<source media="(max-width:400px)" srcset="picture-small_1x.png 1x, picture-small_2x.png 2x, picture-small_1x.png 3x">
<img src="picture.png" alt="picture"">
</picture>
让我们具体看看嵌套在 <picture>
元素中的两个标签:<source>
和 <img>
。
浏览器将查找第一个 <source>
元素,其中媒体查询与当前视窗宽度匹配,然后它将显示相应的图像(在 srcset 属性中指定)。<img>
元素作为 <picture>
元素的最后一个子元素是必需的,作为如果初始 source 标签都不匹配的备选方案。

我们还可以使用图像密度来仅使用 <img>
元素和 srcset
属性处理响应式图像
<img
srcset="
flower4x.png 4x,
flower3x.png 3x,
flower2x.png 2x,
flower1x.png 1x
"
src="flower-fallback.jpg"
>
我们还可以根据 **设备本身** 的 **屏幕分辨率** (通常以每英寸点数或 dpi 衡量),而不是仅仅根据设备视窗,在 CSS 中编写媒体查询。这意味着 **而不是**
@media only screen and (max-width: 600px) {
/* Style stuff */
}
我们现在拥有
@media only screen and (min-resolution: 192dpi) {
/* Style stuff */
}
这种方法使我们能够根据设备本身的屏幕分辨率指定要呈现的图像,这在处理高分辨率图像时可能会有所帮助。基本上,这意味着我们可以为支持更高分辨率的屏幕显示高质量图片,而在较低分辨率的屏幕上显示较小版本。值得注意的是,尽管移动设备的屏幕很小,但它们通常具有高分辨率。这意味着仅依靠分辨率来确定要呈现的图像可能不是最好的选择。这可能导致向非常小的屏幕提供大型高分辨率图像,而这可能不是我们真正希望在如此小的屏幕尺寸下显示的版本。
body {
background-image : picture-md.png; /* the default image */
}
@media only screen and (min-resolution: 192dpi) {
body {
background-image : picture-lg.png; /* higher resolution */
}
}
<picture>
提供的功能本质上是能够对图像进行艺术指导。并且,为了保持这种理念,我们可以利用 CSS 功能,例如 object-fit
属性,它与 object-position
结合使用时,允许我们裁剪图像以获得更好的焦点,同时保持图像的长宽比。
因此,要更改图像的焦点
@media only screen and (min-resolution: 192dpi) {
body {
background-image : picture-lg.png;
object-fit: cover;
object-position: 100% 150%; /* moves focus toward the middle-right */
}
}
在 CSS 中设置最小值和最大值
min()
函数指定元素可以缩小的绝对最小尺寸。此函数在帮助文本大小跨不同屏幕尺寸进行适当缩放方面非常有用,例如,从不允许流体类型下降到低于可读字体大小。
html {
font-size: min(1rem, 22px); /* Stays between 16px and 22px */
}
min()
接受两个值,它们可以是相对值、百分比或固定单位。在这个例子中,我们告诉浏览器永远不要让具有类 .box
的元素的宽度低于 45% 或 600px,以视窗宽度为准,以较小的值为准
.box {
width : min(45%, 600px)
}
如果 45% 计算出的值小于 600px,则浏览器使用 45% 作为宽度。相反,如果 45% 计算出的值大于 600px,则使用 600px 作为元素的宽度。
max()
函数也是如此。它也接受两个值,但它不是指定元素的最小尺寸,而是定义它可以达到的最大尺寸。
.box {
width : max(60%, 600px)
}
如果 60% 计算出的值大于 600px,则浏览器使用 60% 作为宽度。另一方面,如果 60% 计算出的值小于 600px,则使用 600px 作为元素的宽度。
钳位值
我们中的许多人一直在呼吁使用 clamp()
,并且它实际上已经获得了所有现代浏览器的广泛支持(抱歉,Internet Explorer)。clamp()
是 min()
和 max()
函数的组合,它接受三个参数
- 最小值,
- 首选值,以及
- 最大值
例如
.box {
font-size : clamp(1rem, 40px, 4rem)
}
浏览器将字体设置为 1rem,直到 1rem 的计算值大于 40px。当计算值超过 40px 时?是的,浏览器在达到 4rem 后将停止增加大小。您可以看到 clamp() 如何用于使元素变得灵活,而无需使用媒体查询。
使用响应式单位
您是否曾经构建过一个带大型标题或副标题的页面,并赞叹它在桌面屏幕上的效果,然后在移动设备上查看它,却发现它太大了?我肯定遇到过这种情况,在本节中,我将解释如何处理此类问题。
在 CSS 中,您可以使用各种测量单位来确定元素的大小或长度,最常用的测量单位包括:px
、em
、rem
、%
、vw
和 vh
。虽然还有其他一些不常用的单位。我们感兴趣的是,px
可以被认为是绝对单位,而其他单位则被认为是相对单位。
绝对单位
像素 (px
) 被认为是绝对单位,主要是因为它是固定的,不会根据其他任何元素的测量值而改变。它可以被认为是其他一些相对单位使用的基础或根单位。尝试将像素用于响应式行为可能会遇到问题,因为它固定不变,但如果您需要元素根本不进行调整大小,则它们非常有用。
相对单位
相对单位,如 %
、em
和 rem
,更适合响应式设计,主要是因为它们能够跨不同屏幕尺寸进行缩放。
vw
:相对于视窗宽度vh
:相对于视窗高度rem
:相对于根 (<html>
) 元素(默认字体大小通常为 16px)em
:相对于父元素%
:相对于父元素
同样,大多数浏览器默认字体大小为 16px
,而 rem
单位使用它来生成计算值。因此,如果用户调整浏览器上的字体大小,页面上的所有内容都将根据根大小进行适当缩放。例如,当处理设置为 16px
的根时,您指定的数字将乘以默认大小。例如
.8rem = 12.8px (.8 * 16)
1rem = 16px (1 * 16)
2rem = 32px (2 * 16)
如果用户或您更改了默认大小会发生什么?正如我们已经说过的,这些是相对单位,最终的大小值将基于新的基本大小。这在媒体查询中非常有用,您只需更改字体大小,整个页面就会相应地放大或缩小。
例如,如果您在 CSS 中将字体大小更改为 10px
,则计算后的尺寸最终将为
html {
font-size : 10px;
}
1rem = 10px (1 * 10)
2rem = 20px (2 * 10)
.5rem = 5px (.5 * 10)
注意:这也适用于百分比 %
。例如
100% = 16px;
200% = 32px;
50% = 8px;
rem
和 em
单位之间有什么区别?它取决于单位使用什么作为其基元素。 rem
使用根 (<html>
) 元素的字体大小来计算值,而声明 em
值的元素则引用包含它的父元素的字体大小。如果指定父元素的大小与根元素不同(例如,父元素为 18px,但根元素为 16px),则 em
和 rem
将解析为不同的计算值。这使我们能够更精细地控制元素在不同响应式环境中的响应方式。
vh
是“视窗高度”的缩写,即可视屏幕的高度。100vh
代表视窗高度的 100%(取决于设备)。同样,vw
代表“视窗宽度”,表示设备可视屏幕的宽度,而 100vw
实际上代表视窗宽度的 100%。
超越媒体查询
看到没有?我们刚刚浏览了一些非常强大且相对较新的 HTML 和 CSS 功能,这些功能为我们提供了额外的(可能更有效)方法来构建响应式设计。并不是说这些新奇的技术取代了我们一直以来的做法。它们只是我们开发人员工具箱中的更多工具,使我们能够更好地控制元素在不同环境中的行为。无论是处理字体大小、分辨率、宽度、焦点还是其他任何事情,我们对用户体验的控制都比以往更加精细。
因此,下次您在处理一个项目时,希望对特定设备上的设计的外观和感觉有更多控制,请查看原生 HTML 和 CSS 可以提供什么帮助——令人难以置信的是这些技术已经发展到了何种程度。
很棒的文章!我觉得使用更少的媒体查询现在更容易处理很多不同的环境。另外,说点什么容器查询。
顺便说一下,对于
max()
,我相信这应该写成(我想是复制粘贴错误)啊,是的!感谢提醒。:)
很棒的文章,David,感谢你的时间。是的,我们在开发网站时需要更多工具。
有一个问题,有没有在线工具可以根据这组新的响应式图片标签自动生成调整大小的图片和相应的 html 代码?
是的,这里。
Cloudinary 在优化图片方面做得很好。
嗨,Carlos,关于你的最后一个问题,你可以试试这个
https://responsivebreakpoints.com/
自动生成工具是一个好问题。不是答案,但我要提到我使用了 Google Chrome 开发工具中的 Lighthouse,并且基本上能够“按照指示”进行操作,并得到了图片元素,以及源媒体和图像变体,这些变体采用规定的格式和大小。我现在也在想是否有一种更好、更自动化的方式来做这件事。也就是说,我认为如果你还没有的话,先手动操作一下是值得的,就像我记得有人告诉我至少要手动做一次税务一样:)
这实际上是 imgix 非常适合处理的一种情况。它支持一系列 客户端库,这些库将自动为您生成
srcset
属性的代码。结合其动态图片渲染服务,您可以相当快地自动化生成响应式图片的整个过程。免责声明:我是 imgix 的工程师,并维护上述库。
这与内在式网络设计有很多重叠。我们将找出布局的工作尽可能地交给浏览器。
写得很好。很有帮助。好文章。
很有意思,我一定会将这些技术应用到我的代码中。
我是不是漏掉了什么?以下是如何有效的?
这是一篇很棒的文章。html 中有各种标签,您可以借助 css 创建最佳设计。
哇,我真的很喜欢这里的内容,我以前从未听说过这些 min max 和 clamp 函数,真的很感谢,先生,我有一个请求,请写一篇关于你所做的圆形文本的文章,我查看过的那些都不起作用,也许是我做错了什么,或者其他。
精彩的总结,非常感谢分享,David!
很棒的文章!谢谢。
也许是我一个人,但我找不到任何地方的 minmax() CSS 数学函数。它不在以下位置:https://www.w3.org/TR/css-values-4/#math-function,而且它也没有显示在 caniuse 中。只有 CSS Grid 规范显示了 minmax()。在 Chrome 开发工具中,它在与 width 一起使用时显示为无效属性。你能分享一下你找到它的官方规范页面吗?
很棒的文章!阅读这篇文章让我学到了很多。我几个月前开始学习前端开发,我正在努力熟悉最佳实践,所以这真的很有帮助!
感谢你的文章,David。我正在尝试将其翻译成 selfhtml.org(一个德国的网络知识资源),我正在为你的 min 和 max 描述而苦苦挣扎。
要么是我完全糊涂了,要么就是你糊涂了。min() 选择较小的值,因此,尽管函数名称如此,但 font-size: min(1rem, 22px) 在我放大时为字体定义了一个最大像素大小。但是如果我缩小,这将没有限制。max()(或 clamp())将在这里起作用。
而且 minmax() 在网格模板之外使用似乎是无效的 CSS。我用 Chrome 和 Firefox 尝试过,它们都拒绝了它。这是新东西吗?我个人认为你的例子
.box {
width : minmax( 600px, 50% ); /* 至少 600px,但绝不超过 50% */
}
可以这样写
.box {
width: max(600px, 50%);
}
“min() 函数指定元素可以缩小的绝对最小尺寸。” <– 我认为这个说法很令人困惑,因为我认为它不是对 min() 的准确描述。我的理解是,UI 元素可以缩小!并且增长!到你设置的绝对值。而 max() 允许元素缩小!并且增长!从你设置的绝对值开始。
width: min(50%, 300px) -> 这里 50% 可以是 0 到 300px 之间的任何值
width: max(50%, 300px) -> 这里 50% 可以是 300px 到最大视窗宽度的任何值。
所以总结来说,这是反直观的,因为 min 设置了最大值,而 max 设置了最小值。
希望有意义。
我需要 clamp,尽快!谢谢
很棒的文章!我一直都在想“不,我不能用这个,它还没有足够广泛的支持”,然后意识到我上次检查已经是 5 年前了!这将帮助我更新我的知识,谢谢!
我认为对于 min() 和 max(),一种说法是
min() -> 设置一个上限(它开始缩小的最大值)
max() -> 设置一个下限(它开始增长的最小值)
很棒的帖子!
这是一篇很棒的帖子!但是,我不太理解 clamp 函数的解释。当我在 devtools 中将 `font-size: clamp(1rem, 40px, 4rem)` 应用于此页面上的标题时,字体大小始终为 40px,因为 40px 是首选值。
从解释来看,它似乎应该是在 1rem 和 4rem 之间的范围。我使用它不正确吗?似乎首选值应该是相对单位,然后你可以在最小值和最大值上设置绝对单位。
感谢你的文章,大卫。以前没见过 clamp,很高兴知道。
不过,图片中的元素是否颠倒了。你的 `picture.png` 是默认的,而 `picture-lg.png` 用于更大的屏幕。如果你要对元素使用 `max-width`,那么它们应该从最小的宽度开始,并从那里增加大小。
由于浏览器会选择第一个匹配的元素,任何小于 1000px 的视窗都会选择 `picture-lg.png`,而忽略中等和小的选项。
所以,应该是这样吗
<img src=”picture.png” alt=”picture””>
您好,请问我可以将您的文章翻译成中文吗?我想与中国更多开发者分享。我会注明原作者和原文出处。
当然可以,请便!