Obsługa górnej warstwy w Narzędziach deweloperskich w Chrome

Alina Varkki
Alina Varkki

Narzędzia deweloperskie w Chrome dodają obsługę elementów górnej warstwy, aby ułatwić programistom debugowanie kodu wykorzystującego elementy najwyższego poziomu.

Z tego artykułu dowiesz się, czym są elementy górnej warstwy, jak Narzędzia deweloperskie pomagają wizualizować zawartość górnej warstwy w celu zrozumienia i debugowania struktury DOM zawierającej elementy górnej warstwy. Znajdziesz w nim też opis implementacji obsługi górnej warstwy w Narzędziach deweloperskich.

Co to są elementy warstwy górnej i górnej?

Co dokładnie dzieje się wewnętrznie po otwarciu <dialog> w formacie modalnym? 🤔

Jest umieszczona w górnej warstwie. Zawartość z górnej warstwy jest renderowana nad całą pozostałymi. Na przykład okno modalne musi wyświetlać się nad całą zawartością DOM. W takiej sytuacji przeglądarka automatycznie renderuje ten element w „górnej warstwie”, zamiast zmuszać autorów do ręcznej walki z z-index. Element górnej warstwy pojawia się na elemencie, nawet o najwyższej wartości z-index.

Górną warstwę można opisać jako „warstwę nakładającą się najlepiej”. Każdy dokument ma 1 powiązany widoczny obszar, a tym samym również jedną górną warstwę. W górnej warstwie może się jednocześnie znajdować wiele elementów. W takiej sytuacji jedna z nich jest jedna nad drugą. Inaczej mówiąc, wszystkie elementy górnej warstwy są umieszczone w stosie ostatnio, pierwszy na zewnątrz (LIFO) w warstwie górnej.

Element <dialog> nie jest jedynym elementem, który przeglądarka renderuje w górnej warstwie. Obecnie elementami górnej warstwy są: popovery, okna modalne i elementy w trybie pełnoekranowym.

Sprawdź implementację okien dialogowych:

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

Oto prezentacja kilku okien dialogowych z zastosowanymi stylami do tła (tła opisane poniżej):

Co to jest tło?

Na szczęście można dostosować treść znajdującą się pod elementem górnej warstwy.

Każdy element w górnej warstwie ma pseudoelement CSS nazywany tłem.

Tło to pole o rozmiarze widocznego obszaru, które jest renderowane bezpośrednio pod dowolnym elementem górnej warstwy. Pseudoelement ::backdrop umożliwia zakrycie, stylizację lub całkowite ukrycie wszystkiego, co znajduje się pod elementem, gdy znajduje się on najwyżej w warstwie górnej.

Gdy tworzysz wiele elementów modalnych, przeglądarka rysuje tło bezpośrednio pod tym pierwszym elementem i nad innymi elementami pełnoekranowymi.

Tak możesz określić styl tła:

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

Jak wyświetlić tylko pierwsze tło?

Każdy element górnej warstwy ma tło, które należy do stosu górnych warstw. Tła te są zaprojektowane w taki sposób, aby nakładały się na siebie, więc jeśli przezroczystość tła nie wynosi 100%, będą widoczne widoczne pod nim tła.

Aby to zrobić, możesz śledzić identyfikatory produktów w stosie górnej warstwy, jeśli musi być widoczne tylko pierwsze tło w stosie górnej warstwy.

Jeśli dodany element nie jest pierwszym elementem w górnej warstwie, funkcja wywoływana po umieszczeniu elementu w górnej warstwie stosuje do klasy ::backdrop klasę hiddenBackdrop. Ta klasa jest usuwana po usunięciu elementu z górnej warstwy.

Zapoznaj się z kodem podanym w tej przykładowej prezentacji:

Projektowanie obsługi górnej warstwy w Narzędziach deweloperskich

Obsługa górnej warstwy w Narzędziach deweloperskich pomaga programistom zrozumieć koncepcję górnej warstwy i wizualizować zmiany jej zawartości. Te funkcje pomagają deweloperom zidentyfikować:

  • Elementy w górnej warstwie w dowolnym momencie i w ich kolejności.
  • Element na górze stosu w dowolnym momencie.

Obsługa górnej warstwy w Narzędziach deweloperskich pomaga też w wizualizacji pozycji pseudoelementu tła w stosie górnych warstw. Mimo że nie jest to element drzewa, odgrywa ważną rolę w działaniu górnej warstwy i może być przydatny dla programistów.

Funkcje obsługi górnej warstwy umożliwiają:

  1. Obserwuj, które elementy w danej chwili znajdują się na stosie warstw w górnej części ekranu. Stos reprezentacji z górnej warstwy zmienia się dynamicznie w miarę dodawania elementów do górnej warstwy i ich usuwania.
  2. Sprawdź położenie elementu na stosie warstw górnych.
  3. Przejdź z elementu górnej warstwy lub z pseudoelementu tła elementów w drzewie do elementu lub pseudoelementu tła w kontenerze reprezentacji górnej warstwy i z powrotem.

