自定义属性是“更改内容菜单”吗?

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您的旅程每个阶段提供云产品。 立即开始使用 200 美元免费信用额度!

PPK 在 “使用自定义属性的两种选择” 中阐述了一个有趣的情况,他与 Stefan Judis 对使用 自定义属性 做同样事情有两种不同的方法。 在一种方法中,链接的悬停和焦点样式使用两个不同的自定义属性处理,每个状态一个。 在另一种方法中,使用单个自定义属性。

两个自定义属性

.component1 {
  --linkcolor: red;
  --hovercolor: blue;
}

.component2 {
  --linkcolor: purple;
  --hovercolor: cyan;
}

a {
  color: var(--linkcolor);
}

a:hover,a:focus {
  color: var(--hovercolor)
}

一个自定义属性

.component1 a {
  --componentcolor: red;
}

.component1 :is(a:hover,a:focus) {
  --componentcolor: blue;
}
	
.component2 a {
  --componentcolor: purple;
}

.component2 :is(a:hover,a:focus) {
  --componentcolor: cyan;
}
	
a {
  color: var(--componentcolor)		
}

使用两个属性有一种更自然的感觉,就像它非常明确地说明了特定自定义属性的用途。 但使用一个自定义属性有很多优点。 不仅是为了减少一个自定义属性,而且自定义属性与单个属性一一对应。

进一步来看,您可以使用一个规则集,每个属性一个自定义属性,为更改内容提供一种类似于“菜单”的选项。 PPK 对此说道:

现在您本质上找到了一个定义文件。 您不仅看到了组件的默认样式,还看到了可能发生变化和不会发生变化的内容。

也就是说,您可以为要更改的任何内容使用自定义属性,而对于不想更改的任何内容,您则不会使用。 这当然是一种有趣的方法,我不会怪任何尝试的人。

.lil-grid {
  /* will change */
  --padding: 1rem;
  padding: var(--padding);
  --grid-template-columns: 1fr 1fr 1fr;
  grid-columns: var(--grid-template-columns);

  /* won't change */
  border: 1px solid #ccc;
  gap: 1rem;
}

我对这种方法的犹豫是,它充其量只是一个提示,表明哪些内容会发生变化,哪些内容不会发生变化。 例如,即使在自定义属性中未设置内容,我仍然可以更改内容。 之后,我可以执行以下操作:

.lil-grid.two-up {
  grid-columns: 1fr 1fr;
}

这会消除自定义属性的使用。 同样,我永远无法更改 --grid-template-columns 的值,这意味着它看起来会在不同的情况下发生变化,但实际上从未发生变化。

同样,我可以执行以下操作:

.lil-grid.thick {
  border-width: 3px;
}

… 即使我最初的组件规则集暗示边框宽度不会发生变化,但它会使用修饰符类发生变化。

因此,为了使这种方法有效,您需要将其视为一种坚持的约定,类似于通用的编码标准。 不过,我担心这会变成一件麻烦事。 对于您决定更改的任何声明,您都必须返回并进行重构,使其成为或不成为自定义属性。

这使我想到了 HTML 和 CSS 的“隐式样式 API”。 我们已经在浏览器中拥有一个样式 API。 HTML 在浏览器中转换为 DOM,我们使用 CSS 对 DOM 进行样式设置。 选择内容,对其进行样式设置。

也许我们不需要一个菜单来显示可以和不可以设置样式的内容,因为 DOM 和 CSS 本身就是这样的。 这并不是说精心制作的自定义属性集不能成为其中的一部分,但它们不需要代表更改和不更改内容的硬性规则。

说到隐式样式 API,Jim Nielsen 在 “Shadow DOM 及其对非官方样式 API 的影响” 中写道:

[…] shadow DOM 破坏了我们多年来在网络上使用的自文档样式 API。

什么样式 API? 如果您想为屏幕上的元素设置样式,您可以打开开发者工具,查看 DOM,找到您想要的元素,找出目标该元素的正确选择器,编写选择器和样式,就完成了。

如果您停下来思考一下,这真是太了不起了。

我想这就是我对 Web 组件最大的不满。 我并不讨厌 Shadow DOM; 事实上,它可能是我最喜欢的 Web 组件方面。 我只是不喜欢我必须为它们发明一个样式 API(类似于内部摆动的自定义属性或 ::part),而不是使用一直为我们服务良好的样式 API:DOM + CSS。