Hiệu ứng CSS làm thay đổi cơ sở định vị của position: fixed

Khi sử dụng position: fixed trong CSS, phần tử thường được căn chỉnh dựa trên khung nhìn (viewport) — tức là cửa sổ trình duyệt. Tuy nhiên, nếu một phần tử cha áp dụng bất kỳ thuộc tính nào sau đây, trình duyệt sẽ tạo ra một khối chứa mới (containing block), khiến phần tử con có position: fixed không còn gắn vào viewport mà chuyển sang định vị tương đối với chính phần tử cha đó:

transform: translateZ(0);     /* bất kỳ giá trị nào khác 'none' */
perspective: 500px;          /* giá trị khác 'none' */
filter: opacity(1);         /* ví dụ: blur(0), brightness(1) */
backdrop-filter: contrast(1); /* cũng phải khác 'none' */

1. Cơ chế hoạt động của transform

Thuộc tính transform không chỉ thay đổi vị trí trực quan mà còn kích hoạt việc tạo lớp hiển thị độc lập (compositing layer). Khi điều này xảy ra:

  • Trình duyệt tách phần tử ra khỏi luồng kết xuất thông thường.
  • Lớp mới có hệ tọa độ riêng, và mọi phần tử con — kể cả những phần tử có position: fixed — đều bị ràng buộc vào hệ tọa độ này.
  • Điều này dẫn đến hành vi "giả cố định": phần tử vẫn giữ thuộc tính fixed về mặt cú pháp, nhưng thực tế lại behave như absolute đối với khối chứa mới.

Ví dụ minh họa:

<div class="container">
  <div class="overlay">Nội dung nổi</div>
</div>
.container {
  transform: scale(1); /* đủ để kích hoạt lớp mới */
}

.overlay {
  position: fixed;
  top: 20px; /* giờ đây là cách 20px từ đỉnh .container, không phải viewport */
}

2. Vai trò của perspective

Khi thiết lập perspective, trình duyệt dựng một bối cảnh 3D riêng cho toàn bộ nội dung bên trong phần tử. Do đó:

  • Các phép biến đổi 3D (như rotateX, translateZ) được tính toán trong không gian đó.
  • Phần tử có position: fixed cũng tuân theo bối cảnh này — nghĩa là gốc tọa độ của nó trở thành điểm tham chiếu của khối cha, chứ không còn là góc trên trái của viewport.

3. Ảnh hưởng từ filterbackdrop-filter

Cả hai thuộc tính này đều yêu cầu trình duyệt thực hiện xử lý hình ảnh ngoài luồng chính (offscreen rendering):

  • filter áp dụng hiệu ứng lên nội dung của phần tử.
  • backdrop-filter xử lý vùng nền phía sau phần tử (ví dụ: hiệu ứng kính mờ).
  • Để đảm bảo hiệu ứng không bị cắt hoặc chồng lấn sai, trình duyệt tạo một lớp render riêng biệt — và do đó, cũng tạo ra một containing block mới.

Ngay cả khi giá trị filter không gây thay đổi thị giác rõ rệt (ví dụ: filter: blur(0) hay opacity(1)), cơ chế vẫn được kích hoạt.

4. Nguyên nhân cốt lõi: Lớp hiển thị và ngữ cảnh xếp chồng

Sự thay đổi hành vi của position: fixed bắt nguồn từ ba yếu tố kỹ thuật liên quan:

  1. Tạo khối chứa mới: Các thuộc tính nói trên buộc trình duyệt xác định lại "gốc" cho các phép tính vị trí.
  2. Phân tách lớp hiển thị: Mỗi lớp compositing có hệ tọa độ riêng, ngăn chặn can thiệp chéo giữa các hiệu ứng.
  3. Quy tắc đặc tả CSS: Theo tiêu chuẩn W3C, nếu phần tử có position: fixed nằm trong một "transform container", thì khối chứa của nó được xác định bởi container đó — không phải viewport.

5. Cách kiểm tra và khắc phục

Để xác minh xem một phần tử có đang nằm trong lớp compositing hay không:

  • Mở Chrome DevTools → More Tools → Layers.
  • Tìm phần tử có viền cam — đó là dấu hiệu của một compositing layer.
  • Nếu thấy lớp đó bao phủ phần tử cha của modal/toast, khả năng cao nguyên nhân nằm ở transform, filter, hoặc perspective.

Các giải pháp thực tế:

  • Dịch chuyển phần tử ra ngoài cây DOM gây nhiễu: Đặt phần tử cần fixed trực tiếp dưới <body>, tránh bị bao bởi bất kỳ phần tử nào có thuộc tính kích hoạt layer.
  • Gỡ bỏ hoặc đặt lại thuộc tính gây ảnh hưởng: Nếu không cần hiệu ứng, thiết lập transform: none, filter: none, v.v.
  • Thay thế bằng position: absolute + JavaScript cập nhật vị trí: Chỉ dùng khi bắt buộc, vì dễ gây trễ và khó bảo trì.

6. Bảng tổng hợp ảnh hưởng

Thuộc tính Mục đích sử dụng Tác động lên fixed
transform Biến đổi 2D/3D: dịch chuyển, xoay, phóng to Tạo khối chứa mới → fixed định vị tương đối với phần tử cha
perspective Thiết lập chiều sâu cho không gian 3D Tương tự trên — do yêu cầu bối cảnh 3D riêng
filter Áp dụng hiệu ứng hình ảnh lên phần tử Bắt buộc offscreen rendering → tạo khối chứa mới
backdrop-filter Áp dụng hiệu ứng lên vùng nền phía sau Cùng cơ chế với filter

Thẻ: css position-fixed Transform perspective filter

Đăng vào ngày 21 tháng 6 lúc 00:39