响应式布局之 clamp 函数

响应式布局

响应式布局(Responsive Design)是大约十年前提出的一个概念,意在以一套代码适配不同终端设备——而不是为每个终端做一个特定的版本;它的目的是解决移动互联网时代不同设备分辨率繁多,而多版本 CSS 代码生产成本过高的难题。传统意义上,我们实现响应式布局,有如下两种方式:

  • Media queries(媒体查询)

    CSS 媒体查询事实上早已有之,最早它是来适配打印机、电报、盲文印刷设备这类上个世纪的终端产品的。它的主要语法是:

    @media mediatype and|not|only (media feature){
      CSS-Code;
    }
    

    我们可以通过调整 media 规则,为不同媒体设备提供不同的样式。如下 CSS 代码,example元素在宽度小于 600 像素的屏幕上,显示长度为 50vm,即半个屏宽;在大于 600 像素的屏幕上,只显示 300 像素的长度。

    @media screen and (max-width: 600px){
      .example {
        width: 50vw;
      }
    }
    
    @media screen and (min-width: 600px){
      .example {
        width: 300px;
      }
    }
    
  • ResizeObserver

    ResizeObserver 就是通过 JS 来调整页面元素的大小了。不过,该方法及其繁琐,除非某些元素有很强的需求,一般来说我们也不会去尝试的:

    const resizeObserver = new ResizeObserver((entries) => {
      const screenWidth = document.documentElement.clientWidth;
      for (let entry of entries) {
        entry.target.style.width = screenWidth > 600 ? "300px" : "50vw";
      }
    });
    resizeObserver.observe(document.querySelector(".example"));
    

上面两种通用手段都有一个特点,就是代码量比较大。随着现代 CSS 功能的不断增强,很多原始的写法其实已经过时了。现在调整响应式布局的宽度,更多时候用的是 CSS3 的新函数——clamp,下文就简单介绍一下它的使用方法。

min & max

谈到clamp,不得不提的就是它的两个前辈函数——min()max(); 顾名思义,前者是取最小值,后者是取最大值。该节就以 min 方法为例,详细介绍一下这两个函数的用法。

min() 方法语法如下:以一个或多个逗号分隔的数学函数字面量或是其他表达式作为参数,返回参数列表中的最小值:

property: min(expression [, expression])

举两个例子:

  • width: min(8px, 9px):返回的宽度是 8px
  • font-size: min(8px + 2px, 9px):得到 9px 的字体大小

注意:在 CSS 的函数里,+-前后必须要有空格,但是*/可以不用

不过,上面两个例子在现实中毫无意义,因为单纯比较 8px 和 9px 是没有实际应用场景,min 的主场还是在响应式布局上的。我们看个有意义的例子:

<style>
  .css-min {
    width: min(50vw, 300px);
  }

  div {
    background-color: pink;
  }
</style>

<div class="css-min">
  min(50vw, 300px) - If the viewport at 50vw is less than 300px, take the value
  of 50vw, otherwise, stay at 300px.
</div>
CSS min

简单解释一下上面的代码,如果视窗小于 600px, 则粉色区域占据一半的视窗宽度(50vw);反之则宽度保持 300px。效果大约等价于如下传统方式——可以看出 min 代码简洁许多:

  • max-width

    .css-min {
      width: 50vw;
      max-width: 300px;
    }
    
  • 媒体查询

    .css-min {
      width: 50vw;
    }
    
    @media ( min-width: 600px ) {
      .css-min {
        width: 300px;
      }
    }
    

min 需要比较的是不同衡量单位下的数值大小;尤其在响应式布局下,参数一般都会包括一些与全屏相关的度量单位,如 vw、vh、rem 等等:

.example {
  width: min(var(--size)*1px, 6rem + 2px,5em, 10%, 2vw)
}

同理,max 函数就是取最大值了;使用方法与 min 相同,这里就不赘述了。

clamp

OK,花了很大篇幅在 min 函数上,那它和我们的主角 clamp 有什么关系呢?我们先看看 clamp 的定义:

