Trường biểu mẫu tự động điều chỉnh cho vừa với nội dung

Tính năng web: field-sizing

Theo mặc định, các chế độ điều khiển biểu mẫu như <input>, <textarea> và <select> có kích thước cố định. Kích thước của các thành phần này không đổi, bất kể lượng nội dung mà người dùng nhập hoặc chọn.

Để cho phép các thành phần điều khiển này tự động thu nhỏ hoặc tăng kích thước cho vừa với nội dung (bao gồm cả phần giữ chỗ), hãy sử dụng thuộc tính CSS field-sizing: content.

Tự động định cỡ các thành phần điều khiển biểu mẫu

Việc đặt field-sizing: content trên dữ liệu đầu vào, lựa chọn hoặc vùng văn bản cho phép các thành phần này đổi kích thước linh hoạt khi người dùng nhập hoặc chọn các lựa chọn. Tuy nhiên, bạn phải tính đến kiểu kế thừa, bố cục mặc định và các quy tắc ràng buộc tối thiểu/tối đa để đảm bảo trải nghiệm người dùng hiệu quả.

Để tránh các vấn đề về bố cục, bạn nên đặt cả min-inline-size (hoặc min-width) và max-inline-size (hoặc max-width) cùng với field-sizing: content trên dữ liệu đầu vào dạng văn bản. Kích thước tối thiểu giúp ngăn trường nhập liệu thu gọn về chiều rộng bằng 0 khi trống (khiến người dùng không thể nhấp vào), còn kích thước tối đa đảm bảo trường nhập liệu không mở rộng vô thời hạn và làm hỏng bố cục trang.

Đối với vùng văn bản, việc cho phép tự động đổi kích thước theo chiều ngang có thể gây ra trải nghiệm người dùng không tốt (ví dụ: vùng văn bản có phần giữ chỗ dài sẽ đột ngột thu nhỏ theo chiều ngang khi người dùng nhập một ký tự). Để ngăn chặn điều này, hãy áp dụng chiều rộng rõ ràng (như width: 100%) cho vùng văn bản. Điều này buộc vùng văn bản phải duy trì chiều rộng ngang ổn định trong khi vẫn tự động định cỡ theo chiều dọc khi nội dung xuống dòng.

Bạn nên đặt max-inline-size (hoặc max-width) trên các phần tử <select> bằng field-sizing: content để đảm bảo rằng các lựa chọn đã chọn quá dài không làm hỏng bố cục trang.

/* 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;
}

QUAN TRỌNG: Các thuộc tính width và height rõ ràng sẽ ghi đè field-sizing: content trên tất cả các thành phần điều khiển biểu mẫu. Nếu CSS chung của dự án đặt dữ liệu đầu vào, lựa chọn hoặc vùng văn bản thành width: 100%, thì bạn phải đặt lại các giá trị này thành width: auto (hoặc width: fit-content) một cách rõ ràng trên các phần tử sử dụng field-sizing: content để tính năng tự động đổi kích thước hoạt động. Ngược lại, bạn nên đặt rõ ràng height: auto trên các vùng văn bản nếu chiều cao cố định đã được đặt trên toàn cục trước đó.

QUAN TRỌNG: Bố cục Lưới và Flexbox thường ngầm kéo giãn các phần tử con để lấp đầy không gian có sẵn. Nếu bất kỳ thành phần điều khiển biểu mẫu nào sử dụng field-sizing: content từ chối thu nhỏ, hãy kiểm tra các thuộc tính căn chỉnh của vùng chứa và áp dụng align-self: start hoặc justify-self: start cho thành phần điều khiển biểu mẫu để ghi đè việc kéo giãn.

Chiến lược dự phòng

field-sizing nên được coi là một cải tiến tăng dần. Trong các trình duyệt không hỗ trợ thuộc tính này, các chế độ điều khiển biểu mẫu sẽ xuống cấp nhẹ về hành vi định cỡ cố định mặc định. Người dùng sẽ chỉ trải nghiệm thao tác cuộn thông thường cho nội dung tràn bên trong các phần tử nhập và vùng văn bản có kích thước cố định.

Nếu các trường tăng trưởng linh động là bắt buộc đối với các trình duyệt cũ, thì bạn phải sử dụng tính năng phát hiện tính năng và một giải pháp phức tạp. Phương án dự phòng mạnh mẽ nhất cho vùng văn bản sử dụng thủ thuật Lưới CSS, trong đó một phần tử giả ẩn phản ánh dữ liệu đầu vào của người dùng theo thời gian thực, buộc vùng chứa lưới (và vùng văn bản bên trong) phải mở rộng.

<!-- 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;
  }
}

Do sự phức tạp của việc sao chép kiểu và đồng bộ hoá trạng thái trên các nút DOM cho mọi thành phần điều khiển biểu mẫu, bạn nên dựa vào hành vi dự phòng mặc định của dữ liệu đầu vào cố định cho hầu hết các ứng dụng, trừ phi việc định cỡ động là yếu tố quan trọng đối với trải nghiệm người dùng.