表单字段自动适应内容

Web 功能: field-sizing

默认情况下,<input>、<textarea> 和 <select> 等表单控件具有固定尺寸。无论用户输入或选择的内容量如何,其大小都保持不变。

如需允许这些控件自动缩小或放大以适应其内容(包括占位符),请使用 field-sizing: content CSS 属性。

自动调整大小的表单控件

在输入框、选择框或文本区域上设置 field-sizing: content,可让它们在用户输入或选择选项时动态调整大小。不过,您必须考虑继承的样式、布局默认值和最小/最大限制,以确保提供可靠的用户体验。

为防止出现布局问题,建议在文本输入中同时设置 min-inline-size(或 min-width)和 max-inline-size(或 max-width)以及 field-sizing: content。设置最小尺寸可防止输入框在为空时宽度缩减为零(导致无法点击),而设置最大尺寸可确保输入框不会无限扩展并破坏页面布局。

对于文本区域,允许水平自动调整大小可能会导致用户体验不佳(例如,当用户输入单个字符时,具有长占位符的文本区域会突然水平缩小)。为防止出现这种情况,请为 textarea 应用显式宽度(例如 width: 100%)。这会强制文本区域保持稳定的水平宽度,同时在内容换行时仍垂直自动调整大小。

建议使用 field-sizing: content 在 <select> 元素上设置 max-inline-size(或 max-width),以确保极长的所选选项不会破坏页面布局。

/* Applies horizontal auto-sizing to inputs */
input {
  /* Instructs the element to size itself to fit its content */
  field-sizing: content;

  /* Reset explicit width if inherited from global styles */
  width: auto;

  /* Prevents the input from collapsing and disappearing when empty */
  min-inline-size: 15ch;

  /* Prevents infinite horizontal growth */
  max-inline-size: 50ch;
}

textarea {
  /* Instructs the element to size itself to fit its content */
  field-sizing: content;

  /* Reset explicit height if inherited from global styles */
  height: auto;

  /* Use a fixed width to prevent jarring horizontal shifts when replacing a long placeholder */
  width: 50ch; /* or 100% depending on your layout */

  /* Sets a reasonable minimum height (e.g., 3 lines) for empty textareas */
  min-block-size: 3lh;

  /* Prevents infinite vertical growth. Once a textarea hits this */
  /* height, it will stop growing and show a vertical scrollbar. */
  max-block-size: 10lh;
}

select {
  /* Sizes the select element to fit the active option only */
  field-sizing: content;

  /* Prevents the dropdown from expanding infinitely and breaking the layout */
  max-inline-size: 50ch;
}

重要提示:显式 width 和 height 属性会替换所有表单控件上的 field-sizing: content。如果项目的全局 CSS 将输入、选择或文本区域设置为 width: 100%,则必须在元素上使用 field-sizing: content 将其显式重置为 width: auto(或 width: fit-content),才能使自动调整大小功能正常运行。相反,如果之前已全局设置固定高度,则应在文本区域中明确设置 height: auto。

重要提示:网格和 Flexbox 布局通常会隐式拉伸其子项,以填充可用空间。如果任何使用 field-sizing: content 的表单控件拒绝缩小,请检查其容器的对齐属性,并对表单控件应用 align-self: start 或 justify-self: start 以替换拉伸。

后备策略

field-sizing 应被视为渐进增强。在不支持该属性的浏览器中,表单控件会优雅降级,恢复为默认的固定大小调整行为。用户只需在固定大小的输入框和文本区域内滚动浏览溢出的内容。

如果旧版浏览器绝对需要动态增长字段,您必须使用特征检测和复杂的解决方法。最可靠的 textarea 后备方案是使用 CSS 网格技巧,其中隐藏的伪元素会实时镜像用户的输入,从而强制网格容器(及其内部的 textarea)展开。

<!-- The textarea is wrapped in a container that will mirror its value -->
<div class="growable-textarea" data-replicated-value="">
  <textarea></textarea>
</div>
// Only attach the fallback event listeners if field-sizing is unsupported
if (!CSS.supports('field-sizing', 'content')) {
  document.querySelectorAll('.growable-textarea > textarea').forEach(textarea => {
    textarea.addEventListener('input', () => {
      textarea.parentNode.dataset.replicatedValue = textarea.value;
    });
  });
}
/* Only apply the fallback if field-sizing is NOT supported */
@supports not (field-sizing: content) {
  .growable-textarea {
    display: grid;
  }

  /* The pseudo-element and textarea must share the exact same cell, font, and padding */
  .growable-textarea::after,
  .growable-textarea > textarea {
    grid-area: 1 / 1 / 2 / 2;
    font: inherit;
    padding: 0.5rem;
    border: 1px solid #999;
  }

  /* The pseudo-element renders the copied text invisibly to stretch the grid */
  .growable-textarea::after {
    /* The space is necessary for trailing empty lines to be rendered */
    content: attr(data-replicated-value) " ";
    white-space: pre-wrap;
    visibility: hidden;
  }

  .growable-textarea > textarea {
    resize: none;
    overflow: hidden;
  }
}

鉴于为每个表单控件复制样式和跨 DOM 节点同步状态的复杂性,对于大多数应用,建议依赖固定输入的默认回退行为,除非动态调整大小对用户体验至关重要。