无需媒体查询即可构建您的响应式网站

2025-05-24

无需媒体查询即可构建您的响应式网站

谈论 Web 开发时,我们离不开响应式设计。响应式设计如今已成为必需,每个人都会使用媒体查询来构建响应式网站。

自媒体查询 (2000 年之前) 引入以来,CSS 不断发展。如今(2021 年),有很多技巧可以帮助您大幅减少媒体查询的使用,并创建优化的代码。我甚至会向您展示如何仅用一个 CSS 声明来替换多个媒体查询。

PS:由于嵌入式版本非常小,您必须在 DEV 之外运行所有示例才能更好地查看结果


我将从广泛使用但仍然有限的简单示例开始:

flex&flex-wrap

演示https://codepen.io/t_afif/pen/zYNggoq

flex: 400px将设置一个等于 的基本宽度400px。如果 没有足够的空间,项目将会换行400px。它们会扩大以填充空白处,如果容器宽度大于 ,则会缩小400px

✔️ 易于使用,只需 2 行代码
❌ 我们无法控制项目何时换行
❌ 我们无法控制每行的项目数量
❌ 最后一行的项目将具有不同的宽度


auto-fit&minmax

演示https ://codepen.io/t_afif/pen/wvgVVPN

与前面的示例类似,repeat(auto-fit,minmax(400px,1fr))将定义基本宽度,并且我们将具有类似的包装行为。

✔️ 易于使用,只需 1 行代码
✔️ 最后一行的项目将保持相同的宽度
❌ 我们无法控制项目何时换行
❌ 我们无法控制每行的项目数量
❌ 我们没有 flexbox 的收缩效果,因此我们可能会面临溢出


我们将尝试使用一些 CSS 技巧来优化上述示例,以克服缺点。


控制项目数量

在我们的第一个例子中,让我们改为flex: 400pxflex: max(400px, (100% - 20px)/3)调整屏幕大小,您会注意到每行不会超过 3 个项目(即使对于较大的屏幕宽度)。

演示https://codepen.io/t_afif/pen/abpeeeV

逻辑很简单。当屏幕宽度增加时,100%/3会大于 ,400px所以会使用最大值。如果所有项目的宽度都等于 ,那么每行不能超过 3 个项目100%/3

这到底是什么鬼20px??

这是我们定义的间隙的两倍。如果是 3 个项目,间隙就是 2 个;如果是 N 个项目,间隙应该为max(400px, (100% - (N - 1)*gap)/N)

我们仍然可以优化公式以消除间隙并使用max(400px, 100%/(N + 1) + 0.1%)。我们告诉浏览器每个项目将等于每行的项目100%/(N + 1)N + 1,但我们添加了一个很小的百分比(0.1%),因此其中一个项目将换行,最终N每行仅包含项目!

演示https://codepen.io/t_afif/pen/wvJwzbL

✔️现在我们可以控制每行的最大项目数。

同样的方法也可以应用于 CSS 网格示例:

演示https://codepen.io/t_afif/pen/BaWBLge

我添加了 CSS 变量来轻松控制不同的值。


控制收缩效果

使用 CSS 网格时,如果基本宽度大于容器宽度,则可能会出现溢出,这与 Flexbox 不同,在 Flexbox 中,我们有flex-shrink

为了克服这个问题,我们max(400px, 100%/(N + 1) + 0.1%)改为clamp(100%/(N + 1) + 0.1%, 400px, 100%)

  • 对于较大的屏幕宽度,100%/(N + 1) + 0.1%将会大于400px并且我们将获得最大项目数。
  • 对于较小的屏幕宽度,100%将小于400px并且我们的项目将不会超过容器宽度。

演示https://codepen.io/t_afif/pen/ZEezBGL

✔️ 我们有收缩效果,不再溢出


控制包裹

在前面的所有例子中,我们无法控制换行。我们不知道它何时会发生。这取决于底部宽度、间隙、容器宽度等。

为了控制这一点,我们将改变我们的基准宽度(400px)以(400px - 100vw)*1000获得以下内容

clamp(100%/(N + 1) + 0.1%, (400px - 100vw)*1000, 100%)
Enter fullscreen mode Exit fullscreen mode

这看起来有点奇怪,但很容易理解。100vw是我们的屏幕宽度,从逻辑上讲,这个值会随着屏幕大小的调整而变化,而400px保持不变。这将引出以下逻辑:

  • screen width (100vw) > 400px差值为负时,它将被限制为100%/(N + 1) + 0.1%正值:每行有 N 个项目

  • screen width (100vw) < 400px差值为正时,我们将其乘以一个大值(1000),以便将其限制在100%:每行有 1 个项目

演示https://codepen.io/t_afif/pen/BaWBQqK

我们进行了第一次媒体查询!

我们无需使用任何 CSS 声明,只需一个 CSS 声明,就能从 N 列移动到 1 列。我们的基础宽度已成为一个断点。@media

✔️ 我们可以控制项目何时换行
✔️ 我们可以控制每行的项目数量


那么从 N 列移动到 M 列怎么样?

我们只需clamp()像下面这样更新我们的函数:

clamp(100%/(N + 1) + 0.1%, (400px - 100vw)*1000, 100%/(M + 1) + 0.1%)
Enter fullscreen mode Exit fullscreen mode

