calc-size()
calc-size()
CSS 函数允许您对 固有尺寸 值执行计算,例如 auto
、fit-content
和 max-content
;这不被常规的 calc()
函数支持。
calc-size()
的返回值也可以插值,从而使尺寸关键字值能够用于动画和过渡。实际上,在属性值中包含 calc-size()
会自动将 interpolate-size: allow-keywords
应用于选择。
但是请注意,interpolate-size
是继承的,因此将其应用于一个元素会为应用于该元素及其子元素的每个属性启用固有尺寸关键字的插值。因此,interpolate-size
是启用固有尺寸动画的首选解决方案。您只应在需要计算时才使用 calc-size()
来启用固有尺寸动画。
语法
/* Pass a value through calc-size() */
calc-size(auto, size)
calc-size(fit-content, size)
/* Perform a calculation */
calc-size(min-content, size + 100px)
calc-size(fit-content, size / 2)
/* Calculation including a function */
calc-size(auto, round(up, size, 50px))
参数
calc-size()
函数的语法如下:
calc-size(<calc-size-basis>, <calc-sum>)
参数为:
<calc-size-basis>
-
您希望在其上执行计算的值(最常见的是固有尺寸)。
<calc-sum>
-
定义要对
<calc-size-basis>
执行的计算的表达式。
返回值
返回一个值,该值等于通过 <calc-sum>
表达式修改的 <calc-size-basis>
。由于 <calc-size-basis>
值是固有尺寸值,因此返回值是修改后的固有尺寸值,其行为类似于输入到函数中的固有尺寸值。
描述
某些浏览器布局算法对固有尺寸关键字有特殊行为。calc-size()
函数明确定义为表示固有尺寸而不是 <length-percentage>
,从而强制执行正确性。calc-size()
允许以安全、明确的方式对固有尺寸值执行计算。
第一个参数 (<calc-size-basis>
) 的有效值
第一个 calc-size()
参数可以是以下固有值之一:
auto
min-content
max-content
fit-content
content
(用于使用flex-basis
调整大小的容器)。
此参数还可以采用一些特殊值:
-
嵌套的
calc-size()
值。这并不是您会经常做的事情,但它确保了使用 CSS 变量 作为<calc-size-basis>
总是有效的,前提是该变量是calc-size()
所设置属性的有效值。例如,这将有效:csssection { height: calc-size(calc-size(max-content, size), size + 2rem); }
以及这个:
css:root { --intrinsic-size: calc-size(max-content, size); } section { height: calc-size(var(--intrinsic-size), size + 2rem); }
-
另一个
<calc-sum>
,其限制与为第二个参数指定的<calc-sum>
相同,只是不能包含size
关键字。您可能不会这样做,因为您不再对固有尺寸值进行计算,但如果自定义属性值是<calc-sum>
,该函数仍然会有效。例如,这将直接有效,或者如果您使用值为300px + 2rem
的自定义属性:csssection { height: calc-size(300px + 2rem, size / 2); }
-
关键字
any
,表示未指定的确定尺寸。在这种情况下,第二个参数中不能包含size
关键字,calc-size()
返回第二个参数计算的结果。例如:csssection { height: calc-size(any, 300px * 1.5); /* Returns 450px */ }
在同一个计算中混合不同的固有尺寸不起作用。例如,max-content - min-content
没有意义。calc-size()
在每个计算中只允许一个固有尺寸值,从而避免了这个问题。
第二个参数 (<calc-sum>
) 的有效值
第二个 calc-size()
参数是 <calc-sum>
表达式。
在此表达式中:
- 关键字
size
表示作为第一个参数指定的<calc-size-basis>
。 - 操作数可以包括
size
,以及在上下文中任何有意义的值类型。 - 可以包含
+
、-
、*
和/
运算符。 - 可以包含其他数学函数,例如
round()
、max()
,甚至是嵌套的calc-size()
。 - 整个表达式必须匹配
<length-percentage>
,并解析为<length>
。
启用固有尺寸值的动画
calc-size()
返回值可以插值,从而可以在 <length-percentage>
值和 calc-size()
固有尺寸返回值之间进行动画。
注意:如果可能,您应避免动画盒模型属性,以减少布局事件并减轻由此对性能造成的影响(请参阅关键渲染路径 > 布局)。
例如,您可以使用过渡来动画容器的 width
在 0
和 auto
之间,如下所示:
section {
width: 0;
transition: width ease 1s;
}
section:hover,
section:focus {
width: calc-size(auto, size);
}
在上述情况下,我们没有计算任何东西——我们将 auto
放入 calc-size()
并将其不变地返回。interpolate-size
属性使得像上述那样的动画在大多数情况下更容易实现,尤其是在有多个动画需要考虑时。它是继承的,因此只需在祖先属性上声明一次,这意味着我们可以不使用 calc-size()
就能在 0
和 auto
之间进行过渡。
只有在固有尺寸动画还需要计算时,才应使用 calc-size()
函数。例如,在以下情况下,我们正在动画 width
并对固有尺寸最终状态应用计算:
section {
width: 0;
transition: width ease 1s;
}
section:hover,
section:focus {
width: calc-size(auto, size + 2rem);
}
calc-size()
有用的一个情况是,当您想要在固有尺寸和同一固有尺寸的修改版本之间进行动画时。这在使用 interpolate-size
和 calc()
时是不可能的。例如,以下 @keyframes
定义动画容器的 width
在 fit-content
和 fit-content
的 70% 之间(使用 calc-size()
计算)。
@keyframes narrower {
from {
width: fit-content;
}
to {
width: calc-size(fit-content, size * 0.7);
}
}
注意:请注意,calc-size()
不支持在两个不同的固有尺寸值之间进行动画。
正式语法
<calc-size()> =
calc-size( <calc-size-basis> , <calc-sum> )
<calc-size-basis> =
<size-keyword> |
<calc-size()> |
any |
<calc-sum>
<calc-sum> =
<calc-product> [ [ '+' | '-' ] <calc-product> ]*
<calc-product> =
<calc-value> [ [ '*' | / ] <calc-value> ]*
<calc-value> =
<number> |
<dimension> |
<percentage> |
<calc-keyword> |
( <calc-sum> )
<calc-keyword> =
e |
pi |
infinity |
-infinity |
NaN
示例
calc-size
的基本用法
此示例演示了使用 calc-size()
对容器进行基本尺寸调整
HTML
HTML 包含一个 <section>
元素,其中包含一些子内容。
<section>
<h2>Favorite quote</h2>
<p>
Fashion is something so ugly it has to be changed every fifteen minutes.
</p>
</section>
CSS
在 CSS 中,我们使用 Flexbox 将子元素在 <section>
内部居中,并将 <section>
的 width
和 height
设置为 calc-size()
函数。width
设置为 fit-content
加 6rem
。height
设置为 auto
乘以二。
section {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: calc-size(fit-content, size + 6rem);
height: calc-size(auto, size * 2);
}
为了简洁起见,其余的 CSS 已隐藏。
结果
我们为文本创建了一些水平和垂直空间,使其居中,而无需使用内边距。
基本 calc-size
动画
此示例演示如何使用 calc-size()
在特定尺寸和固有尺寸之间进行动画。该演示展示了一个角色徽章/“名牌”,可以悬停或聚焦以显示有关角色的信息。显示通过在设定长度和 max-content
之间的 height
过渡来处理。
HTML
HTML 包含一个 <section>
元素,其上设置了 tabindex="0"
,以便它可以接收键盘焦点。<section>
包含 <header>
和 <main>
元素,每个元素都有自己的子内容。
<section tabindex="0">
<header>
<h2>Chris Mills</h2>
</header>
<main>
<p>Chris is the silent phantom of MDN.</p>
<ul>
<li><strong>Height</strong>: 3.03m</li>
<li><strong>Weight</strong>: 160kg</li>
<li><strong>Tech Fu</strong>: 7</li>
<li><strong>Bad Jokes</strong>: 9</li>
</ul>
</main>
</section>
CSS
在 CSS 中,我们将 <section>
的 height
设置为 2.5rem
,将 overflow
设置为 hidden
,以便默认只显示 <header>
,然后指定一个 transition
,在状态更改期间在 1 秒内动画 <section>
的 height
。最后,我们将 <section>
的 height
设置为 :hover
和 :focus
上的 calc-size()
函数调用。函数返回值等同于 max-content
+ 2rem
。
section {
height: 2.5rem;
overflow: hidden;
transition: height ease 1s;
}
section:hover,
section:focus {
height: calc-size(max-content, size + 2rem);
}
为了简洁起见,其余的 CSS 已隐藏。
结果
尝试将鼠标悬停在 <section>
上或通过键盘聚焦它 — 它将动画到其完整高度 + 2rem,显示所有内容并在底部留出 2rems 的额外空间。
根据 fit-content
调整阅读宽度
此示例展示了一个包含文本的容器和一个按钮,可以单击该按钮根据阅读偏好使容器宽度变窄或变宽。
HTML
HTML 包含一个 <section>
元素,其中包含子文本内容,以及一个 <button>
用于更改 <section>
的宽度。
<section class="easy-reader">
<h2>Easy reader</h2>
<p>
Eius velit aperiam ipsa. Deleniti eum excepturi ut magni maxime maxime
beatae. Dicta aperiam est laudantium ut illum facere qui officiis. Sunt
deleniti quam id. Quis sunt voluptatem praesentium minima dolorum autem
consequatur velit.
</p>
<p>
Vitae ab incidunt velit aspernatur deleniti distinctio rerum. Et natus sed
et quos mollitia quia quod. Quae officia ex ea. Ducimus ut voluptatem et et
debitis. Quidem provident laboriosam exercitationem similique deleniti.
Temporibus vel veniam mollitia magni unde a nostrum.
</p>
<button class="width-adjust">Narrower</button>
</section>
CSS
在 CSS 中,我们将 <section>
的 width
默认设置为 fit-content
。然后我们定义两组 @keyframes
,narrower
,它从 fit-content
动画到 fit-content
的 70%(使用 calc-size()
计算),以及 wider
,它动画相同的值但方向相反。最后,我们将这些动画附加到两个类——.narrower
和 .wider
。每个动画都定义为持续一秒,并在完成后保持最终状态。
section {
width: fit-content;
}
@keyframes narrower {
from {
width: fit-content;
}
to {
width: calc-size(fit-content, size * 0.7);
}
}
@keyframes wider {
from {
width: calc-size(fit-content, size * 0.7);
}
to {
width: fit-content;
}
}
.narrower {
animation: narrower 1s ease forwards;
}
.wider {
animation: wider 1s ease forwards;
}
为了简洁起见,其余的 CSS 已隐藏。
JavaScript
JavaScript 提供了一个更窄/更宽的切换功能,当按钮被点击时,它会将相关类应用于 <section>
const widthAdjustBtn = document.querySelector(".width-adjust");
const easyReader = document.querySelector(".easy-reader");
widthAdjustBtn.addEventListener("click", () => {
if (easyReader.classList.length === 1) {
easyReader.classList.add("narrower");
widthAdjustBtn.textContent = "Wider";
} else if (easyReader.classList.contains("wider")) {
easyReader.classList.replace("wider", "narrower");
widthAdjustBtn.textContent = "Wider";
} else if (easyReader.classList.contains("narrower")) {
easyReader.classList.replace("narrower", "wider");
widthAdjustBtn.textContent = "Narrower";
}
});
结果
尝试点击 <button>
几次,以在宽和窄阅读宽度之间调整 <section>
,这是通过根据 fit-content
值操作 width
来实现的。
在 calc-size()
函数内部使用函数
如前所述,可以在 calc-size()
内部使用另一个函数。此示例将 field-sizing: content
设置在 <input>
元素上,使其宽度与输入内容相同,然后使用 calc-size()
内部的 max()
函数来确保 <input>
至少有一个最小尺寸,并且只有当输入文本宽度超过该尺寸时才开始增长——通过将其设置为 fit-content
加 20px
。
HTML
HTML 包含一个 <form>
元素,其中包含三个文本 <input>
类型。每个 <input>
都带有一个相关的 <label>
以使表单可访问,并应用了 maxlength
以防止输入值过长导致表单布局混乱。
<form>
<div>
<label for="name">Name:</label>
<input type="text" id="name" name="name" maxlength="48" />
</div>
<div>
<label for="email">Email:</label>
<input type="email" id="email" name="email" maxlength="48" />
</div>
<div>
<label for="address">Address:</label>
<input type="text" id="address" name="address" maxlength="60" />
</div>
</form>
CSS
在 CSS 中,我们将 <label>
元素的 width
设置为 100px
。我们将 field-sizing: content
设置在 <input>
元素上,使其宽度与输入内容相同——默认情况下,如果未输入任何值,它们将没有宽度。为了解决这个问题,我们将它们的 width
值设置为 calc-size(fit-content, max(100px, size + 20px))
。这意味着即使没有输入任何值,它们也至少有 100px
宽。当输入值宽度超过 100px
时,它们的 width
会变为 fit-content
加 20px
,这意味着它们会随着内容大小增长,但在右侧保留 20px
的间隙。
label {
width: 100px;
}
input {
field-sizing: content;
width: calc-size(fit-content, max(100px, size + 20px));
}
为了简洁起见,其余的 CSS 已隐藏。
结果
尝试在表单输入框中输入一些文本,看看当输入值开始达到 max()
函数强制的最小宽度时,它们是如何增长的。
规范
规范 |
---|
CSS 值和单位模块 Level 5 # calc-size |
浏览器兼容性
加载中…
另见
interpolate-size
calc()
round()
- 在 CSS 中将高度动画到 auto;(以及其他固有尺寸关键字),developer.chrome.com (2024)