Zobaczmy, jak korzystać z tych funkcji.

Kontener górnej warstwy

Aby ułatwić wizualizację elementów górnej warstwy, Narzędzia deweloperskie dodają do drzewa elementów kontener górnej warstwy. Znajduje się po zamykającym tagu </html>.

Ten kontener umożliwia obserwowanie w dowolnym momencie elementów znajdujących się w stosie górnej warstw. Kontener górnej warstwy to lista linków do elementów górnej warstwy oraz ich tła. Stos reprezentacji z górnej warstwy zmienia się dynamicznie w miarę dodawania elementów do górnej warstwy i ich usuwania.

Aby znaleźć elementy najwyższego poziomu w drzewie elementów lub w kontenerze górnej warstwy, kliknij linki z reprezentacji elementu górnej warstwy w kontenerze górnej warstwy do tego samego elementu w drzewie elementów i z powrotem.

Aby przejść z elementu kontenera górnej warstwy do elementu drzewa górnej warstwy, kliknij przycisk Pokaż obok elementu w kontenerze górnej warstwy.

Przechodzę z linku do kontenera górnej warstwy do elementu.

Aby przejść z elementu drzewa najwyższego poziomu do linku w kontenerze górnej warstwy, kliknij obok niego plakietkę Górna warstwa.

Przechodzenie od elementu do linku do kontenera górnej warstwy.

Możesz wyłączyć dowolną plakietkę, w tym tę górną. Aby wyłączyć plakietki, kliknij je prawym przyciskiem myszy, wybierz Ustawienia plakietki i wyczyść pola wyboru obok plakietek, które chcesz ukryć.

Wyłączam plakietkę.

Kolejność elementów w stosie warstw najwyższego poziomu

Górny kontener warstwy pokazuje elementy w takiej postaci, w jakiej wyświetlają się w stosie, ale w odwrotnej kolejności. Górna część stosu elementów jest ostatnia. Oznacza to, że ostatnim elementem na liście kontenerów górnej warstwy jest element, z którym możesz obecnie wchodzić w interakcje w dokumencie.

Plakietki obok elementów drzewa wskazują, czy elementy należą do górnej warstwy, i zawierają numer pozycji elementu w stosie.

Na tym zrzucie ekranu stos górnych warstw składa się z 2 elementów, a drugi jest na samej górze. Jeśli usuniesz drugi element, pierwszy zostanie przeniesiony na górę.

Kolejność elementów w stosie.

Tło w kontenerze górnej warstwy

Jak już wspomnieliśmy, każdy element górnej warstwy ma pseudoelement CSS nazywany tłem. Możesz zmienić styl tego elementu, warto więc go obejrzeć i zobaczyć jego reprezentację.

W drzewie elementów element tła znajduje się przed tagiem zamykającym elementu, do którego należy. Jednak w kontenerze górnej warstwy link do tła jest wymieniony tuż nad elementem górnej warstwy, do którego należy.

Pozycja stosu tła.

Zmiany w drzewie DOM

Klasa ElementsTreeElement odpowiedzialna za tworzenie poszczególnych elementów drzewa DOM i zarządzanie nimi w Narzędziach deweloperskich nie była wystarczająca, aby wdrożyć kontener warstwy najwyższego poziomu.

Aby wyświetlić kontener górnej warstwy jako węzeł w drzewie, dodaliśmy nową klasę, która tworzy węzły elementów drzewa DevTools. Wcześniej klasa odpowiedzialna za tworzenie elementów Narzędzi deweloperskich była inicjowana co TreeElement za pomocą klasy DOMNode, która jest klasą z backendNodeId i innymi właściwościami związanymi z backendem. Z kolei w backendzie jest przypisany numer backendNodeId.

Węzeł kontenera górnej warstwy, który zawiera listę linków do elementów górnej warstwy, musi działać jak zwykły węzeł elementu drzewa. Ten węzeł nie jest jednak „prawdziwym” węzłem DOM, a backend nie musi tworzyć węzła kontenera górnej warstwy.

Aby utworzyć węzeł frontendu reprezentujący górną warstwę, dodaliśmy nowy typ węzła frontendu tworzony bez: DOMNode. Ten element kontenera górnej warstwy to pierwszy węzeł frontendu bez węzła DOMNode, co oznacza, że istnieje tylko w frontendzie, a backend nie „wie” o nim. Aby zapewnić takie samo działanie jak w przypadku innych węzłów, utworzyliśmy nową klasę TopLayerContainer, która rozszerza klasę UI.TreeOutline.TreeElement, która odpowiada za działanie węzłów frontendowych.

