如何将 css calc() 的值分配给 css 变量,并且不让它延迟计算直到使用 css 变量
How can I assign the value of a css calc() to a css-variable, and not have it delay the calculation until the css-variable is used
我无法从我能找到的任何解释中确定 css 变量的值何时被设置,所以我进行了测试
html
<div class="flex">
<div class="item1">
<div class="included"></div>
</div>
<div class="item2">
<div class="included"></div>
</div>
</div>
css
:host {
display: grid;
place-content: center;
}
.flex {
display: flex;
flex-direction: column;
width:800px;
height: 300px;
background-color: blue;
--div-width: calc(100% - 10px);
}
.item1, .item2 {
background-color: green;
height: 100px;
}
.item1 {
width: 80%;
}
.item2 {
width: 40%;
}
.included {
width: var(--div-width);
background-color:yellow;
height:50px;
}
请注意,我在自定义元素内进行了测试,因此使用了 :host
描述符,但这并不重要。
重要的是我在 800px 宽的 div 中将 --div-width
设置为 calc(100% - 10px)
- 所以期望它的值为 790px。
不过,从这张截图来看
很明显,计算是在延迟到使用变量的地方。因为黄色框距离周围元素仅 10px。
有没有办法告诉 css 将 属性 的值设置为声明它的元素,而不是使用它的地方。
我确实尝试代理变量 - 就像这样......
--proxy-width: calc(100% - 10px);
--div-width: var(--proxy-width);
但这没什么区别。
PS 这是一个简单的例子,我实际想要使用它的方式是根据上下文控制自定义元素内项目(文本区域)的宽度,因此我可以制作元素响应某些外部容器的宽度变化。
如果我理解正确的话,您想使元素响应相对于父容器的大小变化。我这样做的方式(但相对于视口)是使用 relative length units 之类的 vmin
以及 calc()
和 CSS 变量。这样,我们可以创建一个“响应单元”,无论它是相对于初始包含块还是其他定位的祖先。
下面的示例显示了一个 <div>
嵌套 <textarea>
,由响应单元提供支持。由于此 width
和 height
计算是相对于视口进行的,即使 <textarea>
是 div 的子项。您可以将 vmin
换成一个相对长度单位,它不是相对于视口而是相对于某些祖先元素,例如自定义元素。
.wrapper {
border: 1px solid;
padding: 1rem;
}
textarea {
--w: 150;
--h: 80;
width: 200px; /* fallback width */
height: 200px; /* fallback height */
width: calc(var(--w) * 1vmin);
height: calc(var(--h) * 1vmin);
max-width: 100%;
/* extra styles for demo */
border: 1px solid red;
margin: 0 auto;
}
<div class="wrapper">
<textarea id="demo" name="demo"
rows="5" cols="30">It was a dark and stormy night...
</textarea>
</div>
我找到了一个“完美”的解决方法!
解决这个问题的方法是使用 'resize' 事件来读取你想要使用 100% 的元素的大小,使用 getBoundingClientRect();
并使用返回的宽度将“calc”设置为宽度 px - 随便
因此对于问题中的示例,我将使用此代码
_resize() {
if (this.resizeInProgress) return;
this.resizeInProgress = true;
requestAnimationFrame(() => {
const container = this.shadowRoot.querySelector('.flex');
const bound = container.getBoundingClientRect();
container.style.setProperty('--div-width', `calc(${bound.width}px - 10px)`);
this.resizeInProgress = false;
});
}
我将该函数绑定到自定义元素构造函数中的 this
this.resizeInProgress = true;
this._resize = this._resize.bind(this);
和connectedCallback
中的这个
window.addEventListener('resize', this._resize);
this.resizeInProgress = false;
并在我的 disconnectedCallback
中用
再次删除它
this.resizeInProgress = true;
window.removeEventListener('resize', this._resize);
我保留了 calc()
功能,因为在我的现实生活中,减去的数量是以“em”为单位的
我无法从我能找到的任何解释中确定 css 变量的值何时被设置,所以我进行了测试
html
<div class="flex">
<div class="item1">
<div class="included"></div>
</div>
<div class="item2">
<div class="included"></div>
</div>
</div>
css
:host {
display: grid;
place-content: center;
}
.flex {
display: flex;
flex-direction: column;
width:800px;
height: 300px;
background-color: blue;
--div-width: calc(100% - 10px);
}
.item1, .item2 {
background-color: green;
height: 100px;
}
.item1 {
width: 80%;
}
.item2 {
width: 40%;
}
.included {
width: var(--div-width);
background-color:yellow;
height:50px;
}
请注意,我在自定义元素内进行了测试,因此使用了 :host
描述符,但这并不重要。
重要的是我在 800px 宽的 div 中将 --div-width
设置为 calc(100% - 10px)
- 所以期望它的值为 790px。
不过,从这张截图来看
很明显,计算是在延迟到使用变量的地方。因为黄色框距离周围元素仅 10px。
有没有办法告诉 css 将 属性 的值设置为声明它的元素,而不是使用它的地方。
我确实尝试代理变量 - 就像这样......
--proxy-width: calc(100% - 10px);
--div-width: var(--proxy-width);
但这没什么区别。
PS 这是一个简单的例子,我实际想要使用它的方式是根据上下文控制自定义元素内项目(文本区域)的宽度,因此我可以制作元素响应某些外部容器的宽度变化。
如果我理解正确的话,您想使元素响应相对于父容器的大小变化。我这样做的方式(但相对于视口)是使用 relative length units 之类的 vmin
以及 calc()
和 CSS 变量。这样,我们可以创建一个“响应单元”,无论它是相对于初始包含块还是其他定位的祖先。
下面的示例显示了一个 <div>
嵌套 <textarea>
,由响应单元提供支持。由于此 width
和 height
计算是相对于视口进行的,即使 <textarea>
是 div 的子项。您可以将 vmin
换成一个相对长度单位,它不是相对于视口而是相对于某些祖先元素,例如自定义元素。
.wrapper {
border: 1px solid;
padding: 1rem;
}
textarea {
--w: 150;
--h: 80;
width: 200px; /* fallback width */
height: 200px; /* fallback height */
width: calc(var(--w) * 1vmin);
height: calc(var(--h) * 1vmin);
max-width: 100%;
/* extra styles for demo */
border: 1px solid red;
margin: 0 auto;
}
<div class="wrapper">
<textarea id="demo" name="demo"
rows="5" cols="30">It was a dark and stormy night...
</textarea>
</div>
我找到了一个“完美”的解决方法!
解决这个问题的方法是使用 'resize' 事件来读取你想要使用 100% 的元素的大小,使用 getBoundingClientRect();
并使用返回的宽度将“calc”设置为宽度 px - 随便
因此对于问题中的示例,我将使用此代码
_resize() {
if (this.resizeInProgress) return;
this.resizeInProgress = true;
requestAnimationFrame(() => {
const container = this.shadowRoot.querySelector('.flex');
const bound = container.getBoundingClientRect();
container.style.setProperty('--div-width', `calc(${bound.width}px - 10px)`);
this.resizeInProgress = false;
});
}
我将该函数绑定到自定义元素构造函数中的 this
this.resizeInProgress = true;
this._resize = this._resize.bind(this);
和connectedCallback
中的这个
window.addEventListener('resize', this._resize);
this.resizeInProgress = false;
并在我的 disconnectedCallback
中用
this.resizeInProgress = true;
window.removeEventListener('resize', this._resize);
我保留了 calc()
功能,因为在我的现实生活中,减去的数量是以“em”为单位的