无需媒体查询即可构建您的响应式网站
谈论 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: 400px
。flex: 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%)
这看起来有点奇怪,但很容易理解。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%)
我想现在大家都明白这个窍门了。当屏幕宽度大于时,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%)
我们有两个断点,因此从逻辑上讲我们需要两个宽度(W1
和W2
)。
我们可以看到我们的函数是这样的:
clamp(clamp( .. ), (W2 - 100vw)*1000, 100%)
- 当屏幕宽度小于
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 变量轻松更新
✔️ 我们可以控制每行的项目数
✔️ 我们可以控制项目何时换行
✔️ 小屏幕上不会溢出
✔️ 所有项目都有相同的宽度
✔️ 每个容器都可以有自己的断点
容器查询
每个人都很高兴使用这个新功能,它考虑元素的宽度而不是屏幕来创建媒体查询,但无需等待它。
我编写的技巧已经涵盖了此功能。我们只需将其更改100vw
为100%
,之前编写的所有逻辑现在都将考虑容器宽度而不是屏幕宽度。
调整以下容器的大小,看看其中的魔力
演示: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;
}
我们考虑 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>
?我还根据宽度或高度更改了文本颜色和边框。
就是这样!
现在,您掌握了一个绝妙的技巧,它允许您在不使用媒体查询的情况下,仅用几行代码即可控制响应式布局。当然,这并不是媒体查询的替代品。这只是一项优化,可以帮助您减少代码量。