CSS 比较函数构建响应式UI

特别声明:如果您喜欢小站的内容,可以点击申请会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)

在 CSS 中说起函数,我想很多人首先想到是 calc() 数学运算函数,其实在 CSS 中有很多种不同类型的函数,有些“CSS函数”可以在CSS中用于动态计算,比如 calc()函数,计数器函数 counter()counters()CSS比较函数 min()max()clamp()。尤其是 calc()min()max()clamp() 这几个函数,在现代Web开发中所起的作用越来越大,使用的场景越来越多,带来的灵活性和扩展性越来越强。那么在这篇文章中,我们主要和大家一起来探讨 CSS 比较函数在实际开发中能用在哪些地方?又是如何帮助前端构建响应式UI?感兴趣的同学请继续往下阅读。

你需要准备的知识

在这篇文章中,我们并不会详细介绍这些函数(calc()min()max()clamp())的基础理论,但如果你想更顺畅的了解它们在实战的功能以及不阻碍你往下阅读和实际使用,你需要具备一些有关于它们的基础知识。如果你从未接触这些领域,建议你先花一点时间阅读下面这几篇文章:

除此之外,我们接下来的内容会用到很多关于 CSS 自定义属性相关的知识,你可以阅读《图解CSS:CSS自定义属性》一文,或者点击这里了解更多关于 CSS 自定义属性

要是你不想花时间去深入了解上面提到的这些 CSS 特性,那就请花几分钟时间快速了解一下。

先来看最早在 CSS 中可用于计算的 calc() 函数。

