Tạo ảnh động theo kích thước nội tại

Tính năng web: calc-size() interpolate-size

Trước đây, để tạo ảnh động cho các phần tử có kích thước động như block-size: auto hoặc inline-size: max-content, bạn phải sử dụng JavaScript hoặc các thủ thuật "max-height" không ổn định. Thuộc tính interpolate-size và hàm calc-size() cho phép trình duyệt nội suy giữa các từ khoá về độ dài cố định và kích thước nội tại.

Các bước triển khai

  1. Chọn sử dụng nội suy từ khoá: Áp dụng interpolate-size: allow-keywords cho một phần tử mẹ (thường là :root) để bật hiệu ứng chuyển đổi cho các thuộc tính sử dụng từ khoá nội tại.
  2. Xác định hiệu ứng chuyển đổi: Đặt transition cho thuộc tính định cỡ (ví dụ: block-size, inline-size) trên phần tử mục tiêu.
  3. Sử dụng từ khoá nội tại: Thay đổi thuộc tính định cỡ thành một từ khoá nội tại được hỗ trợ (auto, min-content, max-content, fit-content hoặc (đối với flex-basis) content) trong một lượt tương tác (ví dụ: :hover hoặc một lớp trạng thái).
  4. Thực hiện phép tính (Không bắt buộc): Sử dụng calc-size() nếu bạn cần thực hiện phép toán trên kích thước nội tại (ví dụ: auto + 2rem). calc-size() cũng hỗ trợ từ khoá any cho các phép tính không phụ thuộc vào cơ sở.

Ví dụ: Mẫu mở rộng chung

Bạn có thể áp dụng mẫu này cho bất kỳ vùng chứa nào (chẳng hạn như mục "Hiện thêm" hoặc trình đơn điều hướng) để chuyển đổi giữa chiều cao bị hạn chế và kích thước tự nhiên của phần tử.

/* Opt-in globally for all children */
:root {
  /* MANDATORY: Transitions to intrinsic keywords are disabled by default for compatibility */
  interpolate-size: allow-keywords;
}

.expandable-container {
  /* 1. Define a fixed initial size (or 0) and hide overflow */
  block-size: 100px;
  overflow: hidden;
  
  /* 2. Transition the sizing property */
  transition: block-size 0.4s ease-out;
}

.expandable-container.is-expanded {
  /* 3. Smoothly animate to the intrinsic natural height */
  block-size: auto;
}

Ví dụ: Kích thước nội tại được tính toán

.badge {
  inline-size: 40px;
  overflow: hidden;
  white-space: nowrap;
  transition: inline-size 0.3s ease;
}

.badge:hover {
  /* calc-size(basis, calculation) */
  /* 'size' refers to the evaluated basis (max-content in this case) */
  inline-size: calc-size(max-content, size + 20px);
}

Ví dụ: Chuyển đổi từ kích thước nội tại sang kích thước cố định

Bạn cũng có thể tạo ảnh động theo hướng ngược lại – bắt đầu từ kích thước tự nhiên và thu gọn về một chiều dài cụ thể. Điều này hữu ích cho các thành phần "có thể đóng".

.collapsible-alert {
  /* 1. Start with the natural content height */
  block-size: auto;
  overflow: hidden;
  transition: block-size 0.5s ease-in-out, opacity 0.5s ease;
}

.collapsible-alert.is-dismissed {
  /* 2. Smoothly collapse to zero */
  block-size: 0;
  opacity: 0;
  pointer-events: none;
}

/* MANDATORY Copy-Paste Safety: Disable sizing animations for sensitive users */
@media (prefers-reduced-motion: reduce) {
  .expandable-container,
  .badge,
  .collapsible-alert {
    transition: none !important;
  }
}
// MANDATORY Accessibility Synchronization: Ensure elements collapsed to zero dimensions are removed from the assistive technology tree, and sync aria-expanded states on triggers.
const alertElement = document.querySelector('.collapsible-alert');
alertElement.addEventListener('transitionend', (e) => {
  if (e.propertyName === 'block-size' && alertElement.classList.contains('is-dismissed')) {
    alertElement.hidden = true;
  }
});

// Example trigger syncer
const triggerBtn = document.querySelector('.accordion-trigger');
triggerBtn?.addEventListener('click', () => {
  const isExpanded = triggerBtn.getAttribute('aria-expanded') === 'true';
  triggerBtn.setAttribute('aria-expanded', !isExpanded);
});

Các quy tắc ràng buộc chính

  • Hạn chế về từ khoá với từ khoá: Bạn không thể tạo ảnh động trực tiếp giữa hai từ khoá khác nhau (ví dụ: từ min-content đến max-content). Một đầu của hiệu ứng chuyển đổi phải là độ dài hoặc tỷ lệ phần trăm cố định (ví dụ: 0 đến auto).
  • Cú pháp calc-size: Bên trong calc-size(), bạn không thể kết hợp nhiều từ khoá nội tại trong cùng một biểu thức. Đối số đầu tiên (cơ sở) xác định nội dung mà size đại diện.
  • Yêu cầu chọn sử dụng: Quá trình chuyển đổi sang từ khoá nội tại bị tắt theo mặc định (numeric-only) để duy trì khả năng tương thích ngược. Bạn phải áp dụng interpolate-size: allow-keywords cho phần tử hoặc phần tử gốc. calc-size() đóng vai trò là cơ chế ghi đè theo từng thuộc tính, tự động bật nội suy bất cứ khi nào được sử dụng.

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

interpolate-size và calc-size() là các cải tiến tăng dần. Những trình duyệt không hỗ trợ các thuộc tính này sẽ chuyển ngay đến kích thước mục tiêu.

  • Xuống cấp nhẹ: Đối với các hiệu ứng chuyển đổi block-size: auto đơn giản, các trình duyệt tiêu chuẩn sẽ chỉ chuyển đổi kích thước ngay lập tức. Cách này hoạt động nhưng không được mượt mà.
  • Dự phòng từ khoá thủ công: Khi sử dụng calc-size(), hãy luôn cung cấp một từ khoá dự phòng chuẩn cho các trình duyệt cũ, vì các trình duyệt này sẽ loại bỏ toàn bộ nội dung khai báo calc-size().
.card {
  block-size: auto; /* Fallback for older browsers */
  block-size: calc-size(auto, size); /* Modern browsers use this */
  transition: block-size 0.3s ease;
}