为一个元素设置长度(高度或宽度)减去另一个元素的可变长度,即 calc(x - y),其中 y 未知
Setting a length (height or width) for one element minus the variable length of another, i.e. calc(x - y), where y is unknown
我知道我们可以在定义长度时使用 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 是可接受的替代方案。
Flexbox 可以做到这一点。
支持 IE10 及更高版本。
* {
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>
您可以使用 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>
水平大小写也可以用float实现:
#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>
已更新
正如我 earlier, and besides flex
, this is also solvable using display: table
and here is a fiddle demo我展示的那样。
如果垂直演示也需要固定顶部,这里是我原来的 display:table
版本的更新:fiddle demo
有时我不能(或不想)使用 flex 或 tables,我断断续续地研究过使用 css calc() and css attr().
两者都有不足之处,因为 calc()
只能使用 +-*/
而 attr()
只能 return 一个字符串值,无法通过 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>
连同下面的脚本,它绝不是所有 属性 组合的完全 developed/tested,它确实调整了 div 的大小。
简而言之,运行时,它获取属性,将其拆分为一个数组,将第一个项目值作为属性读取的第一个项目值,第二个项目属性设置和读取值获得 inserted/replaced 并分配给要设置的 属性 的第三个(嗯,仍在研究更好的方式来表达这一点,但希望脚本足够清楚,发生了什么) .
这里是 a fiddle 显示高度和宽度的演示,集成,使用相同的脚本。
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]);
}
}
}
I'm looking for something simple and portable. In the same way a CSS
property can be easily applied across documents, I'm looking for
something similar in terms of ease-of-application for this function.
... isolated fix is preferred.
水平:
这只能使用 CSS 来实现。由于您不喜欢 flex
布局解决方案,下一个最佳选择是 table 布局。
一个简单的 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%; }
然后您可以根据站点要求将 site-specific 样式添加到此基础 CSS。比如,nowrap
等
两个apparent这个方案的优点是:
- 您不需要更改标记,也不需要用 class 装饰所有 children。只需将 class
flexh
应用到您的 parent div
即可。
需要最少的标记:
<div class="flexh">
<div>...</div>
<div>...</div>
<div>...</div>
</div>
- 您不仅限于三列。您可以根据需要拥有尽可能多的列。第一个将具有固定宽度,最后一个将是灵活的,所有列 in-between 将获得 content-based 宽度。
演示 Fiddle:http://jsfiddle.net/abhitalks/qqq4mq23/
演示片段:
div.flexh {
display: table; box-sizing: border-box; padding: 0; margin: 0;
/* Override your custom styling below */
width: 80%; border: 2px solid black;
border-right: 2px dashed black;
font-size: 1em;
}
div.flexh > div {
display: table-cell; width: auto;
box-sizing: border-box; vertical-align: middle;
/* Override your custom styling below */
background-color: lightgreen; border: 1px solid #ddd;
padding: 15px 5px;
}
div.flexh > div:first-child {
/* Override your custom styling below */
min-width: 75px; width: 75px; max-width: 75px;
background-color: orange;
}
div.flexh > div:last-child {
width: 100%;
/* Override your custom styling below */
background: skyblue;
}
<div class="flexh">
<div>75px Fixed Width</div>
<div>Variable Content Width</div>
<div>Flexible Remaining Width</div>
</div>
<hr/>
<div class="flexh">
<div>75px Fixed Width</div>
<div><img src='//placehold.it/128x48/66c' /></div>
<div>Flexible Remaining Width</div>
</div>
<hr/>
<div class="flexh">
<div>75px Fixed Width</div>
<div>Variable TextWidth</div>
<div>
<img src='//placehold.it/128x48/66c' />
<p>Variable ContentWidth</p>
</div>
<div>Flexible Remaining Width</div>
</div>
垂直:
如果没有 flex
布局,实现起来有点棘手。 table 布局在这里不起作用 主要是因为 table-row
不会按照您的要求保持固定高度use-case。 table-row
或 table-cell
上的 height
仅表示所需的最小高度。如果 space 被限制,或者内容超出可用 space,那么 cell
或 row
将根据内容增加其高度。
根据此处的规格:http://www.w3.org/TR/CSS21/tables.html#height-layout
The height of a 'table-row' element's box is calculated once the user
agent has all the cells in the row available: it is the maximum of the
row's computed 'height', the computed 'height' of each cell in the
row, and the minimum height (MIN) required by the cells...
...the height of a cell box is the minimum height required by the
content
这个效果可以在这里看到:http://jsfiddle.net/abhitalks/6eropud3/
(调整window窗格的大小,你会看到第一行的高度会增加,因为内容无法适应指定的高度,因此违背了目的)
因此,您可以使用内部标记(如 div 元素)间接限制高度,或者放弃 table-layout 并计算灵活元素的高度。在您的 use-case 中,您不想更改标记,因此我不建议使用内部标记。
这里的best-bet就是使用普通block
级div
的time-tested模型,灵活计算高度。正如您已经发现 CSS 无法实现的那样,您将需要一个小的 JavaScript 片段来为您做到这一点。
一个简单的 JavaScript 片段( 没有 jQuery),您可以将其包装在 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 片段或多或少类似于水平片段,没有 table 布局,您也可以将其放入您的项目并添加额外的 site-specific 样式。所需的最少标记保持不变。
演示 Fiddle 2: http://jsfiddle.net/abhitalks/Ltcuxdwf/
演示片段:
document.addEventListener("load", flexit);
function flexit(e) {
var flexv = document.querySelectorAll('div.flexv');
[].forEach.call(flexv, function(div) {
var children = [].slice.call(div.children),
flexChild = children.splice(-1, 1),
usedHeight = 0, totalHeight = div.offsetHeight;
children.forEach(function(elem) {
usedHeight += elem.offsetHeight;
});
flexChild[0].style.height = (totalHeight - usedHeight) + 'px';
});
}
div.flexv {
display: inline-table; box-sizing: border-box; padding: 0; margin: 0;
overflow: hidden;
/* Override your custom styling below */
height: 320px; width: 20%; border: 1px solid black; font-size: 1em;
margin: 8px;
}
div.flexv > div {
display: block; height: auto; box-sizing: border-box;
overflow: hidden;
/* Override your custom styling below */
background-color: lightgreen; border: 1px solid #ddd;
padding: 5px 15px;
}
div.flexv > div:first-child {
/* Override your custom styling below */
min-height: 36px; height: 36px; max-height: 36px;
background-color: orange;
}
div.flexv > div:last-child {
height: 100%;
/* Override your custom styling below */
background: skyblue;
}
<div class="flexv">
<div>36px Fixed Height</div>
<div>Variable Content Height</div>
<div>Flexible Remaining Height</div>
</div>
<div class="flexv">
<div>36px Fixed Height</div>
<div><img src='//placehold.it/64x72/66c' /></div>
<div>Flexible Remaining Height</div>
</div>
<div class="flexv">
<div>36px Fixed Height</div>
<div>Variable Text Height</div>
<div>
<img src='//placehold.it/72x48/66c' />
<p>Variable Content Height</p>
</div>
<div>Flexible Remaining Height</div>
</div>
注意:正如@LGSon 所指出的,用于演示的 display: inline-table
在 Firefox 中运行不佳。这仅用于演示,应根据您的 use-case.
替换为 block
或 inline-block
输入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)
}
Sass Variable in CSS calc() function
在容器 css 的两种情况下,您应该放置:
#container {
overflow: hidden;
}
但是,它会隐藏溢出容器的信息。我认为这就是重点,因为你把 white-space: nowrap;
这意味着你不想改变高度,所以你必须隐藏不适合容器的文本。
我知道我们可以在定义长度时使用 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 是可接受的替代方案。
Flexbox 可以做到这一点。
支持 IE10 及更高版本。
* {
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>
您可以使用 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>
水平大小写也可以用float实现:
#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>
已更新
正如我flex
, this is also solvable using display: table
and here is a fiddle demo我展示的那样。
如果垂直演示也需要固定顶部,这里是我原来的 display:table
版本的更新:fiddle demo
有时我不能(或不想)使用 flex 或 tables,我断断续续地研究过使用 css calc() and css attr().
两者都有不足之处,因为 calc()
只能使用 +-*/
而 attr()
只能 return 一个字符串值,无法通过 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>
连同下面的脚本,它绝不是所有 属性 组合的完全 developed/tested,它确实调整了 div 的大小。
简而言之,运行时,它获取属性,将其拆分为一个数组,将第一个项目值作为属性读取的第一个项目值,第二个项目属性设置和读取值获得 inserted/replaced 并分配给要设置的 属性 的第三个(嗯,仍在研究更好的方式来表达这一点,但希望脚本足够清楚,发生了什么) .
这里是 a fiddle 显示高度和宽度的演示,集成,使用相同的脚本。
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]);
}
}
}
I'm looking for something simple and portable. In the same way a CSS property can be easily applied across documents, I'm looking for something similar in terms of ease-of-application for this function.
... isolated fix is preferred.
水平:
这只能使用 CSS 来实现。由于您不喜欢 flex
布局解决方案,下一个最佳选择是 table 布局。
一个简单的 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%; }
然后您可以根据站点要求将 site-specific 样式添加到此基础 CSS。比如,nowrap
等
两个apparent这个方案的优点是:
- 您不需要更改标记,也不需要用 class 装饰所有 children。只需将 class
flexh
应用到您的 parentdiv
即可。
需要最少的标记:
<div class="flexh">
<div>...</div>
<div>...</div>
<div>...</div>
</div>
- 您不仅限于三列。您可以根据需要拥有尽可能多的列。第一个将具有固定宽度,最后一个将是灵活的,所有列 in-between 将获得 content-based 宽度。
演示 Fiddle:http://jsfiddle.net/abhitalks/qqq4mq23/
演示片段:
div.flexh {
display: table; box-sizing: border-box; padding: 0; margin: 0;
/* Override your custom styling below */
width: 80%; border: 2px solid black;
border-right: 2px dashed black;
font-size: 1em;
}
div.flexh > div {
display: table-cell; width: auto;
box-sizing: border-box; vertical-align: middle;
/* Override your custom styling below */
background-color: lightgreen; border: 1px solid #ddd;
padding: 15px 5px;
}
div.flexh > div:first-child {
/* Override your custom styling below */
min-width: 75px; width: 75px; max-width: 75px;
background-color: orange;
}
div.flexh > div:last-child {
width: 100%;
/* Override your custom styling below */
background: skyblue;
}
<div class="flexh">
<div>75px Fixed Width</div>
<div>Variable Content Width</div>
<div>Flexible Remaining Width</div>
</div>
<hr/>
<div class="flexh">
<div>75px Fixed Width</div>
<div><img src='//placehold.it/128x48/66c' /></div>
<div>Flexible Remaining Width</div>
</div>
<hr/>
<div class="flexh">
<div>75px Fixed Width</div>
<div>Variable TextWidth</div>
<div>
<img src='//placehold.it/128x48/66c' />
<p>Variable ContentWidth</p>
</div>
<div>Flexible Remaining Width</div>
</div>
垂直:
如果没有 flex
布局,实现起来有点棘手。 table 布局在这里不起作用 主要是因为 table-row
不会按照您的要求保持固定高度use-case。 table-row
或 table-cell
上的 height
仅表示所需的最小高度。如果 space 被限制,或者内容超出可用 space,那么 cell
或 row
将根据内容增加其高度。
根据此处的规格:http://www.w3.org/TR/CSS21/tables.html#height-layout
The height of a 'table-row' element's box is calculated once the user agent has all the cells in the row available: it is the maximum of the row's computed 'height', the computed 'height' of each cell in the row, and the minimum height (MIN) required by the cells...
...the height of a cell box is the minimum height required by the content
这个效果可以在这里看到:http://jsfiddle.net/abhitalks/6eropud3/
(调整window窗格的大小,你会看到第一行的高度会增加,因为内容无法适应指定的高度,因此违背了目的)
因此,您可以使用内部标记(如 div 元素)间接限制高度,或者放弃 table-layout 并计算灵活元素的高度。在您的 use-case 中,您不想更改标记,因此我不建议使用内部标记。
这里的best-bet就是使用普通block
级div
的time-tested模型,灵活计算高度。正如您已经发现 CSS 无法实现的那样,您将需要一个小的 JavaScript 片段来为您做到这一点。
一个简单的 JavaScript 片段( 没有 jQuery),您可以将其包装在 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 片段或多或少类似于水平片段,没有 table 布局,您也可以将其放入您的项目并添加额外的 site-specific 样式。所需的最少标记保持不变。
演示 Fiddle 2: http://jsfiddle.net/abhitalks/Ltcuxdwf/
演示片段:
document.addEventListener("load", flexit);
function flexit(e) {
var flexv = document.querySelectorAll('div.flexv');
[].forEach.call(flexv, function(div) {
var children = [].slice.call(div.children),
flexChild = children.splice(-1, 1),
usedHeight = 0, totalHeight = div.offsetHeight;
children.forEach(function(elem) {
usedHeight += elem.offsetHeight;
});
flexChild[0].style.height = (totalHeight - usedHeight) + 'px';
});
}
div.flexv {
display: inline-table; box-sizing: border-box; padding: 0; margin: 0;
overflow: hidden;
/* Override your custom styling below */
height: 320px; width: 20%; border: 1px solid black; font-size: 1em;
margin: 8px;
}
div.flexv > div {
display: block; height: auto; box-sizing: border-box;
overflow: hidden;
/* Override your custom styling below */
background-color: lightgreen; border: 1px solid #ddd;
padding: 5px 15px;
}
div.flexv > div:first-child {
/* Override your custom styling below */
min-height: 36px; height: 36px; max-height: 36px;
background-color: orange;
}
div.flexv > div:last-child {
height: 100%;
/* Override your custom styling below */
background: skyblue;
}
<div class="flexv">
<div>36px Fixed Height</div>
<div>Variable Content Height</div>
<div>Flexible Remaining Height</div>
</div>
<div class="flexv">
<div>36px Fixed Height</div>
<div><img src='//placehold.it/64x72/66c' /></div>
<div>Flexible Remaining Height</div>
</div>
<div class="flexv">
<div>36px Fixed Height</div>
<div>Variable Text Height</div>
<div>
<img src='//placehold.it/72x48/66c' />
<p>Variable Content Height</p>
</div>
<div>Flexible Remaining Height</div>
</div>
注意:正如@LGSon 所指出的,用于演示的 display: inline-table
在 Firefox 中运行不佳。这仅用于演示,应根据您的 use-case.
block
或 inline-block
输入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)
}
Sass Variable in CSS calc() function
在容器 css 的两种情况下,您应该放置:
#container {
overflow: hidden;
}
但是,它会隐藏溢出容器的信息。我认为这就是重点,因为你把 white-space: nowrap;
这意味着你不想改变高度,所以你必须隐藏不适合容器的文本。