你可能不再需要媒体查询

2025-05-25

你可能不再需要媒体查询

在 Webbe 开发™️ 的旧时代,如果我们想要创建响应式网站和应用程序,就意味着要根据特定的设备断点编写一系列媒体查询,并针对每种尺寸重新设计内容(有人在评论中说, Web 开发真正的旧时代是基于表格的布局——我记得那种布局,而且它们也很糟糕)。CSS 框架(Bootstrap、Skeleton 等)介入以简化设备断点绘制点,因为编写所有这些框架的工作量非常大!慢慢地,随着越来越多各种形状和尺寸的设备出现,我们看到编写媒体查询的最佳实践(必然)从基于设备的断点转变为基于内容的断点。现在,屏幕几乎可以支持任何你能想象到的尺寸,是时候再次改变我们的方法了——断点时代已经结束,流体设计时代已经到来。我们的内容应该始终根据可用空间的大小进行调整,而不是到达某个点然后捕捉到新的布局。

值得庆幸的是,CSS 从那时起也取得了长足的进步,但我们很多人习惯于仅仅添加一个或五个媒体查询来实现响应式布局,并且从未彻底改掉这个习惯。现在我们有了诸如、、、、、、、、等等现代 CSS 功能grid时候抛弃媒体查询了。在本文中flexbox,我们将从最顶层开始,从宏观显示格式一直vhvw最小单元。至于你的旧样式表……我们可以重构。我们有技术。calcclampminmaxaspect-ratio

总体情况:网格和弹性框

让我们从一些最流行的响应式显示选项grid和开始flexbox。它们已经存在一段时间了,分别grid在2017年和flexbox2013年获得了浏览器的全面支持,但很多人仍然不完全理解它们之间的区别,或者不知道什么时候应该使用其中一种(或者两种都用!)。很多人错误地认为两者等同,这可能会导致在选择工具时陷入非此即彼的误区——而实际上,它们不仅有着截然不同的用例,而且可以(也应该)一起使用,互相补充!

不过,为了我们的目的,让我们关注它们的工作原理,以及如何使用它们来处理页面上元素的布局,以便实现自然包装和响应调整,而无需使用媒体查询。

网格

grid主要专注于创建一个包含多行多列的网格,并可在其中填充元素。您可以通过创建一个容器<grid>元素,然后用子元素填充它来实现。您可以对网格的行、列和单元格进行大量的自定义,从而创建出您能想象到的简单或复杂的网格。

但为了创建简洁、响应式的设计,我们先来看看最相关的功能。网格具有自动重复列或行的功能,以及auto-fit自动调整列大小以适应可用空间的功能。例如,以下代码:

 .grid {
   display: grid;
   grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); 
  }

--- 

<div class="grid">
  <div></div>
  <div></div>
  <div></div>
</div>
Enter fullscreen mode Exit fullscreen mode

在这种情况下,网格会将您的内容转换为自然适合您所拥有空间的列,每列的最小宽度至少为300px,最大宽度不超过1fr1fr是一个新的 CSS 单位,代表分数,它告诉浏览器均匀划分空间并为每列分配该空间的一小部分。在这种情况下,它将创建三个相等的列,每列占用可用空间的 1/3,但绝不会小于 300px。如果我们添加另一个 div,或者拿走一个,网格会自动处理计算并调整显示。如果屏幕太小,无法同时并排显示所有列,它会自动将剩余的列换到下一行。

如果您希望使用网格创建更复杂的布局,这里有一些我最喜欢的参考资源:

弹性盒子

flexbox采用类似(但不完全相同)的方法帮助您在页面上布局元素并根据需要自动调整它们。然而,它并非创建包含多行多列的完整网格,flexbox而是关注子元素在父元素中的相对位置。简单来说:如果您需要同时在两个方向(行和列)上工作,请查看网格。如果您需要专注于一个方向(单行或单列),那么这就是您需要的flexbox

同样,关于何时使用它们以及它们在实际应用中有哪些区别,还有很多需要注意的地方,不过我们留到另一篇文章再讨论吧。现在,我们先来关注一下 Flexbox 是如何处理响应式布局的,这样你就可以省去那些不必要的媒体查询了。

最值得关注的是 属性flex-wrap。Flex 会首先尝试将您写入的所有内容放入一行或一列,但如果这行不通,您可以通过设置为 来告诉 flex 允许换行flex-wrapwrap如果flex-wrap没有指定 ,flex 会挤压元素以使它们保持在同一行(如果min-width为子元素指定了 ),或者允许它们溢出视图(如果min-width指定了 )。