calc() 将允许你在用于 CSS 尺寸属性的值进行基本的数学运算,比如给 width 的值做 加(+减(-乘(×除(÷ 四则运算。并且可以在单位之间做插值计算,比如不同单位之间的混合计算,如 calc(100% - 20px),运算式中的%px 单位,客户端会自己进行插件计算。

calc() 最大的好处是允许你避免在 CSS 硬编码一系列神奇的数字或使用 JavaScript 来计算所需的值。特别是在 CSS 自定义属性的使用中,calc() 的身影随处可见。比如下面这个示例,使用 calc() 将一个数值变成带有% 的值:

:root { 
    --h: 180; 
    --s: 50; 
    --l: 50; 
} 

.icon__container { 
    color: hsl(var(--h) calc(var(--s) * 1%) calc(var(--l) * 1%)); 
}

.icon__container--like {
    --h: 232;
}

而比较函数 min()max()clamp()calc() 类似,除了可以接受 加(+减(-乘(×除(÷ 四则运算之外,还可以接受一个值列表参数,浏览器则会从这个值列表中确定使用哪个值。

  • min(<value-list>):从逗号分隔的表达式列表中选择最小值(最小负数),相当于 使用 min() 设置最大值
  • max(<value-list>):从逗号分隔的表达式列表中选择最大值(最大正数),与min()刚好相反,相当于 使用 max() 设置最小值
  • clamp(<min>, <ideal>, <max>):根据设定的理想值(<ideal>),将值限定在上限(<max>)与下限(<min>)之间,相当于 使用了 min()max() 函数, 即 clamp(<min>, <ideal>, max) 等于 max(<min>, min(<ideal>, <max>))

我分别给 min()max()clamp() 录制了一个视频,可以从视频中窥探出它们带来的作用:

视频录自于 min() Function

视频录自于 max() Function

视频录自于 clamp() Function

有关于 min()max()clamp() 更详细的介绍可以阅读:

虽然 min()max()clamp() 看上去和 calc() 相似,都可以在允许使用 <length><frequency><angle><time><percentage><number><integer> 值类型的属性上使用,并且进行基础的数学运算。但它们有着一个本质的区别:

min()max()clamp()函数中的参数,计算的值取决于上下文

简单地说:

  • calc()执行基本的数学运算,具有在单位类型之间的插值能力
  • min()允许以包含元素的响应环境的方式设置最大允许值的界限
  • max()允许以包含元素的响应环境的方式设置最小允许值的界限
  • clamp() 允许在可接受的数值范围内设置界限

这些函数给开发者提供更为强大的动态控制能力,也将允许你使用它们创建更具动态性和响应性的网站或应用程序。接下来,我们通过一些实例来体验他们强大的能力。

案例

在《下一代响应式Web设计:组件驱动式Web设计》一文中深度的探讨了 CSS 容器查询特性可以让我们在微观上改变组件样式。更为响应式Web设计带来新的理念。另外,时至今日,CSS 已经发展到有很多新特性(《2022 年的 CSS》)可以让开发者更容易构建动态响应的Web了。甚至这些新特性允许我们只用一行代码就可以实现以往需要多个代码块才能实现的效果。

为此,我们就从布局的案例开始。

布局响应

现代Web布局中,常常基于 CSS 的 FlexboxGrid 来布局,但不管是使用哪种布局技术,都离不开对元素的尺寸设置(会涉及到 CSS 盒模型相关属性)和 值单位的运用等。也就是说,我们在布局中总是少不了对尺寸进行计算。在没有这些 CSS 函数之前,我们需要使用 JavaScript 来动态计算,但有了这些函数特性,让你布局更为灵活。

我们先从两列布局开始。

假设你有一个两列布局,侧边栏宽度是 220px 和 自适应的主内容区域:

关键代码如下:

:root {
    --aside-w: 220px;
    --gap: 20px;
}

body {
    display: flex;
    flex-wrap: wrap;
    gap: var(--gap);
}

aside {
    flex-basis: var(--aside-w);
    flex-shrink: 0;
}

main {
     flex:1 1 calc(100% - var(--aside-w) - var(--gap));
}

示例中在 flex-basis 中使用 calc() 计算赋值,即使不赋值 main 也会因 flex-shrinkflex-grow 做自适应匹配。我们显式设置该值是因为,在Flexbox布局中设置 Flex 项目的尺寸时有一个隐式的公式存在:

contentwidthflex-basis

意思就是,如果未显式指定flex-basis的值,那么flex-basis将回退到width属性;如果未显式指定width,那么flex-basis将回到基于Flex项目内容的计算宽度。 有关于这方面更详细的介绍,你可能要花一些时间阅读:

效果看上去符合我们的预期,但事实未必。如果你尝试着把浏览器视窗尺寸调小,你会发现在窄屏的时候,布局效果差强人意:

我们希望,在窄屏的时候效果如下:

如果你对 Flexbox 较为熟悉的话,你可以已经想到了,可以在 aside 元素上显式设置 flex-grow 值为 1,可以让 Flex 项目根据 Flexbox 容器剩余空间进行扩展。

aside {
    flex: 1 0 var(--aside-w);
}

main {
    flex: 1 1 calc(100% - var(--aside-w) - var(--gap));
}

我们可以在这个基础上做得更好,可以给 main 设置一个最佳的值,比如:

main {
    flex: 1 1 calc(100% - var(--aside-w) - var(--gap));
    min-width: min(100%, 18ch);
}

min-width 属性上使用 min() 设置了下界面,根据上下文环境计算,当18ch长度值小于100%(父容器宽度的100%,),min()会取18ch,反之则会取100%

我们先来看未设置 min-width 的效果:

加上min-width:min(100%, 18ch) 之后的效果:

CSS中取值为 % 时,它的计算依赖于上下文环境,即不同属性取%值时,计算时参照物(相对属性)不同。如果你对这方面知识感兴趣的话,可以移步阅读《CSS中百分比单位计算方式》一文。另外,ch 单位是一个近似等宽的一个单位,它基于字体0字形宽度计算,它会随字体和字号变化,相关的介绍可以查阅《图解CSS:CSS 的值和单位》一文。

如此一来,你的布局不会那么容易被打破,具有较强的动态性和响应性,而且还不需要依赖任何的 JavaScript 脚本和 CSS媒体查询(或其他的条件查询)。这也就是在《如何编写防御式的 CSS》所提到的,构建具有防御式的CSS。

aside(侧边栏)的 flex-basis 同样可以使用 min()max() 函数对其宽度做一个尺寸的界限设置,比如:

aside {
    flex-basis: max(30vw, var(--aside-w));
}

当视窗的宽度达到 1068px 左右的时候,30vw 的值才大于 --aside-w,即只有视窗宽度大于 1068pxmax() 才会取 30vw,否则会取 --aside-w 的值(320px)。

你可能已经想到了,在 flex-basis 上也可以使用 clamp() 函数来设置值,答案确定的,但我们把 clamp() 用于布局中的使用放到后面来介绍。

在现代Web的布局中除了 Flexbox 之外还有 CSS Grid 布局(CSS Grid用于布局的灵活度是你不可想象的,在2022年,你已经很有必要开始学习 CSS Grid 相关的知识了)。如果你阅读过《网格轨道尺寸的设置》和《网格中的可用函数》的话,你已经知道了,我们可以使用 min()max()clamp() 以及

剩余80%内容付费后可查看

如需转载,烦请注明出处:https://www.w3cplus.com/css/practical-uses-of-css-math-functions-calc-clamp-min-max.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部