设置一个元素的长度(高度或宽度)减去另一个元素的可变长度,即 calc(x - y),其中 y 未知

IT技术 javascript jquery css flexbox
2021-03-16 19:07:36

我知道我们可以calc在定义长度时使用

flex-basis: calc(33.33% - 60px);
left: calc(50% - 25px);
height: calc(100em/5);

但是如果长度是可变的呢?

height: calc(100% - <<header with variable height>>);

或者

width: calc(100% - 50px - <<box with variable width>>);

在此处输入图片说明

在 CSS 中是否有标准的方法来做到这一点?

我知道使用 flexbox 和表格可以完成整个任务,但我想知道 CSS 是否提供了更简单的方法。Flexbox、表格和简单的 Javascript 是可接受的替代品。

高度演示

宽度演示

6个回答

您可以使用 CSS 表:

.wrapper {
  display: table;
  width: 100%;
  margin: 15px 0;
}

.horizontal.wrapper > div {
  display: table-cell;
  white-space: nowrap; /* Prevent line wrapping */
  border: 1px solid;
}
.left { width: 100px } /* Minimum width of 100px */
.center { width: 0; }  /* Width given by contents */

.vertical.wrapper { height: 200px; }
.vertical.wrapper > div {
  display: table-row;
}
.vertical.wrapper > div > span {
  display: table-cell;
  border: 1px solid;
}
.top    { height: 100px; } /* Minimum heigth of 100px */
.middle { height: 0; }     /* Height given by content */
.bottom { height: 100%; }  /* As tall as possible */
<div class="horizontal wrapper">
  <div class="left">100px wide</div>
  <div class="center">Auto width, given by contents</div>
  <div class="right">Remaining space</div>
</div>
<div class="vertical wrapper">
  <div class="top"><span>100px tall</span></div>
  <div class="middle"><span>Auto height, given by contents</span></div>
  <div class="bottom"><span>Remaining space</span></div>
</div>

水平情况也可以用浮点数来实现:

#wrapper, .right { overflow: hidden; } /* Establish BFC */
#wrapper > div { border: 1px solid; }
.left, .middle { float: left; }
.left { width: 100px }
<div id="wrapper">
  <div class="left">100px</div>
  <div class="middle">Auto width, given by contents</div>
  <div class="right">Remaining space</div>
</div>

Flexbox 可以做到这一点。

支持 IE10 及更高版本。

JSfiddle 演示

* {
  margin: 0;
  padding: 0;
}
html,
body {
  height: 100%;
}
#container {
  height: 100%;
  display: flex;
  flex-direction: column;
}
#top {
  background-color: lightgreen;
}
#bottom {
  background-color: lightblue;
  flex: 1;
}
<div id="container">
  <div id="top">green box variable height</div>
  <div id="bottom">blue box no longer overflows browser window</div>
</div>

这真的行不通。这是填充其容器的一些 HTML 的 2 个示例。示例#1示例#2一旦放置在 flexbox 中,它们就不再正确填充它们的容器。解决方法在这里,解决方案涉及position: absolute;. 上述解决方案使浏览器处于破坏各种内容的状态。
2021-05-16 19:07:36

我正在寻找简单便携的东西。以同样的方式,可以轻松地跨文档应用 CSS 属性,我正在寻找在此功能的易用性方面类似的东西。

...隔离修复是首选。

水平的:

这只能使用 CSS 来实现。由于您不喜欢flex布局解决方案,下一个最佳选择是表格布局。

您可以放入项目(并完成)的简单 CSS 片段如下所示:

div.flexh {
    display: table; box-sizing: border-box; padding: 0; margin: 0;
}
div.flexh > div { 
    display: table-cell; width: auto; 
    box-sizing: border-box; vertical-align: middle;
}
div.flexh > div:first-child {
    /* Override your custom styling below */
    min-width: 75px; width: 75px; max-width: 75px; 
}
div.flexh > div:last-child { width: 100%; }

