Hỗ trợ lớp trên cùng trong Công cụ của Chrome cho nhà phát triển

Công cụ dành cho nhà phát triển của Chrome sẽ hỗ trợ thêm các phần tử lớp trên cùng, giúp nhà phát triển dễ dàng gỡ lỗi mã sử dụng các phần tử lớp trên cùng.

Bài viết này mô tả các phần tử lớp trên cùng, cách DevTools giúp trực quan hoá nội dung lớp trên cùng để hiểu và gỡ lỗi cấu trúc DOM chứa các phần tử lớp trên cùng, cũng như cách triển khai tính năng hỗ trợ lớp trên cùng của DevTools.

Lớp trên cùng và các phần tử lớp trên cùng là gì?

Chính xác thì điều gì sẽ xảy ra trong nội bộ khi bạn mở <dialog> dưới dạng một cửa sổ bật lên? 🤔

Lớp này được đưa vào lớp trên cùng. Nội dung lớp trên cùng hiển thị ở trên tất cả nội dung khác. Ví dụ: hộp thoại phương thức cần xuất hiện trên tất cả nội dung DOM khác, vì vậy, trình duyệt sẽ tự động hiển thị phần tử này trong "lớp trên cùng" thay vì buộc tác giả phải tự chiến đấu với chỉ số z. Phần tử lớp trên cùng xuất hiện ở đầu phần tử ngay cả khi có chỉ mục z cao nhất.

Lớp trên cùng có thể được mô tả là "lớp xếp chồng cao nhất". Mỗi tài liệu có một khung nhìn liên kết duy nhất và do đó, cũng có một lớp trên cùng duy nhất. Nhiều phần tử có thể nằm trong lớp trên cùng cùng một lúc. Khi điều đó xảy ra, các tệp sẽ xếp chồng lên nhau, tệp gần đây nhất ở trên cùng. Nói cách khác, tất cả các phần tử của lớp trên cùng được đặt trong ngăn xếp vào sau, ra trước (LIFO) ở lớp trên cùng.

Phần tử <dialog> không phải là phần tử duy nhất mà trình duyệt hiển thị thành một lớp trên cùng. Hiện tại, các phần tử lớp trên cùng là: cửa sổ bật lên, hộp thoại phương thức và các phần tử ở chế độ toàn màn hình.

Hãy kiểm tra cách triển khai hộp thoại sau:

<main>
  <button onclick="window.dialog.showModal();">Open Dialog</button>
</main>
<dialog id="dialog"></dialog>

Sau đây là một bản minh hoạ có một vài hộp thoại áp dụng kiểu cho phông nền (phông nền được mô tả bên dưới):

Phông nền là gì?

May mắn thay, có một cách để tuỳ chỉnh nội dung bên dưới phần tử lớp trên cùng.

Mỗi phần tử trong lớp trên cùng đều có một phần tử mô phỏng CSS được gọi là phông nền.

Phông nền là một hộp có kích thước bằng khung nhìn được kết xuất ngay bên dưới bất kỳ phần tử lớp trên cùng nào. Phần tử giả ::backdrop cho phép bạn làm mờ, tạo kiểu hoặc ẩn hoàn toàn mọi thứ nằm bên dưới phần tử khi đó là phần tử trên cùng trong lớp trên cùng.

Khi bạn tạo nhiều phần tử theo phương thức phương thức, trình duyệt sẽ vẽ phông nền ngay bên dưới phần tử đó ở phía trước và phía trên các phần tử toàn màn hình khác.

Sau đây là cách tạo kiểu cho phông nền:

/* The browser displays the backdrop only when the dialog.showModal() function opens the dialog.*/
dialog::backdrop {
    background: rgba(255,0,0,.25);
}

Làm cách nào để chỉ hiển thị phông nền đầu tiên?

Mỗi phần tử lớp trên cùng đều có phông nền thuộc ngăn xếp lớp trên cùng. Các phông nền này được thiết kế để chồng lên nhau, vì vậy, nếu độ mờ của một phông nền không phải là 100%, thì các phông nền bên dưới sẽ hiển thị.

Nếu chỉ cần hiển thị phông nền đầu tiên trong ngăn xếp lớp trên cùng, bạn có thể thực hiện việc này bằng cách theo dõi giá trị nhận dạng mục trong ngăn xếp lớp trên cùng.

Nếu phần tử được thêm không phải là phần tử đầu tiên trong lớp trên cùng, thì hàm được gọi khi phần tử được đưa vào lớp trên cùng sẽ áp dụng lớp hiddenBackdrop cho ::backdrop. Lớp này sẽ bị xoá khi phần tử bị xoá khỏi lớp trên cùng.

Hãy xem mã trong bản minh hoạ ví dụ này:

Thiết kế hỗ trợ lớp trên cùng trong Công cụ cho nhà phát triển

Tính năng hỗ trợ DevTools cho lớp trên cùng giúp nhà phát triển hiểu được khái niệm về lớp trên cùng và hình dung cách nội dung của lớp trên cùng thay đổi. Các tính năng này giúp nhà phát triển xác định những thông tin sau:

  • Các phần tử trong lớp trên cùng tại bất kỳ thời điểm nào và thứ tự của các phần tử đó.
  • Phần tử ở đầu ngăn xếp tại bất kỳ thời điểm nào.

Hơn nữa, tính năng hỗ trợ lớp trên cùng của DevTools giúp trực quan hoá vị trí của phần tử giả lập phông nền trong ngăn xếp lớp trên cùng. Mặc dù không phải là phần tử cây, nhưng phần tử này đóng vai trò quan trọng trong cách hoạt động của lớp trên cùng và có thể hữu ích cho nhà phát triển.

Với các tính năng hỗ trợ lớp trên cùng, bạn có thể:

  1. Quan sát xem phần tử nào nằm trong ngăn xếp lớp trên cùng bất cứ lúc nào. Ngăn xếp đại diện cho lớp trên cùng thay đổi linh động khi các phần tử được thêm hoặc xoá khỏi lớp trên cùng.
  2. Xem vị trí phần tử trong ngăn xếp lớp trên cùng.
  3. Chuyển từ phần tử lớp trên cùng hoặc phần tử giả lập phông nền của các phần tử trong cây sang phần tử hoặc phần tử giả lập phông nền trong vùng chứa đại diện lớp trên cùng và quay lại.

Hãy cùng xem cách sử dụng các tính năng này!

Vùng chứa lớp trên cùng

Để giúp hình dung các phần tử lớp trên cùng, DevTools sẽ thêm một vùng chứa lớp trên cùng vào cây phần tử. Thuộc tính này nằm sau thẻ </html> đóng.

Vùng chứa này cho phép bạn quan sát các phần tử trong ngăn xếp lớp trên cùng bất cứ lúc nào. Vùng chứa lớp trên cùng là danh sách các đường liên kết đến các phần tử lớp trên cùng và phông nền của các phần tử đó. Ngăn xếp biểu diễn lớp trên cùng thay đổi linh động khi các phần tử được thêm hoặc xoá khỏi lớp trên cùng.

Để tìm các phần tử lớp trên cùng trong cây phần tử hoặc vùng chứa lớp trên cùng, hãy nhấp vào các đường liên kết từ phần trình bày phần tử lớp trên cùng trong vùng chứa lớp trên cùng đến cùng một phần tử trong cây phần tử và quay lại.

Để chuyển từ phần tử vùng chứa lớp trên cùng đến phần tử cây lớp trên cùng, hãy nhấp vào nút reveal (hiển thị) bên cạnh phần tử trong vùng chứa lớp trên cùng.

Chuyển từ đường liên kết vùng chứa lớp trên cùng đến phần tử.

Để chuyển từ phần tử cây lớp trên cùng đến đường liên kết trong vùng chứa lớp trên cùng, hãy nhấp vào huy hiệu lớp trên cùng bên cạnh phần tử đó.

Chuyển từ một phần tử đến đường liên kết vùng chứa lớp trên cùng.

Bạn có thể tắt bất kỳ huy hiệu nào, bao gồm cả huy hiệu lớp trên cùng. Để tắt huy hiệu, hãy nhấp chuột phải vào bất kỳ huy hiệu nào, chọn Cài đặt huy hiệu rồi bỏ đánh dấu vào các huy hiệu bạn muốn ẩn.

Tắt huy hiệu.

Thứ tự các phần tử trong ngăn xếp lớp trên cùng

Vùng chứa lớp trên cùng hiển thị các phần tử khi chúng xuất hiện trong ngăn xếp nhưng theo thứ tự ngược lại. Phần tử trên cùng của ngăn xếp là phần tử cuối cùng trong danh sách phần tử của vùng chứa lớp trên cùng. Điều này có nghĩa là phần tử cuối cùng trong danh sách vùng chứa lớp trên cùng là phần tử mà bạn hiện có thể tương tác trong tài liệu.

Huy hiệu bên cạnh các phần tử cây cho biết liệu các phần tử đó có thuộc lớp trên cùng hay không và chứa số vị trí của một phần tử trong ngăn xếp.

Trong ảnh chụp màn hình này, ngăn xếp lớp trên cùng bao gồm hai phần tử, trong đó phần tử thứ hai nằm ở đầu ngăn xếp. Nếu bạn xoá phần tử thứ hai, phần tử đầu tiên sẽ di chuyển lên trên cùng.

Thứ tự các phần tử trong ngăn xếp.

Phông nền trong vùng chứa lớp trên cùng

Như đã đề cập ở trên, mỗi phần tử lớp trên cùng đều có một phần tử giả lập CSS có tên là phông nền. Bạn có thể tạo kiểu cho phần tử này, vì vậy, bạn cũng nên kiểm tra và xem phần tử này.

Trong cây phần tử, phần tử phông nền nằm trước thẻ đóng của phần tử mà nó thuộc về. Tuy nhiên, trong vùng chứa lớp trên cùng, đường liên kết phông nền được liệt kê ngay phía trên phần tử lớp trên cùng mà đường liên kết đó thuộc về.

Vị trí ngăn xếp hình nền.

Thay đổi đối với cây DOM

ElementsTreeElement, lớp chịu trách nhiệm tạo và quản lý từng phần tử cây DOM trong DevTools, không đủ để triển khai vùng chứa lớp trên cùng.

Để hiển thị vùng chứa lớp trên cùng dưới dạng một nút trong cây, chúng tôi đã thêm một lớp mới để tạo các nút phần tử cây DevTools. Trước đây, lớp chịu trách nhiệm tạo cây thành phần DevTools đã khởi chạy mọi TreeElement bằng DOMNode. Đây là một lớp có backendNodeId và các thuộc tính khác liên quan đến phần phụ trợ. Đổi lại, backendNodeId được chỉ định trên phần phụ trợ.

Nút vùng chứa lớp trên cùng, có danh sách đường liên kết đến các phần tử lớp trên cùng, cần phải hoạt động như một nút phần tử cây thông thường. Tuy nhiên, nút này không phải là nút DOM "thực" và phần phụ trợ không cần tạo nút vùng chứa lớp trên cùng.

Để tạo một nút giao diện người dùng đại diện cho lớp trên cùng, chúng tôi đã thêm một loại nút giao diện người dùng mới được tạo mà không cần DOMNode. Phần tử vùng chứa lớp trên cùng này là nút giao diện người dùng đầu tiên không có DOMNode, nghĩa là phần tử này chỉ tồn tại trên giao diện người dùng và phần phụ trợ không "biết" về phần tử này. Để có hành vi giống như các nút khác, chúng tôi đã tạo một lớp TopLayerContainer mới mở rộng lớp UI.TreeOutline.TreeElement chịu trách nhiệm về hành vi của các nút giao diện người dùng.

Để đạt được vị trí mong muốn, lớp hiển thị một phần tử sẽ đính kèm TopLayerContainer làm phần tử đồng cấp tiếp theo của thẻ <html>.

Huy hiệu lớp trên cùng mới cho biết phần tử này nằm trong lớp trên cùng và đóng vai trò là đường liên kết đến lối tắt của phần tử này trong phần tử TopLayerContainer.

Thiết kế ban đầu

Ban đầu, kế hoạch là sao chép các phần tử lớp trên cùng vào vùng chứa lớp trên cùng thay vì tạo danh sách đường liên kết đến các phần tử đó. Chúng tôi không triển khai giải pháp này do cách hoạt động của tính năng tìm nạp phần tử con trong DevTools. Mỗi phần tử có một con trỏ mẹ dùng để tìm nạp phần tử con và không thể có nhiều con trỏ. Do đó, chúng ta không thể có một nút mở rộng đúng cách và chứa tất cả các nút con ở nhiều vị trí trong cây. Nhìn chung, hệ thống không được xây dựng để xử lý các cây con trùng lặp.

Giải pháp mà chúng tôi đưa ra là tạo đường liên kết đến các nút DOM ở giao diện người dùng thay vì sao chép các nút đó. Lớp chịu trách nhiệm tạo đường liên kết đến các phần tử trong DevTools là ShortcutTreeElement, lớp này mở rộng UI.TreeOutline.TreeElement. ShortcutTreeElement có hành vi giống như các phần tử cây DOM DevTools khác nhưng không có nút tương ứng ở phần phụ trợ và có nút liên kết đến ElementsTreeElement. Mỗi ShortcutTreeElement đến nút lớp trên cùng có một ShortcutTreeElement con liên kết đến phần trình bày của phần tử giả ::backdrop trong cây DOM của DevTools.

Thiết kế ban đầu:

Thiết kế ban đầu.

Thay đổi đối với Giao thức của Công cụ phát triển Chrome (CDP)

Để triển khai tính năng hỗ trợ lớp trên cùng, bạn cần thay đổi Giao thức công cụ phát triển Chrome (CDP). CDP đóng vai trò là giao thức giao tiếp giữa DevTools và Chromium.

Chúng ta cần thêm các nội dung sau:

  • Lệnh gọi từ giao diện người dùng bất cứ lúc nào.
  • Một sự kiện để kích hoạt trên giao diện người dùng từ phía phụ trợ.

CDP: Lệnh DOM.getTopLayerElements

Để hiển thị các phần tử lớp trên cùng hiện tại, chúng ta cần một lệnh CDP thử nghiệm mới trả về danh sách mã nút của các phần tử nằm trong lớp trên cùng. Công cụ cho nhà phát triển gọi lệnh này bất cứ khi nào Công cụ cho nhà phát triển được mở hoặc khi các phần tử lớp trên cùng thay đổi. Lệnh sẽ có dạng như sau:

  # Returns NodeIds of the current top layer elements.
  # Top layer renders closest to the user within a viewport, therefore, its elements always
  # appear on top of all other content.
  experimental command getTopLayerElements
    returns
      # NodeIds of the top layer elements.
      array of NodeId nodeIds

CDP: Sự kiện DOM.topLayerElementsUpdated

Để có danh sách mới nhất về các phần tử lớp trên cùng, chúng ta cần mọi thay đổi về các phần tử lớp trên cùng để kích hoạt một sự kiện CDP thử nghiệm. Sự kiện này thông báo cho giao diện người dùng về thay đổi, sau đó gọi lệnh DOM.getTopLayerElements và nhận danh sách phần tử mới.

Sự kiện sẽ có dạng như sau:

  # Called by the change of the top layer elements.
  experimental event topLayerElementsUpdated

Những điều cần cân nhắc khi sử dụng CDP

Có nhiều cách để triển khai tính năng hỗ trợ CDP của lớp trên cùng. Một lựa chọn khác mà chúng tôi cân nhắc là tạo một sự kiện sẽ trả về danh sách các phần tử lớp trên cùng thay vì chỉ thông báo cho phần giao diện người dùng về việc thêm hoặc xoá một phần tử lớp trên cùng.

Ngoài ra, chúng ta có thể tạo hai sự kiện thay vì lệnh: topLayerElementAddedtopLayerElementRemoved. Trong trường hợp này, chúng ta sẽ nhận được một phần tử và cần quản lý mảng các phần tử lớp trên cùng ở phần giao diện người dùng.

Hiện tại, một sự kiện giao diện người dùng gọi lệnh getTopLayerElements để lấy danh sách các phần tử đã cập nhật. Nếu gửi danh sách các phần tử hoặc một phần tử cụ thể gây ra thay đổi mỗi khi một sự kiện được kích hoạt, chúng ta có thể tránh được một bước gọi lệnh. Tuy nhiên, trong trường hợp này, giao diện người dùng sẽ mất quyền kiểm soát đối với các phần tử được đẩy.

Chúng tôi triển khai theo cách này vì theo quan điểm của chúng tôi, tốt hơn là giao diện người dùng sẽ quyết định thời điểm yêu cầu các nút lớp trên cùng. Ví dụ: nếu lớp trên cùng bị thu gọn trong giao diện người dùng hoặc người dùng đang sử dụng bảng điều khiển DevTools không có cây phần tử, thì không cần lấy các nút bổ sung có thể nằm sâu hơn trong cây.