现在 @property 最近随 Firefox 128 一起发布,我认为尝试一下是个好主意。
使用常规 HTML 和 CSS 时效果很好
@property --a1 {
syntax: '<angle>';
inherits: false;
initial-value: 10deg;
}
.hi1 {
border: 2px solid black;
width: fit-content;
margin: 0 auto;
}
.box1 {
--a1:10deg; /* needed for firefox to have a valid output */
cursor:pointer;
width:250px;
height:200px;
margin:15px;
display:inline-block;
transition:--a1 0.5s;
background:linear-gradient(var(--a1),red ,blue);
}
.box1:hover {
--a1:180deg;
}
body {
text-align:center;
}
<div class="hi1">
<h1>In regular DOM</h1>
<div class="box1"></div>
<div class="box1" style="background:conic-gradient(from var(--a1), red var(--a1),blue)"></div>
<div class="box1" style="background:linear-gradient(calc(180deg - var(--a1)),red ,blue,red )"></div>
</div>
但是如果我在影子 DOM 中使用它,它会突然被完全忽略。
const css = `@property --a2 {
syntax: '<angle>';
inherits: false;
initial-value: 10deg;
}
.hi2 {
border: 2px solid black;
width: fit-content;
margin: 0 auto;
}
.box2 {
--a2:10deg; /* needed for firefox to have a valid output */
cursor:pointer;
width:250px;
height:200px;
margin:15px;
display:inline-block;
transition:--a2 0.5s;
background:linear-gradient(var(--a2),red ,blue);
}
.box2:hover {
--a2:180deg;
}`;
class MyComponent extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'closed' });
root.innerHTML = `
<style>${css}</style>
<div class="hi2">
<h1>In shadow DOM</h1>
<div class="box2"></div>
<div class="box2" style="background:conic-gradient(from var(--a2), red var(--a2),blue)"></div>
<div class="box2" style="background:linear-gradient(calc(180deg - var(--a2)),red ,blue,red )"></div>
</div>`;
}
connectedCallback() {
}
}
customElements.define('my-component', MyComponent);
<my-component>
</my-component>
知道为什么或如何说服它起作用吗?
这是说明问题的 codepen https://codepen.io/true-cc/pen/eYwYJaM
这似乎应该可行,但由于没有浏览器支持它,我猜这是一个规格错误。规格中有这一段:
与 CSS 中的许多概念不同(请参阅CSS 范围 1 §3.5 名称定义构造和继承),属性注册的范围不限于树范围。所有注册,无论它们出现在最外层文档中还是出现在影子树中,都在Document的单个全局注册映射中进行交互。 为什么无法确定注册范围?
当自定义属性作为 Shadow DOM 使用组件的公共 API 的一部分公开时,此全局注册行为将按预期工作。如果外部页面出于不同目的使用同名的自定义属性,那么这已经是需要解决的冲突,并且注册行为不会使情况变得更糟。
但是,如果自定义属性旨在供组件内部私有使用,则建议为该属性指定一个可能唯一的名称,以尽量减少与任何其他上下文发生冲突的可能性。例如,可以通过在属性名称中包含项目名称或一些简短的随机文本字符串来完成。
这说明的是,由于
@property
只是调用全局 CSS.registerProperty()
方法的另一种方式,如果您在 Shadow DOM 中定义这样的规则,它仍然会影响 light DOM,因为只有一个注册表.
但是,没有浏览器支持 Shadow DOM 内的规则,它们都会完全忽略它。
因此,您可以全局声明该规则,或使用
CSS.registerProperty()
,即使浏览器支持定义,如果影子 DOM 无论如何也不会被限定在所述影子 DOM 范围内。
使用全局规则:
const css = `
.hi2 {
border: 2px solid black;
width: fit-content;
margin: 0 auto;
}
.box2 {
--a2:10deg; /* needed for firefox to have a valid output */
cursor:pointer;
width:250px;
height:200px;
margin:15px;
display:inline-block;
transition:--a2 0.5s;
background:linear-gradient(var(--a2),red ,blue);
}
.box2:hover {
--a2:180deg;
}`;
class MyComponent extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'closed' });
root.innerHTML = `
<style>${css}</style>
<div class="hi2">
<h1>In shadow DOM</h1>
<div class="box2"></div>
<div class="box2" style="background:conic-gradient(from var(--a2), red var(--a2),blue)"></div>
<div class="box2" style="background:linear-gradient(calc(180deg - var(--a2)),red ,blue,red )"></div>
</div>`;
}
connectedCallback() {
}
}
customElements.define('my-component', MyComponent);
@property --a2 {
syntax: '<angle>';
inherits: false;
initial-value: 10deg;
}
<my-component>
</my-component>
使用
CSS.registerProperty()
:
const css = `
.hi2 {
border: 2px solid black;
width: fit-content;
margin: 0 auto;
}
.box2 {
--a2:10deg; /* needed for firefox to have a valid output */
cursor:pointer;
width:250px;
height:200px;
margin:15px;
display:inline-block;
transition:--a2 0.5s;
background:linear-gradient(var(--a2),red ,blue);
}
.box2:hover {
--a2:180deg;
}`;
class MyComponent extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'closed' });
root.innerHTML = `
<style>${css}</style>
<div class="hi2">
<h1>In shadow DOM</h1>
<div class="box2"></div>
<div class="box2" style="background:conic-gradient(from var(--a2), red var(--a2),blue)"></div>
<div class="box2" style="background:linear-gradient(calc(180deg - var(--a2)),red ,blue,red )"></div>
</div>`;
CSS.registerProperty({
name: "--a2",
syntax: "<angle>",
inherits: false,
initialValue: "10deg",
});
}
connectedCallback() {
}
}
customElements.define('my-component', MyComponent);
@property --a2 {
syntax: '<angle>';
inherits: false;
initial-value: 10deg;
}
<my-component>
</my-component>