.flex {
  display: flex;
  flex-wrap: wrap;
}

.flex > div {
    width: 300px
}

--- 

<div class="flex">
  <div></div>
  <div></div>
  <div></div>
</div>
Enter fullscreen mode Exit fullscreen mode

基本上,无论使用网格还是弹性布局,你只需要决定内容是收缩还是包裹,然后相应地设置属性即可!两者都是创建响应式 UI 的好工具。

如果您正在寻找一些资源来掌握 Flexbox,以下是我最喜欢的一些资源:

  • Flexbox Froggy:一个有趣的游戏,通过一些可爱的青蛙插图来帮助您掌握所有不同属性的作用。
  • FLEX:一个简单、直观的备忘单,供您在工作时参考!

中间路线:CSS 属性

一旦我们确定了总体布局,就该为元素设置一些特定的属性了——好消息是,这里也不需要媒体查询!

长宽比

你知道吗?CSS 中有一个专门针对宽高比的属性。如果你要处理视频或大型图片,保持正确的宽高比至关重要,那么这个属性就非常有用。CSS技巧 上有一个很棒的深度讲解,但总的来说,它使用起来相当简单——你只需要一行代码:

  .video-wrapper { aspect-ratio: 16/9; }
Enter fullscreen mode Exit fullscreen mode

width如果您同时设置了和aspect-ratio,那么它将以此为基础自动生成height匹配的值(反之亦然)。但是,如果您同时声明了 awidth和 a height,它将优先于aspect-ratio,所以请谨慎操作!

最小高度、最大高度、最小宽度和最大宽度

虽然在许多情况下,最小和最大高度和宽度属性可以用函数替换clamp()(我们将在下一节讨论),但它们仍然是有效的 CSS,值得随身携带。它们也很简单,因为它们的作用几乎与字面意思完全一致:

.img {
  width: 100%; 
  max-width: 50%;
  min-width: 200px; 
}
Enter fullscreen mode Exit fullscreen mode

这里,我们首先要告诉一张图片,它会占据尽可能多的可用空间,直到max-width达到默认的最大图片尺寸。然后,我们给它一些导轨——我们不希望它占据超过容器一半的空间,但我们也希望确保它仍然大于邮票,所以我们也不希望它小于宽度200px。在这种情况下,我们只在小的一端设置一个绝对值,因为我们确切地知道在图像变得无法识别之前可以变得多小。现在,无论浏览器如何调整大小,我们都知道我们的图像将始终尽可能大……既不会大得离谱,也不会小到难以阅读。

功能齐全:数学函数

数学函数是 CSS 的新特性,功能强大。它们填补了 CSS 开发者长期以来抱怨的空白——在样式表中计算值并设置属性范围。你越早掌握它们并在代码中使用它们,受益就越大!

夹钳()

clamp()允许我们设置属性的基值,以及上下限值,以便在调整时限制其大小。这是我们摆脱媒体查询的最佳工具之一,因为它允许我们设置响应式限制,而无需定义特定的断点。它的工作原理如下:

.img {
  /* the format is `clamp(min value, base value, max value)` */ 
  width: clamp(200px, 100%, 50%);
}
Enter fullscreen mode Exit fullscreen mode

这是我们上一个示例的更新版本——具有最小和最大宽度的图像。只是在这里,我们用一行代码来实现,clamp()即告诉图像占用100%可用空间,但不会大于容器大小的一半,也不会小于200px宽度。

计算()

如果你曾经看过 CSS,并希望它能提供更多数学运算功能,calc()那么这个工具非常适合你。它允许我们在样式表中直接使用 CSS 单位进行简单的算术运算。当你需要根据非绝对单位来设置某些内容时,这非常有用。你还可以在计算中使用 CSS 变量,以获得更大的灵活性!假设我们要创建根据浏览器当前宽度均匀划分的列:

.child { width: calc(100vw / 3); }
Enter fullscreen mode Exit fullscreen mode

由于整个 .333 重复的情况,使用百分比单位设置 1/3 宽度很困难 - 但现在,我们可以说“你知道吗,CSS -来处理它!”在这里,我们取整个窗口的宽度,将其除以三,然后将其设置为子元素的宽度属性。

min() 和 max()

