大家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。
今天给大家带来的主题是“2023年前端必知的CSS 和 UI 15+全新功能”,文章知识点大部分来自于Google官网,但是内容做了不少总结和补充。希望本文能从总体上让大家对2023年的浏览器新功能有一个大而全的了解。
话不多说,直接进入正题!
容器查询(Container Queries)
在创建移动网页时,通常依靠媒体查询来根据屏幕尺寸调整布局。 但是,如果想根据内容块的大小应用修改该怎么办? 这就是容器查询的用途。
容器查询允许根据父级大小修改元素的样式,这与媒体查询根据视口的大小应用更改不同。
比如下面的例子:
.post {
container-type: inline-size;
// size, inline-size或者 normal
// 为.post元素声明一个containment context
}
Card title
Card content
container-type 支持不同类型,不同类型有不同含义:
- size:查询将基于容器的内联尺寸和块尺寸。将布局、样式和大小限制应用于容器。
- inline-size:查询将基于容器的内联尺寸。将布局、样式和内联大小包含应用于元素。
- normal:该元素不是任何容器大小查询的查询容器(query container),但仍然是容器样式查询的查询容器。
接下来,使用 @container 规则定义容器查询。 以下示例中的查询将根据包含上下文的最近祖先(nearest ancestor )的大小将样式应用于元素。 具体来说,如果容器宽度超过 700 像素,此查询将为卡片标题应用更大的字体大小:
/* 容器小于700px样式 */
.card h2 {
font-size: 1em;
}
/* 容器大于 700px */
@container (min-width: 700px) {
.card h2 {
font-size: 2em;
}
}
Style Queries
容器查询规范还允许开发者查询父容器的样式值。 目前,已在 Chrome 111 中部分实现,开发者可以在其中使用 CSS 自定义属性来应用容器样式。
以下示例使用存储在自定义属性值中的天气特征(例如下雨、晴天和阴天)来设置卡片背景和指示器图标的样式。
@container style(--sunny: true) {
.weather-card {
background: linear-gradient(-30deg, yellow, orange);
}
.weather-card:after {
content: url();
background: gold;
}
}
下面是 HTML 的内容值:
{/*使用--sunny: true*/}
-
Saturday
February 12
High: 55/
Low: 47
Clear skies, sun
以上示例只是样式查询的开始,后续甚至可以使用布尔查询来确定自定义属性值是否存在并减少代码重复,目前正在讨论的是范围查询(range queries)以根据一系列值应用样式。
has()
使用 :has() 选择器,可以通过检查父元素是否包含特定子元素,或者这些子元素是否处于特定状态来应用样式。 它本质上是一个“父”选择器。
对该选择器有不同的语法:
- h1:has(p):选择具有
子级标记的
,无论其级别如何。
- h1:has(> p):选择具有
子级标记的
- h1:has(+ p):选择后面直接跟着
元素的
假如有以下 HTML:
Morning Times
Delivering you news every morning
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.
同时有以下选择器:
h1:has(+ h2) {
margin: 0 0 0.25rem 0;
color:red;
}
此时“Morning Times”文案将显示红色。
nth-of
Web 平台现在具有更高级的 nth-child 选择功能,而高级 nth-child 语法提供了一个新关键字(“of”),它允许开发者使用 An+B 的现有微语法,以及要在其中进行搜索的更具体的子集。
如果在特殊类上使用常规的 nth-child,例如 :nth-child(2),则浏览器将选择应用了特殊类的元素,并且也是第二个子元素。 这与 :nth-child(2 of .special) 形成对比,后者将首先预过滤所有 .special 元素,然后从该列表中选择第二个元素。
:nth-child(2 of .highlight)
// 选择具有 .highlight 类的第二个匹配元素
:nth-child(4 of .highlight, .sale)
// 从一组同级元素中选择第四个元素,即 .highlight 或 .sale
text-wrap: balance
Chrome Canary 包含一项新功能(Chrome 114 或更高版本),即 text-wrap:balance。
如果没有 text-wrap: balance, 设计师、内容编辑和出版商几乎没有工具来改变行平衡的方式。最好的选择是使用
作为开发人员,由于不知道标题或段落的最终大小、字体大小,甚至语言。 有效且美观地处理文本换行所需的所有变量都在浏览器中。 这就是为什么会看到标题换行,如下图所示:
.unbalanced {
max-inline-size: 50ch;
}
使用 CSS Text 4 中的 text-wrap:balance,可以请求浏览器找出文本的最佳平衡换行解决方案。 浏览器确实知道所有因素,例如:字体大小、语言和分配的区域。 比如下面效果:
代码如下:
.balanced {
max-inline-size: 50ch;
text-wrap: balance;
}
initial-letter
网页排版的另一个不错的改进是 initial-letter, 此 CSS 属性使开发者可以更好地控制内嵌首字下沉样式。
开发者可以在:first-letter 伪元素上使用 initial-letter 来指定,比如:基于字母占用的行数的字母大小。 字母的块偏移或“下沉”,即字母所在的位置。
p:first-letter {
initial-letter: 3.5 3;
}
- 第一个参数定义字母的大小及其占用的行数: 字母将放大,同时保持其纵横比。不能使用负值,但可以使用小数值。
- 第二个参数定义字母下沉(letter sink): 这可以被认为是字母所在位置的偏移量。 值是可选的,不能为负数。 如果不存在,则假定字母大小的值取整至最接近的整数。 这相当于使用关键字“drop”。 接收器还接受另一个关键字值“raise”,它相当于接收器 1。
新 viewport 单元
开发网页时,考虑屏幕的尺寸非常重要。 使用视口进行设计的一种方法是使用视口高度单位 vh/vw(100vh 是屏幕高度的 100%)。
这种方法的问题是移动设备上没有考虑浏览器的工具栏高度:
- 蓝色箭头:显示页面的高度
- 红色箭头:屏幕上可见的高度
为了解决这个问题,浏览器现在提供了新的单位值:
- 小视口(svh/svw):考虑地址栏和工具栏
- 大视口(lvh/lvw):不考虑地址栏和工具栏
- 动态视口 (dvh/dvw):当工具栏可见或/和不可见时调整其值。
重要的是要知道这些单位没有考虑滚动条。 因此,根据具体情况,开发者可能希望使用一个单位值而不是另一个单位值,或者只使用视口以外的另一个单位。
广色域色彩空间
Web 平台的另一个新的关键补充是广色域色彩空间。 在 Web 平台上提供广色域颜色之前,开发者可以拍摄色彩鲜艳的照片,并可在现代设备上查看,但无法创建与这些鲜艳值相匹配的按钮、文本颜色或背景。
但现在 Web 平台上有了一系列新的色彩空间,包括: REC2020、P3、XYZ、LAB、OKLAB、LCH 和 OKLCH,可以在高清色彩指南中了解新的网络色彩空间等。
可以立即在 DevTools 中看到颜色范围如何扩展,其中白线描绘了 srgb 范围的结束位置以及更宽色域颜色范围的开始位置。
[data-color="red"] {
background-color: oklch(50% 130 20);
}
[data-color="red-alpha"] {
background-color: oklch(50% 130 20 / 0.4);
}
color-mix()
color-mix() 函数对扩展的颜色空间进行扩展。
此函数支持混合两个颜色值,以根据混合颜色的通道创建新值,混合的色彩空间会影响结果。 在像 oklch 这样更具感知性的色彩空间中,将具有与 srgb 等不同的颜色范围。
该方法的语法如下:
color-mix(in lch, plum, pink);
color-mix(in lch, plum 40%, pink);
color-mix(in srgb, #34c9eb 20%, white);
color-mix(in hsl longer hue, hsl(120 100% 50%) 20%, white);
color-mix() 函数提供了大多数开发要求的功能,即能够保留不透明的颜色值,同时为其添加一些透明度。
现在,可以使用品牌颜色变量,同时以不同的不透明度创建这些颜色的变体, 实现此目的的方法是将颜色与透明混合。比如: 当将蓝色品牌颜色与 10% 透明颜色混合时,会得到 90% 不透明品牌颜色。
.shorter {
background-color: color-mix(
in hsl shorter hue,
hsl(10 100% 50%),
hsl(60 100% 50%)
);
}
.longer {
background-color: color-mix(
in hsl longer hue,
hsl(10 100% 50%),
hsl(60 100% 50%)
);
}
CSS Nesting(CSS 嵌套)
CSS 嵌套的实现来自于大多数开发者对 Sass、Less 的喜爱,也是 CSS 开发人员多年来最要求的功能之一,终于在 Web 平台中得以实现。
CSS 嵌套允许开发人员以更简洁、分组的格式编写,从而减少冗余。
.card {}
.card:hover {}
/* 可以通过下面方式嵌套 */
.card {
&:hover {}
}
CSS 嵌套还支持嵌套媒体查询,当然也包括容器查询。在以下示例中,如果卡片的容器中有足够的宽度,卡片就会从纵向布局更改为横向布局:
.card {
display: grid;
gap: 1rem;
@container (width >= 480px) {
// 尺寸足够大
display: flex;
}
}
Scoped CSS
CSS Scoped 样式允许开发人员指定特定样式应用的边界,本质上是在 CSS 中创建本机命名空间(native namespacing )。
以前,开发人员只能依靠第 3 方脚本来重命名类,或使用特定的命名约定来防止样式冲突,但目前开发者已经可以使用 @scope。:scope 属于 CSS 伪类,它表示作为选择器要匹配的参考点的元素。
/* Selects a scoped element */
:scope {
background-color: lime;
}
在上面的例子中,:scope 等效于 :root,因为目前尚无一种方法来显式建立作用域元素。当从 DOM API 使用,如(querySelector(), querySelectorAll(), matches(), 或 Element.closest()), :scope 匹配调用 API 的元素。
let paragraph = document.getElementById('para');
let output = document.getElementById('output');
if (paragraph.matches(':scope')) {
output.innerText = 'Yep, the element is its own scope as expected!';
}
上面的示例演示了调用 Element.matches() 方法中使用 :scope 伪类来匹配调用它的元素。
Cascade layers
层叠本质就是定义了如何合并来自多个源的属性值的算法,简单来说,CSS 规则的顺序很重要。当两条同级别的规则应用到一个元素的时候,写在后面的就是实际使用的规则。
h1 {
color: red;
}
h1 {
color: blue;
}
// 两条规则优先级相同,所以顺序在最后的生效,h1是color:blue'胜出',显示蓝色。
Cascade layers 通过让用户控制哪些层比其他层具有更高的优先级来解决这个问题,这意味着对应用样式进行更精细的控制。
即 CSS @规则 中的@layer 声明了一个 级联层,同一层内的规则将级联在一起,这给予了开发者对层叠机制的更多控制。
@layer utilities {
/* 创建一个名为 utilities 的级联层 */
}
下面是导入@layer 的方式:
@layer theme, layout, utilities;
层最初被指定的顺序决定了它是否有优先级。对于声明而言,如果同一声明在多个级联层中被指定,最后一层中的将优先于其他层。因此,在上面的例子中,如果 theme 层和 utilities 层中存在冲突的规则,那么 utilities 层中的将优先被应用。
即使 utilities 层中规则的优先级低于 theme 层中的,该规则仍会被应用。一旦级联层顺序建立之后,优先级和出现顺序都会被忽略。这将使创建 CSS 选择器变得更加简单,因为你不需要确保每一个选择器都有足够高的优先级来覆盖其他冲突的规则,只需要确保出现在一个顺序更靠后的级联层中。
三角函数
现在三角函数已经被添加到现有的 CSS 数学函数中。这些功能已经在所有主流浏览器中得到支持,使开发者能够在 Web 平台上创建更复杂的布局。 比如: sin()、cos() 、 tan()、asin()、acos()、atan() 、 atan2()等等。
- cos(): CSS 函数是一个三角函数,它返回数字的余弦值,该值介于 -1 和 1 之间。该函数包含一个计算,必须通过解释解析为
或 以弧度表示的参数结果。 也就是说,cos(45deg)、cos(0.125turn) 和 cos(3.14159 / 4) 都表示相同的值,大约为 0.707。 - sin():CSS 函数是一个三角函数,它返回数字的正弦值,该值是 -1 到 1 之间的值。该函数包含一个计算,必须通过解释来解析为
或 以弧度表示的参数结果。 也就是说,sin(45deg)、sin(0.125turn) 和 sin(3.14159 / 4) 都表示相同的值,大约为 0.707。
单独动画属性
过去,开发者依赖于 transform 函数来应用子函数来缩放、旋转和平移 UI 元素。 这涉及大量重复,并且在动画中的不同时间应用多个变换时尤为复杂。
.target {
transform: translateX(50%) rotate(30deg) scale(1.2);
}
.target:hover {
transform: translateX(50%) rotate(30deg) scale(2);
/* Only scale changed here, yet you have to repeat all other parts */
}
现在,可以通过分离变换类型并单独应用来在 CSS 动画实现所有这些细节。
.target {
translate: 50% 0;
rotate: 30deg;
scale: 1.2;
}
.target:hover {
scale: 2;
}
这样,平移、旋转或缩放的变化可以在动画期间的不同时间以不同的变化率同时发生。
锚定位
弹出窗口经常用于对话框和工具提示等元素,这些元素通常需要锚定到特定元素。
现在,开发者可以使用 anchor()函数创建居中工具提示,使用锚点的宽度将工具提示定位在锚点 x 位置的 50%处。 然后,使用现有定位值来应用其余的放置样式。但是,这种做法常常会遇到不少问题。
为了解决这个问题,锚点定位 API 允许自定义的 fallback 位置。
以下示例创建一个名为“top-then-bottom”的 fallback 位置。 浏览器将首先尝试将工具提示放置在顶部,如果它不适合视口,则浏览器会将其放置在底部的锚定元素下方。
.center-tooltip {
position-fallback: --top-then-bottom;
translate: -50% 0;
}
// 注意下面的两个@try
@position-fallback --top-then-bottom {
@try {
bottom: calc(anchor(top) + 0.5rem);
left: anchor(center);
}
@try {
top: calc(anchor(bottom) + 0.5rem);
left: anchor(center);
}
}大家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。
其他
除了以上新增能力外,最近浏览器还新增了更多高级特性,比如:
- Popover:全局属性 popover 用来指定一个元素为弹出式元素(popover element)。弹出式元素通过 display: none 被隐藏,直到通过调用/控制元素(即带有 popovertarget 属性的
:通过 Popover 和锚点定位(anchor positioning),开发者可以构建完全可定制的选择菜单。 OpenUI 社区小组一直在研究这些菜单的基本结构,并寻找允许自定义其中任何内容的方法。 - Scroll-driven animations:提供了构建在 CSS 动画模块和 Web 动画 API 之上的功能。 允许根据沿着基于滚动的时间线而不是默认的基于时间的文档时间线的进度来对属性值进行动画处理。
- View transitions:View Transitions API 提供了一种机制,可以轻松地在不同 DOM 状态之间创建动画转换,同时还可以一步更新 DOM 内容。
- 离散属性动画:为 Web 提供某种方法来为离散属性设置动画,比如 display:none 等
- accent-color :为某些元素生成的用户界面控件设置强调色。
参考资料
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_container_queries
https://developer.chrome.com/blog/whats-new-css-ui-2023/#style-queries
https://developer.mozilla.org/zh-CN/docs/Web/CSS/:has
https://developer.chrome.com/articles/css-nth-child-of-s/
https://www.bookstack.cn/read/html-tutorial/spilt.4.docs-text.md
https://developer.chrome.com/blog/css-text-wrap-balance/
https://developer.chrome.com/blog/control-your-drop-caps-with-css-initial-letter/
https://web.dev/articles/viewport-units?hl=zh-cn
https://developer.mozilla.org/zh-CN/docs/Web/CSS/color_value/oklch#browser_compatibility
https://developer.mozilla.org/zh-CN/docs/Web/CSS/color_value/color-mix
https://developer.mozilla.org/zh-CN/docs/Web/CSS/:scope
https://developer.chrome.com/blog/cascade-layers/
https://www.mathsisfun.com/sine-cosine-tangent.html
https://web.dev/articles/css-individual-transform-properties?hl=zh-cn
https://developer.chrome.com/blog/tether-elements-to-each-other-with-css-anchor-positioning/
https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes/popover
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_scroll-driven_animations
https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
https://developer.mozilla.org/en-US/docs/Web/CSS/accent-color
https://positivethinking.tech/insights/the-10-new-css-features-in-2023/