使用固有尺寸进行计算

calc-size() 是一个 CSS 函数,用于对 auto、min-content 和 fit-content 等固有尺寸关键字执行数学运算。强制性:仅在需要通过计算或约束修改固有尺寸时使用 calc-size();对于简单的基于关键字的动画(例如 0 到 auto),必须使用 interpolate-size: allow-keywords。

实施步骤

  1. 确定内在基础:确定应以哪个内在关键字(auto、min-content 等)作为计算基础。
  2. 定义限制条件:在第二个参数中使用 clamp()、min() 或 max() 等 CSS 数学函数,对固有尺寸施加设计限制。
  3. 强制性:提供后备方案:请务必在使用 calc-size() 的属性之前立即声明标准大小调整关键字或长度,以确保布局在不受支持的浏览器中仍能正常运行。
  4. 应用逻辑属性:默认使用 inline-size 或 block-size 等逻辑属性,以确保计算结果遵循文档的书写模式。
  5. 可选:渐进增强:将复杂的布局逻辑或动画封装在 @supports (inline-size: calc-size(auto, size + 0px)) 代码块中,以便仅向支持这些功能的浏览器提供高级功能。

基本语法

/* calc-size(<calc-size-basis>, <calc-sum>) — mathematical operations on intrinsic sizing keywords */
.element {
  /* MANDATORY: Always provide a fallback for browsers that do not support calc-size() */
  inline-size: min-content;
  
  /* DO: Use calc-size to modify an intrinsic basis with a calculation or function */
  inline-size: calc-size(min-content, size + 2rem);
}

有效的基准参数 (<calc-size-basis>)

第一个参数定义计算的“基准”大小。

标准关键字:

  • auto:元素的默认大小。
  • min-content:元素在不溢出的情况下可以采用的最小尺寸。
  • max-content:元素在一行中容纳所有内容所需的大小。
  • fit-content:相当于 clamp(min-content, auto, max-content)。
  • content:仅当在 flex-basis 属性中使用 calc-size() 时有效。

特殊参数:

  • any:在特定固有类型未知或嵌套计算时使用的通用基础。
  • 嵌套 calc-size():支持多步或条件计算。
  • <calc-sum>:特定长度、百分比或数学表达式(例如 100px 或 20%)。当使用固定值作为基准时,size 关键字仍然可用(但仅在第二个参数中),并表示该基准的解析值。

强制性:size 关键字在第一个参数 (<calc-size-basis>) 本身中无效。它是一个局部变量,仅用于在第二个实参 (<calc-sum>) 中引用基数。

有效计算参数 (<calc-sum>)

第二个参数是数学表达式。

  • 它通常使用 size 关键字来引用基准的值。
  • 虽然 size 关键字在技术上是可选的,但省略它意味着计算将解析为固定值,完全忽略基准。
  • 可以包含标准数学运算符(+、-、*、/)。
  • 它可以包含 CSS 数学函数,例如 clamp()、min()、max() 和 round()。
  • 强制性:calc-size() 在每次计算中仅允许使用一个固有尺寸值(基准)。您不能在同一 calc-size() 调用中混合使用内在尺寸关键字。

使用场景

添加向固有尺寸过渡和从固有尺寸过渡的动画效果

默认情况下,浏览器无法在长度(例如 0px)和固有关键字(例如 auto)之间进行插值。将关键字封装在 calc-size() 中可使其成为可插值的值。

选择合适的动画工具

  • 强制:使用 interpolate-size: allow-keywords:适用于在不进行任何数学修改的情况下,在固有尺寸(例如 height: 0 到 height: auto)之间进行简单动画。这是简单关键字插值的必需方法,最好通过 :root 全局应用。

    :root {
      /* Best practice: Enable keyword interpolation globally */
      interpolate-size: allow-keywords;
    }
    
    .item {
      height: 0;
      transition: height 0.3s ease;
    }
    
    .item.open {
      /* Simple interpolation from 0 to auto now works without calc-size() */
      height: auto;
    }
    
  • 使用 calc-size():仅当您需要在过渡期间对固有尺寸执行数学计算(例如,添加内边距或限制尺寸)时。

.accordion-content {
  display: block;
  overflow: hidden;
  /* MANDATORY: Fallback value for closed state */
  block-size: 0;
  transition: block-size 0.3s ease-out;
}

