【问题标题】: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 calc() 的值分配给 css 变量,而不是让它延迟计算直到使用 css 变量
【发布时间】:2021-09-04 06:17:54
【问题描述】:

我无法从我能找到的任何解释中确定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 描述符,但这并不重要。

重要的是我将--div-width 设置为calc(100% - 10px) 在一个 800 像素宽的 div 中 - 所以希望它的值是 790 像素。

然而,从这个截图

很明显,计算被延迟到使用变量的地方。因为黄色框距离周围元素仅 10 像素。

有没有办法告诉css将属性的值设置为声明它的元素,而不是使用它的位置。

我确实尝试过代理变量 - 像这样......

          --proxy-width: calc(100% - 10px);
          --div-width: var(--proxy-width);

但这并没有什么不同。

PS 这是一个简单的例子,我实际上想要使用它来控制自定义元素内项目(文本区域)的宽度,具体取决于上下文,因此我可以使元素响应一些外部容器的宽度。

【问题讨论】:

  • 有没有办法告诉css将属性的值设置为声明它的元素,而不是使用它的元素。 --> 不,这个这不是 CSS 变量的设计方式。

标签: css css-variables css-calc


【解决方案1】:

如果我理解正确,您想让元素响应相对于父容器的大小变化。我这样做的方式(但相对于视口)是使用relative length unitsvmin 以及calc() 和CSS 变量。这样,我们可以创建一个“响应单元”,无论它是相对于初始包含块还是其他定位的祖先。

下面的示例显示了一个 &lt;div&gt; 和嵌套的 &lt;textarea&gt;,它由响应单元提供支持。由于 widthheight 计算是相对于视口进行的,即使 &lt;textarea&gt; 是 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>

【讨论】:

  • 是的,我明白这一点。事实上,我使用大众单位作为临时解决方案。但是容器位于网格内,并且从 5 列变为 2 列(使用 @media 查询)。我必须在每个媒体查询中重新定义我的 css 变量,但即使这样你也可以看到它与容器略有不同步。因此寻找基于使用 100% 宽度的解决方案。我觉得奇怪的是,css 文本字符串(即 calc() 函数)的这种“延迟”应用程序在任何关于变量的 css 文档中都没有解释。
  • @akc42 奇怪的是,css 文本字符串的这种“延迟”应用(即 calc() 函数)在任何 css 文档中都没有解释 -- > 那么您正在阅读错误的文档。规范清楚地说明了这一点:自定义属性几乎完全不被评估,除了它们允许和评估 var() 函数的值 w3.org/TR/css-variables-1
  • @TemaniAfif 很高兴知道。感谢分享 w3 规范链接!
【解决方案2】:

我找到了一个“完美”的解决方法!

解决方案是使用 '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”为单位

【讨论】:

    猜你喜欢
    • 2017-05-12
    • 2019-11-12
    • 2016-09-20
    • 2017-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-07
    • 2022-07-08
    相关资源
    最近更新 更多