然后,您可以根据站点要求将站点特定的样式添加到此基本 CSS。之类的nowrap

该解决方案的两个明显优势是:

  1. 你不需要改变你的标记,也不需要用类来装饰所有的孩子。只需将课程flexh应用于您的父母div,就可以了。

所需的最少标记:

<div class="flexh">
    <div>...</div>
    <div>...</div>
    <div>...</div>
</div>
  1. 您不仅限于三列。您可以根据需要拥有尽可能多的列。第一个将具有固定宽度,最后一个将是灵活的,并且中间的所有列都将获得基于内容的宽度。

演示小提琴:http : //jsfiddle.net/abhitalks/qqq4mq23/

演示片段:


垂直的:

在没有flex布局的情况下实现这一点有点棘手表格布局在这里不起作用,主要是因为它table-row不会按照您的用例的要求保持固定的高度。height上一个table-rowtable-cell仅仅是一个指示所需要的最小的高度。如果空间受限,或者内容超过可用空间,则cellrow将根据内容增加其高度。

根据这里的规格:http : //www.w3.org/TR/CSS21/tables.html#height-layout

'table-row' 元素框的高度在用户代理拥有行中所有可用单元格后计算:它是该行计算的“高度”的最大值,该行中每个单元格的计算“高度”,以及单元格所需的最小高度 (MIN)...

...单元格框的高度是内容所需的最小高度

这种效果可以在这里看到:http : //jsfiddle.net/abhitalks/6eropud3/

调整窗口窗格的大小,您会看到第一行的高度会增加,因为内容无法适应指定的高度,从而达不到目的

因此,您可以使用内部标记(如 div 元素)间接限制高度,或者放弃表格布局并计算灵活布局的高度。在您的用例中,您不想更改标记,因此我不建议使用内部标记。

这里最好的选择将是使用普通的经过时间考验的模型block-level divs的要计算的灵活的高度。正如您已经发现使用 CSS 无法实现的那样,您需要一个小的 JavaScript 片段来为您做到这一点。

一个简单的 JavaScript 片段(没有 jQuery),你可以用 a 包裹window.load并放入你的项目(并完成)看起来像这样:

var flexv = document.querySelectorAll('div.flexv');
/* iterate the instances on your page */    
[].forEach.call(flexv, function(div) {
    var children = [].slice.call(div.children), // get all children
        flexChild = children.splice(-1, 1),     // get the last child
        usedHeight = 0, totalHeight = div.offsetHeight;

    children.forEach(function(elem) {
        usedHeight += elem.offsetHeight; // aggregate the height
    });
    /* assign the calculated height on the last child */
    flexChild[0].style.height = (totalHeight - usedHeight) + 'px';
});

CSS 片段或多或少类似于水平片段,没有表格布局,您也可以将其放入项目并添加额外的特定于站点的样式。所需的最少标记保持不变。

演示小提琴 2:http : //jsfiddle.net/abhitalks/Ltcuxdwf/

演示片段:

注意:正如@LGSon 所指出的,display: inline-table用于演示的 Firefox 不能很好地运行。这仅用于演示,应替换为blockinline-block根据您的用例。


@LGSon:我只看到你的一个演示,并且在垂直布局中没有固定的顶部。如果我遗漏了什么,请告诉我。
2021-04-21 19:07:36
@LGSon:感谢您的观察。(1) 在这种情况下,FF 似乎没有遵循规范。规范明确指出,当缺少表格元素时将生成匿名框。参考这里这里(2) 在任何情况下,基于表的解决方案都不适用于 Op 的用例。inline-table部分是之前尝试的遗留物。它应该是inline-block为了演示目的。很快就会修复答案。
2021-05-06 19:07:36
我使用 制作了问题中的两个演示display: table,所以你的意思是它不起作用,就像我的那样?
2021-05-11 19:07:36
别客气。FF 问题来自这篇实际使用的帖子inline-block因此它们也可能会弄乱您的演示(在 FF 上)。
2021-05-12 19:07:36
由于 FF 不喜欢在表格中包含单元格以外的任何内容,因此垂直解决方案在其上效果不佳。有没有办法用你的脚本来补偿它?
2021-05-15 19:07:36

