Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> HTML

Vấn đề z-index Canvas position:fixed trên Google Chrome

Khi <canvas> có position: fixed và z-index âm (hoặc z-index bất kỳ) với kích thước > 256x256px, Chrome có bug render: các element khác có position: fixed bị hiển thị sai (biến mất, sai vị trí, z-index disorder).

Điều kiện tái hiện

  • Canvas: position: fixed + z-index (thường âm để làm background).
  • Kích thước canvas > 256x256 pixel.
  • Có element khác position: fixed (header, modal, tooltip...).
  • Chỉ xảy ra trên Chrome (Blink engine).

Giải pháp: Bọc cả canvas và fixed elements trong container fixed

<div id="fixedContainer" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -10; pointer-events: none;">
  <canvas id="backgroundCanvas" width="1000" height="300"></canvas>
</div>

<h1 style="position: fixed; top: 20px; z-index: 10;">Tiêu đề cố định</h1>

CSS:

#fixedContainer {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  z-index: -10;        /* Canvas background dưới cùng */
  pointer-events: none; /* Cho click xuyên qua canvas */
  overflow: hidden;    /* Quan trọng: chứa canvas lớn */
}

#backgroundCanvas {
  width: 100%; height: 100%; /* Hoặc width/height attribute lớn */
  display: block;
}

h1 {
  position: fixed;
  z-index: 10; /* Trên canvas container */
}

Tại sao cách này hoạt động?

  • Chrome bug xảy ra khi canvas fixed trực tiếp взаимодействует với stacking context của page.
  • Bọc trong div fixed tạo stacking context riêng cho canvas.
  • Các fixed element khác ở stacking context gốc (root) không bị ảnh hưởng.
  • pointer-events: none trên container cho phép click xuyên qua canvas đến content dưới.

Giải pháp thay thế

1. Không dùng position:fixed cho canvas (Khuyên dùng)

/* Canvas làm background body */
body {
  margin: 0;
  min-height: 100vh;
}
canvas#bg {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  z-index: -1;
  pointer-events: none;
}

2. Giảm kích thước canvas ≤ 256x256 (scale up bằng CSS)

<canvas width="256" height="256" style="width: 1000px; height: 300px; image-rendering: pixelated;"></canvas>

3. Dùng CSS background-image thay vì canvas (nếu tĩnh)

body::before {
  content: '';
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: url('pattern.png') repeat;
  z-index: -10;
  pointer-events: none;
}

Lưu ý

  • Bug này tồn tại lâu năm (Chrome 60+), chưa fix hoàn toàn.
  • Kiểm tra trên Chrome mới nhất trước khi deploy.
  • Luôn test với header/modal fixed khi dùng canvas background lớn.