.accordion-content.open {
  /* MANDATORY: Fallback value for open state */
  block-size: auto;

  /* 
    DO: Use calc-size(auto, ...) to enable animation from 0 to the element's 
    intrinsic size while doing a calculation (in this case, adding a space of 2rem).
  */
  block-size: calc-size(auto, size + 2rem);
}

强制性:无法直接在两个固有尺寸关键字之间进行插值。过渡的一端必须是长度或百分比。

尊重用户的动作偏好设置

对于患有前庭障碍的用户来说,改变大布局区域大小的动画可能会造成特别大的干扰。强制性要求:始终尊重用户的动画偏好设置,使用 prefers-reduced-motion 媒体查询来简化或尽量减少非必要的动画。常见策略包括完全停用动画、缩短动画时长,或将布局偏移替换为细微的不透明度过渡。

.accordion-content {
  opacity: 0;
  transition: block-size 0.3s ease, opacity 0.3s ease;
}

.accordion-content.open {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .accordion-content {
    /* 
       EXAMPLE: Replacing disruptive layout animations with a subtle fade-in.
       Setting the block-size instantly and transitioning opacity 
       provides a clear state change without large-scale motion.
    */
    transition: opacity 1.5s ease;
  }

  .accordion-content.open {
    /* Jump the size instantly */
    block-size: auto;
  }
}

对固有尺寸应用限制

您可以将 calc-size() 与任何 CSS 数学函数(例如 min()、max()、clamp() 或 round())搭配使用,以确保元素的固有大小保持在设计边界内。

.dynamic-container {
  /* MANDATORY: Always provide a fallback for browsers that do not support calc-size() */
  inline-size: fit-content;

  /* 
    DO: Establish a dynamic size based on content, while:
    1. Enforcing boundaries using CSS math functions (min, clamp, etc.)
    2. Modifying the intrinsic size with fixed or relative offsets
  */
  inline-size: calc-size(fit-content, min(size + var(--extra-space), var(--max-allowed)));
}

重要考虑因素

  • 百分比陷阱:<calc-sum> 内的百分比是根据容器的大小(而非 size 关键字)解析的。例如,calc-size(auto, size + 10%) 会将父级宽度的 10% 添加到元素的 auto 宽度,这可能会导致意外结果或溢出。
  • 计算要求:强制性:对于简单动画(例如 0 到 auto),请使用 interpolate-size: allow-keywords,而不是 calc-size()。只有在布局需要对固有基数进行动态数学调整时,才应使用 calc-size()。
  • 性能说明:为 inline-size 或 block-size 等盒模型属性添加动画效果会触发布局重新计算,这可能会产生高昂的开销。主要针对对布局至关重要的元素使用 calc-size() 动画,因为非布局替代方案不足以满足需求。

后备策略

calc-size() 和 interpolate-size 是渐进增强。在不支持这些属性的浏览器中,这些属性会被忽略,布局仍可正常运行,但针对固有关键字的动画会跳过过渡效果。请务必提供标准关键字或长度作为后备。

.element {
  /* Fallback for browsers that don't support calc-size() */
  inline-size: fit-content; 
  /* Modern browsers will override the fallback */
  inline-size: calc-size(fit-content, size + 2rem);
}

动画和过渡回退

在不支持 calc-size() 或 interpolate-size 的浏览器中,涉及固有尺寸关键字的过渡将无法插值。

  • 优雅降级:默认后备方案是状态之间的“即时跳转”(例如,从 0 跳转到 auto)。这通常是可以接受的,因为布局仍可正常运行。
  • 增强体验:使用 @supports 应用复杂的布局逻辑或额外的样式,这些逻辑或样式只有在可以实现流畅的固有动画时才有意义。
  • 避免使用基于 JS 的测量:虽然您可以使用 JavaScript 来测量元素并手动为其尺寸添加动画效果,但这通常是不必要的,并且可能会导致布局抖动。对于现代 Web 应用,建议采用原生“即时跳转”作为后备方案。

对于动画,后备体验将是瞬间跳转到最终尺寸。如需在 CSS 或 JavaScript 中检测支持情况,请执行以下操作:

/* CSS Feature Detection */
@supports (inline-size: calc-size(auto, size + 0px)) {
  .element {
    /* Apply advanced logic only when supported */
  }
}
/* JavaScript Feature Detection */
if (CSS.supports('inline-size', 'calc-size(auto, size + 0px)')) {
  // Apply advanced sizing or animations
}