clamp(MIN, VAL, MAX) 函数的作用是把一个值限制在一个上限和下限之间,当这个值超过最小值和最大值的范围时,在最小值和最大值之间选择一个值使用

定义有点抽象,看个例子就明白了:

.css-clamp {
  width: clamp(200px, 50vw, 300px)
}
css clamp

从上面的 gif 里可以比较明显的感觉到,在不断调整浏览器大小的过程中:

  • 当屏宽超过 600px 时,粉红色区域长度固定
  • 而屏宽介于 400px 和 600px 之间时,粉色区域按照屏宽等比例变换
  • 直到屏宽小于 400px 后,粉红区域又趋向固定。

这就是 clamp 的效果,它接受三个参数,分别是最小值、首选值和最大值;返回值默认是首选值,但是超出边界后返回最小值或最大值。还是以 clamp(200px, 50vw, 300px) 为例:

  • 当屏宽小于 400px 时,首选值(50vw)小比下限(200px),所以返回最小值(200px)
  • 当屏宽介于 400px 和 600px 之间时,首选值(50vw)介于最小值(200px)和最大值(300px)之间时,返回首选值(50vw)
  • 当屏宽大于 600px 时,首选值(50vw)大比上限(300px),使用最大值(300px)

简单来说,clamp(MIN, VAL, MAX) 等价于 max(MIN, min(VAL, MAX))。上文提到,min 和 max 可以简化一些媒体查询的代码;clamp 作为更复杂的方法,“语法糖”效果就更明显了,我们看看如下用媒体查询来实现clamp(200px, 50vw, 300px)的效果的代码量,clamp 的优势就可见一斑了:

.example {
  width: 50vw;
}

@media ( min-width: 600px ) {
  .css-min {
    width: 300px;
  }
}

@media ( max-width: 400px ) {
  .css-min {
    width: 200px;
  }
}

除了可以应用到 width、margin、font-size 这种比较常见的长度单位(Length)计算上,clamp 还可以在以下几个数据类型上使用:

  • percentage:表示一个百分比,经常用以根据父对象来确定大小
  • angle:用于颜色渐变、动画等相关属性上,单位有 degrees,gradians,radians,turns
  • time:用于 animations、transition 等相关属性,单位有秒(s)和毫秒(ms)
  • number:用于 CSS 变量(如::root{ --size: min(8px, 1rem) }
  • frequency:表示频率维度,如语音的高低,单位有赫兹(Hz)和千赫兹(KHz)

小结

上文啰里啰嗦,事实上只讲了一个 CSS 函数,也没太重要的知识点;就是觉得作为一个开发人员,还是要关注一些新的趋势和方法的。我常年在一些跨国合作的项目中搬砖,常常觉得别人家写的代码很有特色——长期保持着一种上个世纪的实现风格,即便抛弃了历史包袱,依旧孜孜不倦地坚持着某些早已过气的形式。不知道大家有没有这种经历?也欢迎留言讨论。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 转载自 大漠 导读:CSS是Web开发中不可或缺的一部分,随着Web技术的不断革新,CSS也变得更加强大。CSS的...
    WEB耳阅读 975评论 0 18
  • 1.1CSS 基础与选择器初识 | CSS 1. CSS 加载方式有几种? CSS样式加载一共有四种方式: 1、行...
    没糖_cristalle阅读 684评论 0 0
  • 前端响应式布局原理与方案(详细版) 引言 响应式布局指的是同一页面在不同屏幕尺寸下有不同的布局。传统的开发方式是 ...
    袁俊亮技术博客阅读 432评论 0 2
  • 实现不同屏幕分辨率的终端上浏览网页的不同展示方式。通过响应式设计能使网站在手机和平板电脑上有更好的浏览阅读体验。 ...
    Joel_zh阅读 327评论 0 0
  • https://juejin.im/post/5caaa230e51d452b672f9703 响应式布局指的是同...
    逆风飘游的鱼阅读 35,209评论 0 13