【发布时间】:2021-07-20 15:16:07
【问题描述】:
我开发了一个 HTML Web 组件,其插槽使用 HTML theme 属性来启用子元素的间距(通过对它们应用 margin)。我想使用 CSS 自定义属性 --spacing-size 来控制间距的大小,该属性设置在每个组件实例的 HTML style 属性上。
class VerticalLayout extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
}
connectedCallback() {
this.shadowRoot.innerHTML =
`<style>
:host {
display: flex;
flex-direction: column;
}
:host([theme~="spacing"]) ::slotted(:not(:first-child)) {
margin-top: var(--spacing-size);
}
</style>
<slot></slot>`;
}
}
customElements.define("vertical-layout", VerticalLayout);
当我将我的组件的一个实例添加到另一个实例的槽中时遇到了问题,因为我的 CSS 以槽元素为目标来为它们提供边距。由于在这种情况下,开槽元素 是 我的组件,其值为 --spacing-size 表示 其 子级,因此它获得了为其子级的边距而不是所需的边距在父级内部。
<vertical-layout theme="spacing" style="--spacing-size: 2em;">
<div>No margin on this, it is the first child</div>
<!-- I want a 2em margin on the next element (the size -->
<!-- from the layout it sits within), but it gets 0.2em -->
<!-- because --spacing-size has been redefined -->
<vertical-layout theme="spacing" style="--spacing-size: 0.2em;">
<div>No margin on this, it is the first child</div>
<div>0.2em margin above this</div>
</vertical-layout>
</vertical-layout>
我创建了一个codepen。请参阅 codepen,我通过添加第二个自定义属性 --parent-size 克服了这个问题。 codepen 说明了我期望的布局间距,但是有没有一种聪明的方法可以只使用一个自定义属性来实现相同的行为?
在 codepen 中看到,另一个复杂之处是我明确地将 --spacing-size 设置为 CSS 中的默认值,以便在打开主题但未指定大小时应用。我想这可能会使继承父级中的任何值变得非常困难......
我觉得:host-context() 选择器可能是答案,但我不能完全掌握如何使用它(而且,由于 Safari 不支持它,我无论如何都必须寻找另一种解决方案)。
【问题讨论】:
-
如果我可以结合
:host、:has和::slotted选择器来设置任何内部有另一个插槽的组件的父大小,就像这样:@987654335 @唉,这行不通。 -
我试过了,但它太多了,无法理解你想要什么。你能做更小的sn-ps吗?并使用编辑器中的 [ ] 按钮添加 SO sn-ps 而不是 CodePen。
-
@Danny'365CSI'Engelman,感谢收看,我做了一些编辑,是否更清楚?我真的在想我不能用一个自定义属性来做到这一点,除非......也许有一种方法可以包装添加到插槽中的元素?我还想知道在 connectedCallback 中运行的 JS 是否有可能查看任何父实例(因此越过影子根)并生成我手动添加到我的 codepen 中的 --parent-size 变量?
-
也许您可以用
div包裹嵌套的vertical-layout? div 将获取父级的边距。 -
@Auroratide 我有同样的想法,有没有一种巧妙的方法可以从 Web 组件中做到这一点?我尝试从后端执行此操作,但遇到的一个问题是,在实践中,组件应用了样式(例如宽度:100%),所以我的布局看起来很糟糕——我想我需要一些方法来复制样式也在包装上。
标签: css css-selectors web-component css-variables