CSS 使用许多所谓的标识view-transition-name
来命名事物——想想您为、、等输入view-timeline-name
的值。container-name
一次性为大量元素构建这些唯一值通常是一项重复性工作,其中你会发现自己*-name
要为每个元素重复选择器和声明。有 100 个元素?那就是 100 个声明(作为 100 条规则的一部分)。呃。
刚刚发布的一项 CSS 工作组决议采纳我为解决此问题所提出的一个方案:函数ident()
。
在许多CSS 功能中,您需要为元素指定一个特定的名称,以便以后可以引用这些元素。例如container-name
,,,,等。view-transition-name
view-timeline-name
scroll-timeline-name
根据属性的不同,这些名称可能是<custom-ident>
或<dashed-ident>
。这些名称必须是唯一的(在使用的功能范围内)。对于视图转换和滚动驱动动画,这种唯一性可能会成为作者的负担。
以这个滚动驱动动画为例,我为每个目标元素设置了一个独特的view-timeline-name
(<dashed-ident<
适合场合的)时间轴,稍后也会参考该时间轴:
.parent { timeline-scope: all; } main { div:nth-child(1) { view-timeline-name: --tl-1; } div:nth-child(2) { view-timeline-name: --tl-2; } div:nth-child(3) { view-timeline-name: --tl-3; } } nav { li:nth-child(1) { animation-timeline: --tl-1; } li:nth-child(2) { animation-timeline: --tl-2; } li:nth-child(3) { animation-timeline: --tl-3; } }
与 View Transitions 相同,我曾看到过此代码:
&:nth-child(1) { view-transition-name: opt-1; & > label { view-transition-name: opt-1-label; } & > input { view-transition-name: opt-1-input; } } &:nth-child(2) { view-transition-name: opt-2; & > label { view-transition-name: opt-2-label; } & > input { view-transition-name: opt-2-input; } } &:nth-child(3) { view-transition-name: opt-3; & > label { view-transition-name: opt-3-label; } & > input { view-transition-name: opt-3-input; } }
虽然这两个例子都仅限于 3 个项目,但你可以很容易地发现,当涉及更多项目时,这会成为一种负担。
解决方案:ident()
为了便于批量命名元素,我向 CSS 工作组提出了该函数。这是一个动态构造和值的函数。ident()
<custom-ident>
<dashed-ident>
<ident()> = ident( <ident-arg>+ ) <ident-arg> = <string> | <integer> | <ident>
该函数接受任意数量的空格分隔的参数,但至少需要 1 个。参数的类型为<string>
,<integer>
或其他<ident>
。该函数的结果是<ident>
由传入的参数连接在一起组成的。
例如,使用sibling-index()
,之前分享的第一个示例可以重写如下:
.parent { timeline-scope: all; } nav li { animation-timeline: ident("--tl-" sibling-index()); /* --tl-1, --tl-2, … */ } main div { view-timeline-name: ident("--tl-" sibling-index()); /* --tl-1, --tl-2, … */ }
无论标记中使用了多少元素,此代码都会自动缩放。
更多示例
ident()
当您将该函数与其他函数/特性结合使用时,该函数会大放异彩。我已经提到过sibling-index()
,另一个这样的函数是attr()
您可以使用它将 HTML 属性的值导入 CSS 的函数。
例如:
.item { view-timeline-name: ident("--item-" attr(id) "-tl"); } label { animation-name: ident("--item-" attr(for) "-tl"); }
对于具有像、和 这样的s.item
的元素;结果s 分别为、和。id
beach
house
bike
view-timeline-name
--item-beach-tl
--item-house-tl
--item-bike-tl
或者这里有一个更高级的示例,它首先id
从中读取属性.card
并将其存储到自定义属性中。由于自定义属性在继承之前计算,因此子级可以很好地引用该自定义属性。
.card[data-view-transition-id] { --id: attr(data-view-transition-id); /* E.g. card1, card2, card3, … */ view-transition-name: var(--id); view-transition-class: card; h1 { view-transition-name: ident(var(--id) "-title"); /* E.g. card1-title, card2-title, card3-title, … */ view-transition-class: card-title; } .content { view-transition-name: ident(var(--id) "-content"); /* E.g. card1-content, card2-content, card3-content, … */ view-transition-class: card-content; } }
常问问题
作为今天 CSS WG 讨论的一部分,我准备了一份常见问题的简短列表:
为什么我们需要函数?难道不能直接把所有东西粘合在一起吗?例如view-transition-name: var(--id) "title";
?
解析目的。想想简写,例如scroll-timeline
,很难检测到它所包含的全写。
如果ident()
不明确标识由哪些部分组成:
scroll-timeline: inline "tl-" var(--id)
scroll-timeline: "tl-" var(--id) inline
很清楚的知道ident()
什么是组合:
scroll-timeline: inline ident("tl-" var(--id))
scroll-timeline: ident("tl-" var(--id)) inline
为什么不使用重新设计的attr()
可以解析标识的版本?例如attr(foo type(<custom-ident>))
?
该ident()
功能不止于此atrr()
,它还允许您将多段字符串粘合在一起,例如ident("view-" attr(data-vt-id))
或ident("view-" attr(data-type) "-" attr(data-sequence))
。
需要粘合的部件也可以来自其他元素,通过将它们存储到自定义属性中。
那么构造<dashed-ident>
怎么样?
放在"--"
开头,例如ident("--item-tl-" attr(data-itemnum))
是否需要添加该attr()
函数(这会使你的例子看起来更短)? type(<custom-ident>)
否,当未<attr-type>
指定时,<attr-name>
将被解析为 CSS 字符串。由于也ident()
设计为接受<string>
值,因此它可以正常工作。
为什么不依赖类似…-name: auto
自动生成标识的东西呢?
解决方案的问题…-name: auto
在于:
这些仅适用于特定功能,但
ident()
可以用于所有使用标识的功能。它们会生成一个您无法观察到的标识。这意味着您以后无法引用该生成的标识。对于容器、滚动时间轴等功能,您需要能够从标记中的其他地方引用该标识。
它们只对目标元素本身有意义。
ident()
您可以将值存储在自定义属性中,以将值传递给子元素。当多个元素需要使用相同的标识时(在页面生命周期的不同时间),这种方法不起作用。请参阅https://codepen.io/bramus/pen/PogVZwb等理想演示,其中
title-item-1
生成的名称有条件地应用于两个不同的元素。
所提出的方案ident()
没有这些限制;它超越了像这样的每个功能解决方案…-name: auto
。
网友评论文明上网理性发言 已有0人参与
发表评论: