About Me

Bạn có hiểu rõ z-index trong CSS hay không ?

Nguyên lý hoạt động của z-index

Nếu bạn là một front-end developer và thường xuyên làm việc với CSS, chắc bạn không còn lạ lẫm gì với z-index. Về lý thuyết thì cách thức hoạt động của z-index rất đơn giản: mỗi element trên trang web được hiển thị ngang và dọc theo 2 trục x và y, hiển thị thứ tự chồng lấn theo trục z. Hình vẽ bên dưới của smashingmagazine thể hiện rất dễ hiểu:

z-index và position

Bây giờ mình sẽ lấy ví dụ cụ thể. Chúng ta có 3 block greenredblue đều trực thuộc trực tiếp một div có class demo. Điều này khiến cho 3 block thuộc cùng một stacking context. Trong cùng một stacking context thì thứ tự trên dưới luôn được đảm bảo theo quy tắc: element nào có z-index cao hơn sẽ hiện lên trên. Nếu chưa có một element nào được set z-index thì thứ tự sẽ phụ thuộc vào thứ tự xuất hiện từ trước ra sau của DOM tree.
<div class="demo">
  <div class="red">
    <span>Red</span>
  </div>
  <div class="green">
    <span>Green</span>
  </div>
  <div class="blue">
    <span>Blue</span>
  </div>
</div>
.demo {
  margin-left: 40px;
  margin-top: 40px;
}
.red, .green, .blue {
  width: 100px;
  height: 100px;
  color: white;
  line-height: 100px;
  text-align: center;
}
.red {
  background: red;
}
.green {
  margin-top: -40px;
  margin-left: 60px;
  background: green;
}
.blue {
  margin-top: -40px;
  margin-left: 120px;
  background: blue;
}

Bây giờ thêm z-index vào 3 block để cho block red nổi lên đầu, block green nổi lên thứ 2 và block blue xuống cuối cùng
.red {
  z-index: 3;
}
.green {
  z-index: 2;
}
.blue {
  z-index: 1;
}
Bạn sẽ ngạc nhiên khi thấy thứ tự không hề thay đổiz-index hoàn toàn không có giá trị trong lúc này!

Lý do ở đây là, z-index hoàn toàn mất tác dụng đối với những element không chỉ định positionlà một trong 3 giá trị absolutefixed hay relative. Mình sẽ chỉnh như sau
.red {
  z-index: 3;
  position: relative;
}
.green {
  z-index: 2;
  position: relative;
}
.blue {
  z-index: 1;
  position: relative;
}
Chúng ta sẽ lập tức thấy hiệu quả của z-index

z-index âm và element không có position

Bây giờ mình lấy ví dụ về z-index âm và element không có thuộc tính position. Block green được bỏ position đi như sau
.red {
  z-index: 3;
  position: relative;
}
.green {
  z-index: 2;
  /*position: relative;*/
}
.blue {
  z-index: 1;
  position: relative;
}

Block green ngay lập tức mất ảnh hưởng của z-index và trờ về vị trí của một block với z-index: 0!
Dĩ nhiên, để ẩn ra sau một block với z-index:0 thì có thể set z-index thành một số âm như với block blue dưới đây

.red {
  z-index: 3;
  position: relative;
}

.green {
  z-index: 2;
  /*position: relative;*/
}

.blue {
  z-index: -1;
  position: relative;
}

Có thể tồn tại rất nhiều Stacking Context !

2 ví dụ bên trên thật dễ phải không :) Vậy hãy thử giải thích bài toán dưới đây.
<div>
  <span class="red">Red</span>
</div>
<div>
  <span class="green">Green</span>
</div>
<div>
  <span class="blue">Blue</span>
</div>
div:first-child {
  opacity: .99;
}
.red, .green, .blue {
  position: absolute;
  width: 100px;
  color: white;
  line-height: 100px;
  text-align: center;
}
.red {
  z-index: 1;
  top: 20px;
  left: 20px;
  background: red;
}
.green {
  top: 60px;
  left: 60px;
  background: green;
}
.blue {
  top: 100px;
  left: 100px;
  background: blue;
}

Rõ ràng là block red có z-index là 1, trong khi 2 block còn lại không chỉ định z-index (đồng nghĩ với việc mang giá trị z-index = 0). Cả 3 block đều có position: absolute nên thông số về z-index là hoàn toàn có giá trị. Tại sao block red lại ở dưới cùng ?
Nếu theo đúng thứ tự thì 3 khối block phải trông như dưới đây:

Để trả lời câu hỏi trên, chúng ta hãy để ý cấu trúc DOM trong bài toán này. redgreenblue bây giờ là 3 span không nằm trực tiếp trong một div, mà nằm trong 3 div là anh chị em với nhau !
Khi này, redgreenblue vẫn thuộc global stacking context chung của DOM tree. Tuy nhiên cần phải chú ý một điểm nữa là red nằm trong một div có thuộc tính opacity: .99! Với opacity, div nói trên đã "mở nhánh" ra thành một stacking context mới. Và z-index:1 của red về thực tế chỉ có giá trị trong nhánh stacking context nói trên.
Điều này có nghĩa là, toàn bộ div chứa red vẫn có thứ tự nhỏ hơn div chứa green và blue (do thứ tự xuất hiện từ trước ra sau của DOM), dẫn đến hiển thị như bài toán ban đầu đặt ra.

Kết luận


z-index là một tính chất hay gây nhức đầu đối với developer mới làm quen CSS. Tuy nhiên nếu nắm bắt tốt về stacking contextposition và những thuộc tính có thể khiến stacking context "mở nhánh" như opacity, thì sẽ phần nào bớt-nhức-đầu hơn :)

Bình luận

Mới hơn Cũ hơn

Ads