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 fixedtạ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: nonetrê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.