Aby uzyskać odpowiednie miejsce docelowe, klasa renderująca element dołącza TopLayerContainer jako następne elementy tagu <html>.

Nowa plakietka górnej warstwy wskazuje, że element jest w górnej warstwie i służy jako link do skrótu do tego elementu w elemencie TopLayerContainer.

Projekt początkowy

Początkowo planowaliśmy zduplikować elementy górnej warstwy w kontenerze górnej warstwy zamiast tworzyć listę linków do elementów. Nie wdrożyliśmy tego rozwiązania ze względu na sposób działania pobierania elementów podrzędnych elementu w Narzędziach deweloperskich. Każdy element ma wskaźnik nadrzędny używany przy pobieraniu elementów podrzędnych i nie może istnieć wiele wskaźników. Z tego powodu nie można utworzyć węzła, który prawidłowo się rozwija i zawiera wszystkie elementy podrzędne w wielu miejscach w drzewie. Z reguły system nie był projektowany z myślą o zduplikowanych poddrzewach.

Osiągnięcie kompromisu polegało na utworzeniu połączeń do węzłów DOM frontendu zamiast ich duplikowania. Za tworzenie linków do elementów w Narzędziach deweloperskich odpowiada klasa ShortcutTreeElement, która stanowi rozszerzenie UI.TreeOutline.TreeElement. ShortcutTreeElement działa tak samo jak inne elementy drzewa DOM w Narzędziach deweloperskich, ale nie ma odpowiadającego mu węzła w backendzie i ma przycisk, który łączy się z elementem ElementsTreeElement. Każdy element ShortcutTreeElement do węzła najwyższego poziomu ma element podrzędny ShortcutTreeElement, który jest powiązany z pseudoelementem ::backdrop w drzewie DOM Narzędzi deweloperskich.

Początkowy projekt:

Początkowy projekt.

Zmiany protokołu Chrome DevTools Protocol (CDP)

Aby wdrożyć obsługę najwyższego poziomu, wymagane są zmiany w protokole Chrome DevTools Protocol (CDP). CDP to protokół komunikacyjny między Narzędziami deweloperskimi a Chromium.

Musimy dodać:

  • Polecenie do wywołania z frontendu w dowolnym momencie.
  • Zdarzenie aktywujące się w frontendzie po stronie backendu.

CDP: polecenie DOM.getTopLayerElements

Aby wyświetlić bieżące elementy górnej warstwy, potrzebne jest nowe, eksperymentalne polecenie CDP, które zwraca listę identyfikatorów węzłów elementów znajdujących się w warstwie górnej. DevTools wywołuje to polecenie za każdym razem, gdy otwierają się Narzędzia deweloperskie lub zmieniają się elementy górnych warstw. Polecenie będzie wyglądać tak:

  # 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: zdarzenie DOM.topLayerElementsUpdated

Aby uzyskać aktualną listę elementów górnej warstwy, każda zmiana elementów górnej warstwy musi wywołać eksperymentalne zdarzenie CDP. To zdarzenie informuje frontend o zmianie, która następnie wywołuje polecenie DOM.getTopLayerElements i otrzymuje listę nowych elementów.

Wygląda ono tak:

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

Uwagi na temat CDP

Dostępnych było wiele opcji implementacji obsługi CDP górnej warstwy. Inna możliwość to utworzenie zdarzenia, które będzie zwracać listę elementów górnej warstwy, a nie po prostu poinformować interfejs użytkownika o dodaniu lub usunięciu elementu górnej warstwy.

Zamiast polecenia możemy też utworzyć 2 zdarzenia: topLayerElementAdded i topLayerElementRemoved. W tym przypadku otrzymamy element i musielibyśmy zarządzać tablicą elementów górnej warstwy w interfejsie.

Obecnie zdarzenie frontendu wywołuje polecenie getTopLayerElements, aby pobrać listę zaktualizowanych elementów. Gdybyśmy mieli wysłać listę elementów lub konkretnego elementu, który spowodował zmianę przy każdym wywołaniu zdarzenia, moglibyśmy uniknąć jednego etapu wywoływania tego polecenia. W takim przypadku frontend utraci kontrolę nad tym, które elementy są przekazywane.

Wdrożyliśmy to w ten sposób, ponieważ naszym zdaniem lepiej jest, jeśli frontend decyduje, kiedy wysłać żądanie węzłów najwyższego poziomu. Jeśli na przykład górna warstwa jest zwinięta w interfejsie lub użytkownik korzysta z panelu narzędzi deweloperskich, w którym nie ma drzewa elementów, nie trzeba pobierać dodatkowych węzłów, które mogłyby zostać umieszczone w głębokości drzewa.