更新

正如我之前评论的那样,除此之外flex,这也是可以解决的,这是我制作的display: table一个小提琴演示

如果垂直演示还需要固定顶部,这是我原始display:table版本的更新小提琴演示

有时我无法(或不想)使用 flex 或表格,而且我一直在研究使用css calc()css attr()

但是两者都很短,因为calc()只能使用+-*/并且attr()只能返回一个字符串值,不能由calc().

我的建议,使用普通的 javascript,基于这两种方法,在某些时候,可能会被扩展,以便我们可以更好地利用它们。

这就是我希望看到它们工作的方式;

width: calc(100% - attr(this.style.left))

但因为他们没有,我也不能将它添加到我的 css 中,因为它无法正确验证(甚至可能破坏解析,谁知道)我添加了一个变体作为元素的属性,但有一些怪癖以便于计算。

在这种情况下(2 个演示),它看起来像这样:

//height
<div id="bottom" data-calcattr="top,height,calc(100% - toppx)">...</div>

//width 
<div class="box right" data-calcattr="left,width,calc(100% - leftpx)">...</div>

连同下面的脚本,它绝不是在所有属性组合上完全开发/测试的,它确实调整了 div 的大小。

简而言之,当运行时,它获取属性,将其拆分为一个数组,将第一个项目值作为要读取的属性,第二个要设置的属性以及第三个读取值被插入/替换和分配的值到要设置的属性(嗯,仍在努力寻找一种更好的方式来表达这一点,但希望脚本对正在发生的事情足够清楚)。

这是一个显示高度和宽度演示的小提琴,集成,使用相同的脚本。

function calcattr() {
    var els = document.querySelectorAll('[data-calcattr]');
    for (i = 0; i < els.length; i++) {
        var what = els[i].getAttribute('data-calcattr');
        if (what) {
            what = what.split(',');
            var rect = els[i].getBoundingClientRect();
            var parentrect = els[i].parentNode.getBoundingClientRect();
            var brd = window.getComputedStyle(els[i].parentNode,null).getPropertyValue('border-' + what[0] + '-width');            
            what[2] = what[2].replace(what[0],parseInt(rect[what[0]]-parentrect[what[0]]) - parseInt(brd));
            els[i].setAttribute("style", what[1] + ":" + what[2]);
        }
    }
}

在 CSS 中

虽然我从未尝试过,但我相信这会奏效:

.top {
    height:13px;
}

.main {
    height:calc(100% - var(height));
}

http://www.creativebloq.com/netmag/why-you-need-use-css-variables-91412904


在 SASS

$top_height: 50px

.main {
    height: calc(100% - $top_height)
}

CSS calc() 函数中的 Sass 变量

@LGSon 出于重新调整大小的目的,您应该始终使用 % 或 em/ex
2021-04-17 19:07:36
这不是两个样本预处理器吗?.. 如果是这样,例如当浏览器调整大小时,这将如何工作?..你能不能做一个工作演示。
2021-04-20 19:07:36
我知道这一点,但在这种情况下,我看不到它起作用,而且由于我对所有可以以一种或另一种方式解决此问题的解决方案都非常感兴趣,我想请您展示一下您是如何进行这项工作的。
2021-04-20 19:07:36
CSS 变量必须以 为前缀--,例如--height: 13pxheight: calc(100% - var(--height))
2021-04-29 19:07:36
不是由我来证明您的解决方案有效,但是是的,我尝试过但它不起作用。而“var”技术是实验性的,只能在 FF 中使用,这使得今天已经没什么用了。我认为在将其添加为答案之前真正测试您的建议是一个好主意,现在它确实有效。再说一次,你能展示一下你是如何完成这项工作并解决 2 个演示的吗?
2021-05-06 19:07:36