一年一度的 CSS年度报告
如期而至,我挑了一些我感兴趣的部分,和我一起来看看吧~
这篇文章用了很久,因为平时 CSS 写的实在少,其实看报告的主要目的除了了解CSS技术趋势,更重要的是顺便学习了下之前没用过的一些特性和库 😄
布局
弹性盒子(Flex
)布局
相信大多数人都用过,就不多说了。
CSS 网格(GRID
)布局
用的人越来越多了,只有 0.7%
的受访者没了解过,我在平时中也用过,不过用的不多,大多数场景下 Flex
就能满足需求,你们呢?
子网格(Subgrid
)布局
用过的人比去年多一些,不过没用过或者没了解过的仍然是大多数。
说实话,我也是没用过,特意学习了一下,故名思议,除了操纵同级别的网格,它拥有操纵子网格的能力,它可以实现比 Grid
更复杂的布局,比如下面的例子:
1 | .grid { |
多列布局(Multi-Column)
又是个我没用过的,不过好像这几年趋势变化也不大,大部分人还是没用过。
查了下,还挺好用的,之前这样的事我都是用 display:inline-block
去搞,现在一个属性就搞定了。
1 | <div class="container"> |
比如上面的 container
容器中有三个块级元素,给 container
指定 column-count: 3
后就可以让浏览器自动分成三列,并且计算出每一列分配多少空间。
position: sticky
这个就是我们平时所谓的吸顶布局,相信大多数小伙伴都用过或者了解过了。
逻辑属性(Logical Properties)
逻辑属性
,是 CSS 新引入的的一项变革性能力,它的属性与值能做从逻辑角度控制布局,而不是从物理、方向或维度来控制。
目前调查来看,用过的人也不是很多,我们来简单介绍一下。
传统的 CSS
属性大多是采用物理属性来定义的,比如元素的尺寸,偏移和边距等属性。但是随着业务的发展,越来越多的web应用需要考虑到国家化,必须适配不同的语言。
大部分国家的语言排版都是从左到右,即LTR(left to right)
,但是仍然有一部分语言采用的是从右到左,即RTL(right to left)
的版本布局,比如阿拉伯语和希伯来语等。
图片展示了拉丁文,希伯来文和日语三种不同的书写方式。
逻辑属性
不仅可以让前端的布局在逻辑上更加严谨,而且能让开发者以更少的代码写出兼容性更好的页面。我们来看个简单的例子:
html
1 | <h3>物理布局</h3> |
css
1 | :root { |
当页面布局是正常的从左到右排列时,效果是一样的:
现在我们把容器的排列方式改成:direction: rtl;
,我们会发现物理布局出了问题:
在这段 CSS 里,margin-inline-start
就是一条逻辑属性,它可以让 margin 随着排版方向的变化而变化,而不是固定死的某一个方向。
向这样的逻辑属性还有很多:
aspect-ratio
用于指定图片的纵横比,调查中大概 37%
的人用过。
我在之前很多篇文章中都提到过,是一个很好用的属性:
给定图片的纵横比后,浏览器可以自动计算图片尺寸,可以用来提升 CLS
指标。
1 | aspect-ratio: 1 / 1; |
content-visibility
一个可以控制页面元素渲染的强大 CSS 属性,使用度今年好像和去年变化不大。
之前专门写过一篇文章来介绍它:
浏览器在接收到服务端返回的 HTML
之后,需要把这段数据渲染成用户看到的页面,在开始渲染第一个元素之前可能还需要经过很多步骤。这个过程会适用于整个页面,包括当前不可见的内容。
所以在首屏渲染时,是有很大一部分时间花费在用户不可见的内容上,实际上这部分数据我们没必要在首屏就把它们渲染出来。
content-visibility: auto
可以告诉浏览器暂时跳过该元素的布局和渲染工作,直到这个元素滚动到当前视口,从而可以加快整个页面的初始渲染,并且缩短用户和页面可交互需要花费的时间。
不过目前兼容性还比较差,慎重使用:
Container Queries
容器查询,目前还是一个在实验中的 CSS 特性,只有 5%
的人用过。
在我们要写一个响应式页面时,一般会试用媒体查询(@media
)根据不同的页面尺寸进行不同的布局。
但是,@media
针对的是整个页面的显示大小,然而对于一些特定页面结构中的组件(例如在左右分栏的页面结构中的卡片),明明我们只是想根据组件的大小来调整布局,然而却得考虑整个网页的布局,以推测在不同页面大小下这个组件能够拥有的空间。
比如说,在下面这个布局中,组件可能是横向展示的,也可能是纵向展示的。如果宽度空间够的话,它显示为两列,如果没有空间,将会上下堆叠显示。
这时候我们就可以用到容器查询:
1 | @container (min-width: 400px) { |
目前兼容性感人:
如果想试用,还要开启一个实验配置: chrome://flags/#enable-container-queries
图形和图像
CSS 图形 (Shape)
CSS Shape
描述了在 CSS 中使用的几何形状的方式,它可以实现不规则的文字环绕效果,发展得真不咋地,没了解过的居然越来越多了 …
比如,我们左侧有个圆形的图片,我们想把右侧的文字环绕效果也改成圆形:
这时,我们就可以用到 shape-outside
,它是不规则形状环绕布局的核心,有下面几个值:
circle()
– 圆ellipse()
– 椭圆inset()
– 内矩形(包括圆角矩形)polygon()
– 多边形
我们将它指定为 circle(50%)
,就可以实现圆形文字环绕效果。
1 | img { |
object-fit
object-fit
是个比较常用的 CSS 属性,它可以指定可替换元素的内容应该如何适应到其使用的高度和宽度确定的框。
简单的说,通过这个属性我们可以让一个元素自适应外部容器:
object-fit
有下面五个值:
fill
替换的内容正好填充元素的内容宽,替换内容拉伸填满整个content box,不保证保持原有的比例。contain
保持原有的尺寸比例。保证替换内容尺寸一定可以在容器里面放得下。因此,此参数可能在容器内一下空白。cover
保持原有的尺寸比例。保证替换内容尺寸一定大于容器尺寸,宽度和高度至少有一个和容器一致。因此,此参数可能会让替换内容部分区域不可见。none
保持原有的尺寸比例。同时保持替换内容原始尺寸大小。scale-down
内容的尺寸与none
或contain
中的一个相同,取决于它们之间谁得到的对象尺寸会更小。
clip-path
这个做动画的同学应该平时也用的比较多,我们可以用它来裁剪出一个元素的可视区域,从调查来看使用者也越来越多。
clip-path
是 clip
的升级版,它们的作用都是对元素进行 “剪裁”,不同的是 clip
只能作用于 position
为 absolute
和 fixed
的元素且剪裁区域只能是正方形,而 clip-path
更加强大,可以以任意形状去裁剪元素,且对元素的定位方式没有要求。
混合模式 (Blend Modes)
<blend-mode>
,是一种 CSS 数据类型,也就是我们常说的混合模式,可以用来描述当元素重叠时,颜色应当如何呈现。
当元素重叠时,混合模式是计算像素最终颜色值的方法,每种混合模式采用前景和背景的颜色值,执行其计算并返回最终的颜色值。最终的可见层是对混合层中的每个重叠像素执行混合模式计算的结果。
简单点说,就是有两张不同颜色的图片叠加时,中间重合的部分应该怎么展示。我们来看个简单的例子:
1 | body { |
网页的两边分别有不同的两种颜色,我们在网页中间添加了个文本,文本的颜色和右边的网页颜色重合,所以右边啥也看不到:
这时,我们该动一下文班的混合模式:
1 | h1 { |
就可以实现下面的效果:
mix-blend-mode: difference
的意思就是重合部分取两种颜色的差值,除了difference
,另外还有 darken
(变暗)、lighten
(变暗)、screen
(滤色) 等等。
CSS 滤镜效果
调查报告里使用最广的 CSS 属性之一,相信大多数小伙伴也都用过。
一张图看懂它的主要用途:
color-gamut
99%
的人都没用过 … 恭喜荣登本报告中知道的人最少的特性。
一个非常高级的用法,可以让我们根据输出设备的支持色域分类应用不同的样式,涨姿势了 … 。
1 | @media (color-gamut: srgb) { |
perspective
顾名思义,就是透视的意思,可以让我们实现一些简单的 3D 效果,不过现在用纯 CSS
写 3D
效果的少了,所以这个特性也用的越来越少了:
perspective
其实本质上是指定观察者与 z=0
平面的距离,从而让有三维位置变换的元素产生透视效果。z>0
的三维元素比正常大,而 z<0
时则比正常小,大小程度由该属性的值决定。
Intrinsic Sizing
Intrinsic Sizing
,即内在尺寸,今年第一次参加调查,但是大部分人都了解或者用过了,但是据我了解国内的网页里这个属性用的不错,因为对中文不太友好。
CSS
中存在两种尺寸:内在尺寸(intrinsic
)和外在尺寸(extrinsic
)。元素的 width、height
设置的固定属性值,就是指外部尺寸。而内部尺寸,则是由元素包含的内容决定的。
我们来看洗面这个例子,两个 P 标签分别用两种内容的内在尺寸决定它本身的宽度。
1 | h1 { |
min-content
:宽度等于最长单词的宽度min-content
:宽度等于整条内容的宽度(大概相当于display:inline-block
+white-space:nowrap
)
这个章节其实还提到了 backdrop-filter
、conic-gradient()
、color()
、accent-color
,我没啥兴趣,所以就直接略过了。
交互
CSS 滚动捕捉
CSS 滚动捕捉可以让用户完成滚动之后将视口锁定到某个元素的位置,这种效果经常出现在某些官网的网站里。
实现滚动捕捉主要依靠两个属性:容器元素的 scroll-snap-type
属性,以及子元素的 scroll-snap-align
属性。
scroll-snap-type:mandatory
告诉浏览器,在用户停止滚动时,浏览器必须滚动到一个捕捉点。scroll-snap-align
可以指定元素的哪一部分吸附到容器上,start
指的是元素的顶部边缘。如果你水平滚动,它指的是左边缘。center
和end
属性值与此同理。
来个简单的 Demo:
1 | <div class="slider"> |
1 | .slider { |
你可以实现下面的效果:
overscroll-behavior
可以控制,滚动条到达滚动区域的边界时的行为。
比如我们在网页的右下角放了个机器人聊天窗口,我们在滚动聊天消息的时候,如果滚动到了底部,页面的其他部分也会跟着滚,这时候就可以用 overscroll-behavior-y: contain;
来设置在当前区域已经滚动到底部时,不会带动其他区域滚动。
touch-action
touch-action
可以用于设置触摸屏用户如何操纵元素的区域(平滑、缩放、单指平移手势、手指平移和缩放等等),一般我们会在适配移动端操作的网站上会用到,变化趋势也不大,不再多说。
pointer-events
pointer-events
是个老属性了,可以用来控制特定元素和场景下的鼠标事件。
比如,我们想禁用一个元素的点击事件,就可以用 pointer-events:none
,这不仅仅会禁用元素的 hover
效果,而是真正的移除了 click
事件。
另外还有一些就是针对 SVG 元素的特定属性了,比如 pointer-events: fill;
:
scroll-timeline
scroll-timeline
是一个可以更灵活的控制滚动动画的属性,在被采访者中只有 2.5%
的人用过。
scroll-timeline
还是一个比较早期的提案,属于 Scroll-Linked Animations
规范的一部分:
像让页面滚动条滚动到某个位置、标题固定在顶部、面顶部展示你页面进度、或者是一些我们所说的视差滚动效果等等,在以前我们可能要借助 JavaScript
才能实现,现在我们可以使用 @scroll-timeline
,比如下面的代码:
1 | @scroll-timeline scroll-in-document-timeline { |
source
表示滚动的元素,默认情况下就是document
orientation
确定应当触发动画滚动方向。默认情况下是vertical
scroll-offsets
用于描述动画应处于活动状态的范围,它可以是相对、绝对值或者基于元素的偏移。
然后,我们将上面声明的时间轴动画的名称设置给 animation-timeline
属性,就可以和 CSS 动画关联上了。
1 | #progressbar { |
排版
font-variant
font-variant
代表的其实是一组控制字体的 CSS 属性,从调查来看,用的人越来越少了 …
我们平时在开发里用的最多的可能就是 font-variant:small-caps;
了,它可以把所有小写字母转成大写。
其实除了 font-variant-caps
,它还包括下面几个子属性:
font-variant-numeric
: 控制数字的展示形式font-variant-alternates
: 控制备用字体的使用font-variant-ligatures
: 控制是否连字展示
initial-letter
initial-letter
可以控制首字母的展示形式,比如上升、下沉等效果,不过兼容性极差,也是用的人越来越少了。
line-clamp
line-clamp
可以用来限定一个块级容器中展示内容的行数,这个平时应该用的比较多。
比如,我们要限定一个容器中最多展示两行,文字,超过两行的内容用省略号替代:
1 | .box { |
Variable fonts
可变字体(Variable Fonts
),今年第一次参与调查,大概 20%
的人有用过。
一般来说,字体的不同格式,比如斜体、粗细、拉伸存储在分开的单个文件内,而现在,你可以存储多种字体格式在一个 openType
可变字体文件内,所以,这种文件相对来说体积会更小。
另外,我们可以借助 Variable Fonts
为网站提供更丰富、更灵活、更细粒度的的自定义字体能力(比如说 font-weight:550
就是属于细粒度的字体控制),以适应不同风格和主题的变化。
其他特性
CSS 变量(自定义属性)
CSS 变量,使用率已经高达 84%
,没听过的仅有 2.8%
。
用法很简单,声明变量的时候,变量名前面要加两根连词线(--
),相信大多数小伙伴也都用过,不再多说:
1 | :root { |
特征查询(Feature Support Queries)
特征查询也就是 @supports
,是条件规则的一种,可以用来检测当前浏览器是否支持某个CSS属性,这个确实挺实用的,使用率逐年增长。
用法广泛,比如下面几种:
检测是否支持指定的 CSS 属性
1 | @supports (animation-name: test) { |
检测是否不支持指定的CSS属性
1 | @supports ( not ((text-align-last:justify) or (-moz-text-align-last:justify) ){ |
测试是否支持某个自定义属性
1 | @supports (--foo: green) { |
测试浏览器否支持某个选择器
1 |
|
不过,作为一个用来做兼容性检测的特性,居然在 IE
下全跪,只能说 IE
牛逼!
CSS 约束 (Containment)
CSS contain
属性允许开发者声明当前元素和它的内容尽可能的独立于 DOM 树的其他部分,这是个性能优化利器,居然只有不到 10%
的人用过。
contain
属性的主要目的是隔离指定内容的样式、布局和渲染。开发人员可以使用这个 contain
属性来限制指定的 DOM 元素和它的子元素同页面上其它内容的联系;我们可以把它看做一个 iframe
。跟 iframe
很相似,它能建立起一个边界,产生一个新的根布局;保证了它和它的子元素的 DOM
变化不会触发父元素重新布局、渲染等。
这个属性在包含大量独立组件的页面非常实用,它可以防止某个小部件的 CSS
规则改变对页面上的其他东西造成影响,contain
属性有以下七个值:
none
无layout
开启布局限制style
开启样式限制paint
开启渲染限制size
开启size限制content
开启除了size外的所有限制strict
开启 layout, style 和 paint 三种限制组合
对于页面上的一些独立的小部件,都推荐使用 contain: strict;
,对页面性能很有帮助,目前使用度还比较低,强烈推荐!
will-change
will-change
也是一个用来做性能优化的属性,相比上面的 contain
,它的使用度要高一点。
当我们通过某些行为(点击、移动或滚动)触发页面进行大面积绘制的时候,浏览器往往是没有准备的,只能被动使用 CPU
去计算与重绘,由于没有事先准备,应付渲染够呛,于是掉帧。
will-change
可以在行为触发之前告诉浏览器我们要进行一些什么样的变化操作,让浏览器好有个准备,启动 GPU
为你渲染动画。
当然,用好这个属性也有点难度,一般直接写在 CSS 的默认状态中是没用的,下面我们举两个简单的例子:
结合 JavaScript
用:
1 | var el = document.getElementById('element'); |
在 CSS 里用:
1 | .will-change { |
如果用好的话,也是性能优化的一大利器。
calc()
计算属性,使用率已经高达 93%
,相信大多数同学都用过了。
不多说了, 在布局和动画中都是非常常用的,比如 height: calc(100vh - 80px);
。
Houdini
Houdini
是个非常强大的能力,可以扩展 CSS
的跨浏览器绘制能力,木过的人只有 3%
。
Houdini
通过 Typed Object Model
启用更多的语义化 CSS
。开发者可以通过属性和值 API 定义具有语法、默认值和继承的高级 CSS
自定义属性。
我之前专门写了一篇文章介绍 Houdini
,感兴趣的话可以看:
CSS 比较函数 (Comparison Functions)
CSS
中的 min,max
函数都是属于比较函数,作用类似于 js
函数中的 min,max
,用于取多个属性中的最小值或者最大值,属性之间用逗号分隔,比如(width: min(100px,200px,300px);
)
预处理
在开始之前,我们先对常用的几大预处理框架做个简单的对比:
Sass/Scss
:sass
分为sass
和scss
两个语法分支,scss
是兼容 css 的写法,很容易上手,同时继承了sass
的优点,用的比较多的是scss
,sass
的语法则是用缩进来代替花括号、省略了结尾分号。sass
速度更快且易安装,因为scss
兼容 css 写法,写起来更容易上手,像bootstrap
、Element
也在使用 scss 作为 css 预处理器使用。Less
:日常开发Less
和Scss
差不多,都是偏原生语法,比较容易接纳,less
有个优势就是可以“不用编译”,为啥加引号呢,因为它确实可以做到不手动编译,在引入less
的后面引入less.js
即可,但是作为最佳实践,你始终应该去编译它,因为大多数情况下,编译它并不会花掉你太多时间。stylus
采用了sass
类似的缩进来表示层级,以及省略了分号等等,声明变量也不再需要 $ 或者 @ 符号,变量名和变量值之间使用 = 作为分隔,同时stylus
允许传统css
语法和stylus
语法混用。因为其精简的太多,代码量可以更少,但是阅读起来可能不是那么美妙。PostCSS
一个使用JS插件来转换样式的工具,它跟CSS预处理器的定位其实不同,它的作用主要有lint css
,支持CSS Next
语法,自动添加前缀等等功能,通过插件,基本上可以覆盖 CSS 预处理器的功能,同时可以实现很多预处理器实现不了的功能。优势在于其丰富的插件生态,能够覆盖开发中的方方面面,我们又能够很容易的开发自己的插件。
满意度
PostCSS 常年第一,不过今年新参加的 Assembler CSS
好像有点惨,关注度还行,不过无论是使用度还是满意度都比较差。
使用度
Sass
使用度仍然第一,PostCSS
反超 Less
。
随着时间变化的体验
这个比较有意思,Less、Sass
的满意度随时间推移都是有所下降的,而 PostCSS
在逐步上升。
积极和消极程度
CSS 框架
框架就不做过多介绍了,使用过的基本上都知道。
满意度
这里的亮点是 Ant Design
,满意度逐年增长,国货之光啊!
使用度
没想到 Bootstrap
还能占据第一,我 5 年前就放弃了,另外老外用的比较多的还是 Tailwind CSS
,增长率非常快,Ant Design
还是我们用的比较多,整体使用度只有 16%
。
CSS-in-JS
我个人也在用 CSS-in-JS
,第一个它解决了命名的痛点,传统的 css
方案,因为 class name
是全局的,你就要保证它的唯一性,你要把你的组件名等各种 namespace
作为 class name
的前缀,以保证唯一性,css in js
就解决了这一点。另外,使用 CSS-in-JS
使用 js 动态控制样式会更简单。
满意度
大部分 CSS-in-JS
框架的满意度都有所下降…
这个也比较正常,因为它的缺点也比较明显,一直没得到解决:
- 运行时消耗:于大多数的
CSS-in-JS
的库都是在动态生成CSS的,一般都会有些性能损耗,而且包体积会稍大一些。 - 代码可读性差:大多数
CSS-in-JS
实现会通过生成唯一的CSS选择器来达到CSS局部作用域的效果,这些自动生成的选择器会大大降低代码的可读性。 - 没有统一的业界标准
CSS-in-JS
只是一种技术思路而没有一个社区统一遵循的标准和规范,所以不同实现的语法和功能可能有很大的差异。
使用度
这个没啥变化,Styled Components
的使用率是最高的。
通过 Styled Components
,你可以使用 ES6
的标签模板字符串语法为需要 styled
的 Component
定义一系列 CSS
属性,当该组件的JS代码被解析执行的时候, Styled Components
会动态生成一个 CSS
选择器,并把对应的 CSS
样式通过 style
标签的形式插入到 head
标签里面。动态生成的 CSS
选择器会有一小段哈希值来保证全局唯一性来避免样式发生冲突。
我个人用的是 Emotion CSS
,它和 Styled Components
基本上差不多,不过它对 sourcemap
的支持会更好一点。
1 | import { css, jsx } from '@emotion/react' |
CSS-in-JS Playground
是一个可以快速尝试不同 CSS-in-JS
实现的网站,如果你想做技术选型,可以去看看:
大奖
- 使用度采用最多的特性:
CSS 比较函数
,相比去年增长了15.5%
。 - 最高满意度:
PostCSS
再次以 91% 的满意度位居榜首。 - 最受关注:
CSS Modules
再次以74%
的比例引起了 CSS 开发人员的最大兴趣。
调查范围
最后吐槽一下这个报告的调查范围,中国这么多开发者居然只调查了 75
个人,占所有受访者的 0.9%
,差评!
最后
本文中只节选一些报告中我感兴趣的内容,并非报告全文,想要了解更多请查看报告原文:https://2021.stateofcss.com/
如果你想加入高质量前端交流群,或者你有任何其他事情想和我交流也可以添加我的个人微信 ConardLi 。