我想现在大家都明白这个窍门了。当屏幕宽度大于时,400px我们遵循第一条规则(每行 N 个项目)。当屏幕宽度小于时,400px我们遵循第二条规则(每行 M 个项目)。

演示https://codepen.io/t_afif/pen/ZEezBgo

我们可以轻松控制每行项目的数量,并决定何时更改该数量。所有这些只需一个 CSS 声明即可实现!


那么从 N 列移动到 M 列再移动到 1 列怎么样?

我们可以通过嵌套clamp()如下函数来实现这一点:

clamp(clamp(100%/(N + 1) + 0.1%, (W1 - 100vw)*1000,100%/(M + 1) + 0.1%), (W2 - 100vw)*1000, 100%)
Enter fullscreen mode Exit fullscreen mode

我们有两个断点,因此从逻辑上讲我们需要两个宽度(W1W2)。

我们可以看到我们的函数是这样的:

clamp(clamp( .. ), (W2 - 100vw)*1000, 100%)
Enter fullscreen mode Exit fullscreen mode
  • 当屏幕宽度小于W2我们陷入100%:每行一个项目
  • 当屏幕宽度大于W2我们进入第一个clamp():我们在那里执行逻辑
    • 当屏幕宽度小于W1我们陷入100%/(M + 1) + 0.1%):每行 M 个项目
    • 当屏幕宽度大于W1我们陷入100%/(N + 1) + 0.1%):每行 N 个项目

让我们来看一下实际效果:

演示https://codepen.io/t_afif/pen/xxqKgZe

我们只用一个 CSS 声明就完成了 2 个媒体查询!不仅如此,我们还可以轻松地使用 CSS 变量调整该声明,这意味着我们可以轻松地更新不同容器的逻辑。

演示https://codepen.io/t_afif/pen/mdWbRRE

到现在为止有多少个媒体查询?好吧,我停止计数了……

想要更多断点吗?只需嵌套另一个clamp()函数即可

从 N 列到 M 列到 P 列到 1 列

演示https ://codepen.io/t_afif/pen/bGqbgYY

我们有响应式设计,无需任何单一媒体查询

✔️ 仅一行代码
✔️ 使用 CSS 变量轻松更新
✔️ 我们可以控制每行的项目数
✔️ 我们可以控制项目何时换行
✔️ 小屏幕上不会溢出
✔️ 所有项目都有相同的宽度
✔️ 每个容器都可以有自己的断点


容器查询

每个人都很高兴使用这个新功能,它考虑元素的宽度而不是屏幕来创建媒体查询,但无需等待它。

我编写的技巧已经涵盖了此功能。我们只需将其更改100vw100%,之前编写的所有逻辑现在都将考虑容器宽度而不是屏幕宽度。

调整以下容器的大小,看看其中的魔力

演示https://codepen.io/t_afif/pen/gOmYmgz


奖金

我将以最后一个技巧来结束这篇文章,该技巧允许您在不使用媒体查询的情况下更改项目的颜色。

div {
  background:
   linear-gradient(purple 0 0) 0 /calc(var(--w3) - 100vw) 1px,
   linear-gradient(blue   0 0) 0 /calc(var(--w2) - 100vw) 1px,
   linear-gradient(green  0 0) 0 /calc(var(--w1) - 100vw) 1px,
   red;
}
Enter fullscreen mode Exit fullscreen mode

我们考虑 3 个渐变层加上一个background-color。每个渐变的大小由其中一个断点定义。如果calc()为负数,则渐变将不显示。如果calc()为正数,则大小也将为正数,并且由于重复特性,它将覆盖所有区域。

顺序非常重要。下表可以帮助您更好地理解:

[0 W3[ [W3 W2[ [W2 W1[ [W1 无穷大[
✔️紫色 ❌紫色 ❌紫色 ❌紫色
✔️蓝色 ✔️蓝色 ❌蓝色 ❌蓝色
✔️绿色 ✔️绿色 ✔️绿色 ❌绿色
✔️红色 ✔️红色 ✔️红色 ✔️红色

始终显示红色,并且在每个断点处都会显示一个覆盖底层的渐变色。

以下是包含所有功能的演示。全屏运行并调整大小:

演示https ://codepen.io/t_afif/pen/wvJwdRW

为了使着色根据容器宽度起作用,我们稍微更新了代码,并使用了相对于容器定位的伪元素,并剪辑了溢出

演示https ://codepen.io/t_afif/pen/zYZOwQJ

与 Stack Overflow 相关的问题中,我使用了这样一个技巧:如何根据元素的高度或宽度更改其颜色<div>?我还根据宽度或高度更改了文本颜色和边框。


就是这样!

现在,您掌握了一个绝妙的技巧,它允许您在不使用媒体查询的情况下,仅用几行代码即可控制响应式布局。当然,这并不是媒体查询的替代品。这只是一项优化,可以帮助您减少代码量。


给我买杯咖啡

或者

成为赞助人

文章来源:https://dev.to/afif/build-your-responsive-website-without-media-query-omj
PREV
我带着 100 个“黑暗模式” CSS 加载器回来了,我的天啊😳
NEXT
另外 100 个下划线/叠加动画 | 扩展的 CSS 集合 🥇🥈