如果您希望样式表能为您处理尽可能多的决策,请输入min()max()。它们的工作原理与 类似clamp(),但它不是在两个方向上设置范围,而是一次只关注一个方向,这样我们就可以根据数学计算结果设置最小值(或最大值)。同样,这是一个处理非固定值非常有用的工具,而非固定值是创建响应式内容时必须经常做的事情之一。

.img1 { width: min(30%, 200px) }

.img2 { width: max(50vh, 800px) }
Enter fullscreen mode Exit fullscreen mode

在这种情况下,我们要设置两个不同图像的宽度 - 一个我们希望保持较小,另一个我们希望保持较大。min()将评估是否200px大于或小于30%当前容器并选择最小的值。将在max()之间进行相同的比较并自动选择较大的值。50vh800px

所有小事:CSS 单位

在布局页面元素时,我们需要从宏观角度来思考问题,这固然很好,但我们也不能忘记那些小家伙——那些指定各种属性大小的单位。当我们用像素之类的硬性单位设置所有内容时,每次需要调整大小时,我们都必须手动调整。但是,当我们使用响应式单位时,我们就可以让它为我们完成这项工作!

vw 和 vh

我最喜欢和最常用的两个响应式 CSS 单位是vhvw—— 视口宽度和视口高度。虽然没有百分号,vh但 和vw确实是一种基于百分比的测量单位——1vw是视口宽度的 1%。

window.innerWidth过去,我们不得不通过和获取视口测量值window.innerLength(再次强调,那段黑暗岁月)的日子已经一去不复返了;现在,我们可以在样式表中自动获取它们。当用户调整窗口大小时,它们也会自动更新,因此无需再费力费力。vh这对于需要垂直居中或将某些内容固定在视口底部的情况尤其有用。因此,要创建一个始终与用户当前浏览器高度和宽度完全相同的容器元素,您只需:

.page-wrapper {
   height: 100vh; 
   width: 100vh; 
}
Enter fullscreen mode Exit fullscreen mode

rem 和 em

rem如果您仍在使用像素定义字体大小,那么让我来向您介绍一下单位的美妙之处em。单位的名称em实际上源自古老的印刷测量标准,基于字体中字母 M 的宽度(这也是 em-dash 和 en-dash 的由来——破折号等于 M 或 N 字符的宽度)。em单位是一种相对于父元素字体大小定义字体大小的方法。因此,您可以这样做:

.h2 { font-size: 2.5em } 
Enter fullscreen mode Exit fullscreen mode

这会将 h2 标题设置为父元素中正文字体大小的 2.5 倍。

rem另一方面,允许您声明相对于整个页面根字体大小的字体大小。事实上,R 代表的就是这个意思——根字体大小。rem和 的em工作方式相同,区别在于它们使用的基准大小和缩放比例。总的来说,我更倾向于使用rem大于em,因为我喜欢它所创造的一致性,但如果您想在某个区域创建与整体风格不同的特定设计,em大于 才是您想要的。

如果您正在寻找一个巧妙的技巧,您可以结合vw并为remclamp()的应用程序创建流体排版系统:

p { font-size: clamp(1rem, 2.5vw, 2rem); }
Enter fullscreen mode Exit fullscreen mode

在这里,我们将基本字体大小设置为2.5vw(记住它等于视口宽度的 1%),然后在两侧设置最小值和最大值,以确保您不会遇到文本变得难以阅读的小的情况或文本不断变大的1vw情况

百分比

最后,同样重要的是,不起眼的百分比单位。如果您出于某种原因要手动设置宽度(而不是使用grid或 之类的布局工具flex),那么您几乎肯定会想要使用 ,%而不是任何绝对测量单位。

.container { width: 25%; }
Enter fullscreen mode Exit fullscreen mode

你可能并不需要这个例子,但为了以防万一——这里我们设置了一个元素的宽度为其父元素的 1/4。当父元素的宽度发生变化时,这个元素也会自动调整。没错,这很简单,但却是构建响应式 UI 的基础。

结论

如果您仍然主要依赖媒体查询来确保您的网站或应用完全响应,那么现在或许是时候了解一下 CSS 提供的所有功能,看看能否将一些老式的断点替换为一些全新的流畅样式方法。努力创建完全流畅的布局意味着用户在移动设备和桌面设备之间切换时,可以减少剧烈的更改,同时也能减少您的维护工作——无需在设计发生变化时更新每个断点。利用这些自适应样式方法,准备好顺应潮流吧!

文章来源:https://dev.to/kathryngrayson/you-probabilly-dont-need-media-queries-anymore-a4j
PREV
万事通还是一技之长?
NEXT
Figma 开发者版