Explore CSS 3D Transforms, transformation matrices, setting viewport depth with perspective, and card flip implementations using preserve-3d and backface-visibility.

This lesson is currently only available in Vietnamese. Please switch the language toggle in the menu to Vietnamese to read the full guide and take the interactive quiz.

Hầu hết giao diện trang web được thiết kế phẳng trên không gian 2D trục $X$ (ngang) và $Y$ (dọc). Tuy nhiên, CSS hiện đại cho phép chúng ta phá vỡ giới hạn này bằng cách bổ sung trục $Z$ (sâu thẳng về phía mắt người nhìn), biến trình duyệt thành một không gian đồ họa 3 chiều chân thực.

Trong bài này, chúng ta sẽ đi sâu vào toán học của các phép biến đổi ma trận (Transform Matrices), cơ chế phối cảnh Perspective và các thuộc tính dựng hình 3D nâng cao như preserve-3dbackface-visibility.

1. Hệ tọa độ 3D trong CSS & Ma trận biến đổi

Hệ tọa độ 3D của CSS được định nghĩa như sau:

  • Trục X: Hướng nằm ngang, tăng từ trái sang phải.
  • Trục Y: Hướng dọc, tăng từ trên xuống dưới (đặc thù đồ họa máy tính).
  • Trục Z: Hướng chiều sâu, tăng từ màn hình hướng về phía mắt người xem.

Mọi phép biến đổi 3D (dịch chuyển, xoay, co giãn) thực chất là các phép nhân ma trận đối với tọa độ điểm trong không gian thuần nhất. CSS biểu diễn chúng bằng một ma trận biến đổi $4 \times 4$:

Ví dụ, ma trận dịch chuyển 3D (3D Translation Matrix) với độ dời $(t_x, t_y, t_z)$:

\[\begin{bmatrix} 1 & 0 & 0 & t_x \\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 & 1 \end{bmatrix}\] \[\begin{bmatrix} \cos\theta & 0 & \sin\theta & 0 \\ 0 & 1 & 0 & 0 \\ -\sin\theta & 0 & \cos\theta & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}\]
📖 Tài liệu tham khảo & Hướng dẫn tính ma trận
Để tìm hiểu chi tiết các bước tính toán và nhân ma trận tuyến tính cho các hàm matrix()matrix3d() trong CSS, bạn có thể tham khảo các nguồn uy tín sau:

2. Perspective — Phối cảnh và Khoảng cách điểm nhìn

Nếu bạn xoay một phần tử 3D quanh trục $Y$ nhưng không thiết lập phối cảnh (Perspective), bạn sẽ không thấy bất kỳ chiều sâu nào cả. Phần tử chỉ trông như bị dẹt lại theo chiều ngang. Đó là bởi vì chưa có phép chiếu góc nhìn lên màn hình.

Thuộc tính perspective xác định khoảng cách từ mắt người xem (điểm nhìn) đến mặt phẳng $Z=0$ (màn hình), ký hiệu là $d$. Công thức phối cảnh toán học để tính tọa độ được chiếu $(x', y')$ từ tọa độ gốc $(x, y, z)$ là:

\[x' = \frac{x}{1 - z/d}, \quad y' = \frac{y}{1 - z/d}\]
🔬 So sánh quan trọng: perspective trên cha vs transform: perspective()
Có hai cách khai báo phối cảnh trong CSS dẫn đến kết quả hiển thị hoàn toàn khác nhau:
  • Gán perspective lên thẻ CHA: Thiết lập một điểm nhìn duy nhất (Single Viewpoint) cho toàn bộ không gian. Phù hợp để làm các cảnh nhiều phần tử (như các mặt của khối rubik) vì góc chiếu lên các con sẽ xiên lệch tự nhiên tùy theo vị trí của chúng.
  • Gán transform: perspective(d) lên phần tử CON: Mỗi phần tử tự sở hữu một điểm nhìn độc lập nằm ngay tâm của nó. Các phần tử sẽ được chiếu thẳng góc, không có sự xiên lệch tự nhiên giữa các phần tử cạnh nhau.

3. preserve-3d và backface-visibility

Khi thiết kế các khối 3D phức tạp chứa các mặt phẳng con lồng nhau, ta bắt buộc phải cấu hình:

  • transform-style: preserve-3d; Chỉ định cho trình duyệt bảo toàn không gian 3D của các phần tử con. Nếu để mặc định (flat), các con sẽ bị ép dẹt phẳng (flattened) lên mặt phẳng của thẻ cha.
  • backface-visibility: hidden; Ẩn mặt sau của phần tử khi nó quay lưng về phía người xem. Rất hữu dụng khi làm hiệu ứng lật thẻ 2 mặt (để mặt trước không bị nhìn xuyên thấu ngược qua mặt sau).

Sân chơi tương tác: 3D Graphics Lab

Sân chơi tương tác dưới đây mô phỏng hiệu ứng Lật thẻ 3D hai mặt (Card Flip). Bạn hãy thay đổi các góc xoay $X, Y$, tiêu cự góc nhìn $d$ (perspective) và bật/tắt các thuộc tính 3D để trực quan hóa cách trình duyệt render chiều sâu đồ họa:

🎨 Sân chơi tương tác: 3D Graphics Lab

Thiết lập Không gian 3D

4000 1234 5678 9010
Card Holder
JS DEVELOPER
js-tools
ACCESS GRANTED
3D Space Active
card.html
<div class="card-scene">
  <div class="card-3d">
    <!-- Mặt trước -->
    <div class="card-face card-face-front">
      <div class="chip"></div>
      <div class="number">4000 1234 5678 9010</div>
    </div>

    <!-- Mặt sau -->
    <div class="card-face card-face-back">
      <div class="secret">ACCESS GRANTED</div>
    </div>
  </div>
</div>
card.css

Trắc nghiệm ôn tập

Câu 1: Điều gì xảy ra đối với các phần tử 3D lồng nhau nếu thuộc tính transform-style của thẻ cha được gán là 'flat'?

Trắc nghiệm ôn tập

Câu 2: Điểm khác biệt cốt lõi khi khai báo 'perspective: 500px' trên thẻ CHA so với 'transform: perspective(500px)' trên thẻ CON là gì?

Related Articles

Bài viết liên quan trong series

Lesson 7: Scroll-Driven Animations — Future of Timeline Control Bài 7: Scroll-Driven Animations — Hoạt Ảnh Theo Trục Cuộn Trang Lesson 5: Keyframes & Animation — Multi-State Motion Control Bài 5: Keyframes & Hoạt Ảnh Phức Tạp — Kiểm Soát Chuyển Động Đa Trạng Thái Back to CSS Course Overview Quay lại Lộ trình Series CSS