前言
大概五月份的时候,我下定决心写自己的博客系统,于是断断续续花了近一个月的时间琢磨Nestjs,写完了接口部分。六月份因为工作的原因就搁置了,说来也惭愧,直到九月中旬,才将它拾起。半个月后,后台部分基本功能完成,开始着手写网站。
一股脑儿又写了半个月,基础功能,自动化部署都顺利完成,自我感觉很棒。然而,当我使用手机浏览网站时,总是出现一些不该出现的布局问题。于是我写了一堆媒体查询代码,想要快速解决这个bug,却陷入了无尽的调试环节,这让我感到无比烦躁。这时我才意识到,要想同时兼容pc端和mobile端,远比我想象的要难。
我尝试着从网上寻求解决方案,经过一通搜索,查证,实践,并没有找到自己特别钟意的方案。在这中间,有一篇文章里写道:“兼容pc端和mobile端只有两种办法,一是写两套CSS,二是拆成两个项目独立维护”。分为两个独立项目在前期推进是比较缓慢,但是对后续维护比较友好,对此我深信不疑,深思熟虑之后,我决定采用第二种办法。
工作之余又写了几天,越发觉得哪不对劲,仿佛做了无用功。因为这个博客系统本身相对单一,功能并不多,如果要分为两个子项目,将会产生许多冗余代码,于是我索性关掉vs-code,重新整理思绪。功夫不负有心人,经过漫长地挖掘,总算是找到了较为理想的解决方案。
工欲善其事必先利其器。
基本原理
首先有三个概念必须掌握。
vw:视口单位,通常来说,100vw等于浏览器可见宽度。
rem:CSS布局单位,1rem等于html标签的font-size属性值大小。
CSS locks:利用CSScalc函数,给定使用该函数的属性最小值和最大值,动态计算出该属性在规定的屏幕最小尺寸和最大尺寸区间内,适应当前屏幕大小的属性值。在Flexible typography with CSS locks一文中,作者详细阐述了CSS locks的由来,推荐查阅。
先看案例:
p {
font-size: 16px; /* 最小字体 */
}
@media screen and (min-width: 400px) {
/* 屏幕宽度大于400px,大于640px时,采用CSS locks */
p {
font-size: calc(16px + (20 - 16) * ((100vw - 400px) / (640 - 400)));
}
}
@media screen and (min-width: 640px) {
/* 屏幕宽度大于640px */
p {
font-size: 20px; /* 最大字体 */
}
}
复制代码
利用以上CSS代码,我们就可以做出类似效果:
从图中可以发现,文章段落的font-size属性值随着屏幕大小改变而发生有规律的变化,这种变化使得在不同尺寸的设备上,也不会减小文章的可读性。而事实上,CSS locks 令人惊叹的地方也不止于此,我们完全可以将它发挥在其他数值型CSS属性(这里指类似font-size等属性)上。
我们知道,rem单位与html标签的字体大小紧密相关,如果我们使用CSS locks根据当前屏幕宽度(也就是100vw)动态计算出html标签的font-size属性值,然后使用媒体查询限制最大和最小值,这样,在其他数值型CSS属性中我们就直接使用rem单位。如此一来,只需要少量的媒体查询代码,不同屏幕尺寸适配问题就会迎刃而解。
在CSS中,其实出现过类似CSS locks功能的函数,如clamp(),min(),max()三个函数,它们的功能更加强大,写起来也更加简单优雅,但由于目前的兼容性较差,所以不建议在实际项目中使用。如想深入了解,推荐张鑫旭大佬的文章——了解CSS min()/max()/clamp()数学函数。这里就不再赘述了。
公式与实践
从上文中可得出vw+rem+CSS locks方案公式如下:
CSS
[minimum size]:最小字体大小。
[maximum size]:最大字体大小。
[minimum viewport width]:最小屏幕宽度。
[maximum viewport width]:最大屏幕宽度。
html {
font-size: [minimum size];
}
@media screen and (min-width: [minimum viewport width]) {
html {
font-size: calc([minimum size] + ([maximum size] - [minimum size]) * ((100vw - [minimum viewport width]) / ([maximum viewport width] - [minimum viewport width])));
}
}
@media screen and (min-width: [maximum viewport width]) {
html {
font-size: [maximum size];
}
}
复制代码
SCSS
利用SCSS中的Mixin指令和函数指令,增加了公式的复用性,也让我们的代码更加优雅。
$properties:属性名。
$min-screen:最小屏幕宽度。
$max-screen:最大屏幕宽度。
$min-value:属性最小值。
$max-value:属性最大值。
@mixin interpolate($properties, $min-screen, $max-screen, $min-value, $max-value) {
& {
@each $property in $properties {
#{$property}: $min-value;
}
@media screen and (min-width: $min-screen) {
@each $property in $properties {
#{$property}: css-locks($min-screen, $min-value, $max-screen, $max-value);
}
}
@media screen and (min-width: $max-screen) {
@each $property in $properties {
#{$property}: $max-value;
}
}
}
}
@function strip-unit($value) {
@return $value / ($value * 0 + 1);
}
@function css-locks($min-screen, $min-value, $max-screen, $max-value) {
@return calc(#{$min-value} + #{strip-unit($max-value - $min-value)} * ((100vw - #{$min-screen}) / #{strip-unit($max-screen - $min-screen)}));
}
复制代码
针对某一个属性我们就可以这样写:
p {
@include interpolate(font-size, 400px, 640px, 16px, 20px);
}
复制代码
如果不需要限制极值,也可以单独使用css-locks函数:
html {
font-size: css-locks($min-screen, $min-value, $max-screen, $max-value)
}
复制代码
结语
随着CSS技术领域更新迭代,除了少数古老的浏览器,视口单位已经基本兼容市面上的浏览器设备。显然,采用vw+rem+CSS locks方案解决pc端和mobile端适配问题会是目前较为理想的方案,特别是对于页面结构相对简单的博客系统来说更是堪称完美。具体案例可以查看我的博客小站—Freesims。
以上就是本文的全部内容,如有不正确的地方,请指出。
感谢阅读,欢迎分享!