CSS数学函数与响应式布局
CSS Values and Units Module Level 4 把 函数标记(Functional Notations)单独提取出来做为该规范的一部分,这部分包含了一些具有数学计算能力相关的属性值,比如 calc()
、clamp()
以及min()
、max()
,具备一定数学逻辑能力的开发者,灵活运用这一强大的功能可达到不一般的效果。接下来将以响应式布局这一维度,探索CSS数学函数在这一方向上如何发挥更好的作用。
calc()
calc() 此 CSS 函数允许在声明 CSS 属性值时执行一些计算。它可以用在如下场合:<length>、<frequency>, <angle>、<time>、<percentage>、<number>、或 <integer>。
calc()函数可用表达式作为它的参数,这个表达式可以是加法 +
,减法 -
,乘法 *
和除法 /
的任意组合。
表达式中的运算对象可以使用任意 <length>
值,可以在一个表达式中混用这类值的不同单位(比如混用rem和vw)。在响应式布局中常使用上视窗单位(vh
,vw
,vmin
和 vmax
),因为根据客户端的浏览器,视窗单位会自动重新计算,这意味着可基于视窗单位进行响应式的排版和布局。
calc()
在这4个函数中跨浏览器兼容性最好,有着较为广泛的用途。
缩放字体
通过 calc()结合媒体查询 可以实现响应式排版中样式在特定值区间平滑缩放:
$min_width: 400;
$max_width: 800;
$min_font: 12;
$max_font: 24;
:root { font-size: #{$min_font}px; }
@media (min-width: #{$min_width}px) and (max-width: #{$max_width}px){
:root {
font-size: calc( #{$min_font}px + (#{$max_font} - #{$min_font}) * ( (100vw - #{$min_width}px) / ( #{$max_width} - #{$min_width}) ));
}
}
@media (min-width: #{$max_width}px){
:root {
font-size: #{$max_font}px;
}
}
在这个demo中,限定字体大小为 12px 到 24px,且当设备宽度范围为从 400px 到 800px 区间时,字体大小随之平滑缩放:
上中下布局
calc()结合视窗单位可以用新的方式构建我们很常用的布局,比如带导航和页脚的上中下布局。
header, footer {
height: 50px;
}
.content {
height: calc(100vh - 100px);
}
在上面这个例子中,使用 calc()
获得视窗高度减去导航和页脚的高度,类似的可以用这种方式不用借助js就可以获得视窗宽度/高度减去固定长度的值。
clamp()
clamp() 函数的作用是把一个值限制在一个上限和下限之间,当这个值超过最小值和最大值的范围时,在最小值和最大值之间选择一个值使用。它接收三个参数:最小值、首选值、最大值。 clamp() 被用在 <length>、<frequency>、<angle>、<time>、<percentage>、<number>、<integer> 中都是被允许的。
限制字体缩放
这里常用的场景是当使用视窗单位对 font-size
赋值时,字体大小可以根据视窗大小灵活缩放调整,而结合 clamp()
可以限制字体不过于放大或缩小而影响整体的排版。
比如设置大标题 h1
:
h1 {
font-size: clamp(1.75rem, 4vw + 1rem, 3rem);
}
在这个例子中 1.75rem 和 3rem 为下限和上限,4vw 决定了字体的缩放程度,通常来说在响应式布局中推荐值为
4vw
或 5vw
。
缩放边距
在下面的demo中使用 calc()
设置响应式的边距,元素的边距为父元素宽度的5%,最小和最大边距分别为1rem和3rem。也可以使用视窗单位,比如 4vw
,适用于弹窗等组件或者对body设置padding值。
.element {
padding: 1.5rem clamp(1rem, 5%, 3rem);
}
这种方式设定padding,当父元素有更多空间时边距会更大,但有个最大值限制而不至于无限放大,相反则会边距更小,但有个最小值限制,比如若父元素为狭窄的一列仍有最小值1rem的边距。
min() 和 max(): 界定范围
max() 或者 min() CSS函数让你可以从一个逗号分隔的表达式列表中选择最大或者最小的值作为属性的值,可以用于以下场合 <length>, <frequency>, <angle>, <time>, <percentage>, <number>, 或 <integer> 。
min()
min()
函数和字面意思相反,实际上可以界定可变值的最大变化范围。具体来说,min()
可以对响应式的元素设定最大允许边界值。
比方说 width: min(80ch, 100vw)
,在较大的视窗下(实际尺寸 80ch 比 100vw 小)宽度会被设置成 80ch,相反当缩小视窗时(实际尺寸 80ch 比 100vw 大)宽度会被设置成响应式的尺寸 100vw,在这种场景下 min()
的实际作用是为元素的宽度设置了最大边界值。
限制容器缩放
上面设置宽度的例子很适用于容器布局,再结合运用 min()
函数可以嵌套基本数学运算这一特点,可以使容器内容左右有一定空间的填充:
.container {
margin: 0 auto;
width: min(80ch, 100vw - 2rem);
}
在更大的视窗下容器最多放大到 80ch
,相反当视窗缩小到这个宽度时,容器宽度也会随视窗大小变化而缩放成 100vw - 2rem
,同时保留 1rem
的padding空白填充。
限制背景图缩放
CSS数学函数大都可被运用于允许值为数值的属性,一个比较独特的场景是应用在 background-size
中。为了填充容器通常使用 cover
值去铺满整个节点区域,这时候如果想限制背景图的缩放就可以使用 min()
:
.container {
background-size: min(600px, 100%);
}
在这个例子中,
min()
被用于确保背景图不超过 600px 的同时,通过设置 100% 使之随着节点大小的变化而缩放。
max()
相反的,min()
可以界定可变值的最小变化范围。具体来说,min()
可以对响应式的元素设定最小允许边界值。
限制容器缩放区间
结合 min() 和 max() 可以用一行代码限制宽度缩放的范围:
width: min(max(300px, 70vw), 500px);
上面👆这行代码告诉浏览器设置宽度为70vw,但同时不能小于300px或者大于500px。总结来说可以这样限定范围:
min(max(minN, midN), maxN)
minN
为限定的最小值,midN
为中间值,maxN
为限定的最大值。这一行代码实际上这也等效于使用 min-width
和 max-width
:
min-width: minN;
max-width: maxN;
width: midN;
总结
随着响应式布局在设计领域的发展和日趋完善,CSS技术也在日益进步,为开发者提供越来越多的能力和便利,希望以上的这几个CSS函数运用的例子可以激发大家的灵感,优化响应式布局的写法。
参考
Practical Uses of CSS Math Functions: calc, clamp, min, max | Modern CSS Solutions
Generating font-size CSS Rules and Creating a Fluid Type Scale | Modern CSS Solutions
A guide to the min(), max(), and clamp() CSS functions - LogRocket Blog