Một form nhỏ mà mình từng làm có ô tên chiến dịch rộng gần nửa màn hình dù người dùng chỉ nhập “Sale 8/8”. Sang ô ghi chú thì ngược lại: người dùng gõ ba dòng, textarea vẫn bé tí và phải kéo tay. JavaScript autosize xử lý được, nhưng thêm listener chỉ để một cái ô biết lớn theo nội dung nghe hơi mệt.

field-sizing: content cho browser tự tính kích thước của input, textarea, select và file input theo nội dung. Tính năng này được MDN xếp Baseline 2026, mới khả dụng rộng trên các browser hiện đại từ tháng 06/2026. Mình dựng một form thử với chuỗi tiếng Việt ngắn, dài và textarea nhiều dòng để xem một dòng CSS có đủ dùng không.

Dùng cơ bản chỉ có một dòng

input,
textarea,
select {
  field-sizing: content;
}

Giá trị mặc định là fixed. Khi chuyển sang content, kích thước ưu tiên của control bám vào nội dung hiện có. Input có thể co quanh chuỗi ngắn và nở theo chuỗi dài; textarea tăng chiều ngang đến giới hạn rồi mới tăng chiều cao; select đổi theo option đang chọn.

MDN ghi rõ thuộc tính ảnh hưởng các input nhận text, file input, textarea và select. Nó không phải phiên bản khác của box-sizing; một cái chọn cách control lấy kích thước ưu tiên, cái kia quyết định padding và border được tính vào width/height ra sao.

Bốn loại control form thay đổi kích thước giữa trạng thái ngắn và dài
Ảnh minh họa biên tập: input, textarea, select và file input đều có hành vi content sizing riêng.

Không có min và max thì form dễ chạy quá đà

Thử đầu tiên của mình chỉ bật field-sizing: content. Input trống không có placeholder co gần bằng con trỏ, nhìn như một lỗi render. Nhập một chuỗi dài không có khoảng trắng thì control tiếp tục nở đến khi container chặn lại. Tính năng hoạt động đúng, nhưng giao diện chưa chắc đã đúng ý.

.smart-field {
  field-sizing: content;
  min-inline-size: 10ch;
  max-inline-size: min(100%, 42ch);
}

textarea.smart-field {
  min-block-size: 3lh;
  max-block-size: 12lh;
  resize: vertical;
}

Đây là bộ guardrail mình thấy thực dụng hơn. ch đặt biên ngang theo độ rộng ký tự gần đúng, lh đặt chiều cao theo line-height. min(100%, 42ch) giữ ô không vượt container trên mobile. Textarea vẫn có resize dọc để người dùng tự mở rộng khi nội dung đặc biệt dài.

Các khung form co giãn giữa màn hình điện thoại và desktop với chốt giới hạn
Ảnh minh họa biên tập: min/max là chốt chặn để content sizing không kéo vỡ bố cục.

Placeholder cũng làm thay đổi kích thước ban đầu

Chỗ này khá dễ bất ngờ. Input có placeholder dài sẽ rộng đủ để chứa placeholder trước khi người dùng nhập. Khi bắt đầu gõ một giá trị ngắn, nó có thể co lại về min-width. Nếu form có nhiều placeholder dài ngắn khác nhau, hàng control sẽ nhảy kích thước dù dữ liệu đều đang rỗng.

Mình không dùng placeholder như một đoạn hướng dẫn. Label vẫn nằm ngoài control, còn placeholder chỉ là ví dụ ngắn. Cách này vừa giảm layout thay đổi vừa tốt hơn cho accessibility, vì placeholder biến mất sau khi nhập và không thay thế label được.

Textarea xử lý nhiều dòng ra sao?

Khi chưa chạm giới hạn ngang, textarea có thể nở theo nội dung giống input một dòng. Khi max-inline-size chặn chiều rộng, chữ xuống dòng và control bắt đầu tăng block-size. Đây đúng là hành vi mình cần cho ô ghi chú ngắn: ban đầu gọn, có nội dung mới lớn lên.

Các thuộc tính HTML rows, colssize không còn quyết định preferred size như trước khi field-sizing: content hoạt động. Vì vậy đừng vừa trông chờ rows="4" giữ chiều cao vừa bật content sizing rồi ngạc nhiên. Hãy đặt min/max rõ bằng CSS.

ControlHành vi đáng chú ýGuardrail nên có
Text inputCo sát con trỏ khi rỗngmin-inline-size
TextareaNở ngang rồi xuống dòng và tăng caoMin/max hai trục
SelectĐổi rộng theo option đang chọnMax-width theo container
File inputĐổi theo tên fileOverflow cho tên rất dài

Progressive enhancement để browser cũ không vỡ

Baseline 2026 không có nghĩa mọi máy của người dùng đã nâng cấp. Mình giữ kích thước fixed hợp lý làm fallback rồi chỉ bật content sizing trong @supports. Browser cũ bỏ qua block sau và form vẫn dùng được.

.smart-field {
  inline-size: min(100%, 24rem);
}

@supports (field-sizing: content) {
  .smart-field {
    inline-size: auto;
    field-sizing: content;
    min-inline-size: 10ch;
    max-inline-size: min(100%, 42ch);
  }
}

Cách này giống nguyên tắc mình dùng khi thử CSS text-fit cho tiêu đề tiếng Việt: tính năng mới làm trải nghiệm tốt hơn, nhưng HTML và fallback vẫn phải đứng vững. Với form quan trọng như checkout hoặc đăng ký, nên kiểm tra browser analytics thật trước khi bỏ JavaScript autosize đang ổn.

Control tự lớn lên cũng cần được test cùng overlay và focus. Phần dialog CSS mới có cùng bài học: ít JavaScript hơn không đồng nghĩa được bỏ qua bàn phím, focus và browser cũ.

Chỗ nào không nên dùng?

Không phải control nào nở theo nội dung cũng đẹp. Form nhiều cột cần các cạnh thẳng để quét nhanh có thể trông lộn xộn khi mỗi input một chiều rộng. Ô email, mã đơn hàng hoặc URL có dữ liệu rất dài cũng dễ làm bố cục thay đổi quá nhiều.

  • Dùng tốt cho search box nhỏ, tag editor, tiêu đề ngắn, textarea phản hồi và select compact.
  • Cân nhắc với form nghiệp vụ nhiều cột, nơi alignment quan trọng hơn tiết kiệm chỗ.
  • Không bỏ label, min/max, validation và trạng thái focus chỉ vì control tự co giãn.
  • Test với zoom 200%, chuỗi tiếng Việt dài, email không ngắt và tên file dài.

Mình cũng tránh transition width/height trong lúc gõ. Control chạy theo từng ký tự mà còn animate sẽ tạo cảm giác trễ và làm người dùng khó đoán vị trí. Để browser đổi kích thước ngay lập tức nhìn bình thường hơn.

Kết luận

field-sizing: content giải quyết gọn một nhóm autosize form trước đây thường cần JavaScript. Một dòng CSS đủ để thấy hiệu ứng, nhưng min/max, label và fallback mới làm nó dùng được trong sản phẩm thật. Mình sẽ áp dụng trước cho textarea và các input compact, chưa vội bật toàn bộ form chỉ vì tính năng đã vào Baseline.