Chrome DevTools의 최상위 레이어 지원

Alina Varkki
Alina Varkki

Chrome DevTools에 최상위 레이어 요소 지원이 추가되어 개발자가 최상위 레이어 요소를 사용하는 코드를 더 쉽게 디버그할 수 있습니다.

이 문서에서는 최상위 레이어 요소의 정의, DevTools가 최상위 레이어 콘텐츠를 시각화하여 최상위 레이어 요소가 포함된 DOM 구조를 이해하고 디버그하는 방법, DevTools 최상위 레이어 지원이 구현되는 방식을 설명합니다.

상단 레이어와 최상위 레이어 요소는 무엇인가요?

<dialog>를 모달로 열면 내부적으로 정확히 어떻게 되나요? 🤔

최상위 레이어에 배치됩니다. 상단 레이어 콘텐츠는 다른 모든 콘텐츠 위에 렌더링됩니다. 예를 들어 모달 대화상자는 다른 모든 DOM 콘텐츠의 맨 위에 표시되어야 하므로 브라우저가 이 요소를 '최상위 레이어'에서 자동으로 렌더링합니다. 작성자가 Z-색인과 직접 대결해야 할 필요 없이 상단 레이어 요소는 Z-색인이 가장 높은 요소 위에 표시됩니다.

최상위 레이어는 '가장 높은 스태킹 레이어'로 설명할 수 있습니다. 각 문서에는 연결된 표시 영역이 하나이므로 최상위 레이어도 하나 있습니다. 여러 요소가 동시에 최상위 레이어 내에 있을 수 있습니다. 이때 두 개의 막대가 마지막 하나가 겹쳐 쌓입니다. 즉, 상단 레이어의 모든 요소는 상단 레이어의 후입선출 (LIFO) 스택에 배치됩니다.

<dialog> 요소는 브라우저가 상단 레이어로 렌더링하는 유일한 요소가 아닙니다. 현재 최상위 레이어 요소는 다음과 같습니다. 팝오버, 모달 대화상자, 전체 화면 모드의 요소.

다음 대화상자 구현을 검토합니다.

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

다음은 배경에 스타일이 적용된 몇 가지 대화상자가 포함된 데모입니다 (배경화면은 아래에 설명).

배경화면이란 무엇인가요?

다행히 상단 레이어 요소 아래의 콘텐츠를 맞춤설정할 수 있는 방법이 있습니다.

상단 레이어의 모든 요소에는 배경화면이라는 CSS 의사 요소가 있습니다.

Backdrop은 최상위 레이어 요소 바로 아래에서 렌더링되는 표시 영역 크기의 상자입니다. ::backdrop 의사 요소를 사용하면 요소가 최상위 레이어의 최상위 레이어에 있을 때 그 아래에 있는 모든 요소를 가리거나 스타일을 지정하거나 완전히 숨길 수 있습니다.

여러 요소를 모달로 만들면 브라우저에서 이러한 요소의 가장 앞에 있는 바로 아래 그리고 다른 전체 화면 요소 위에 배경을 그립니다.

배경화면의 스타일을 지정하는 방법은 다음과 같습니다.

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

첫 번째 배경화면만 표시하려면 어떻게 해야 하나요?

모든 상단 레이어 요소에는 상단 레이어 스택에 속하는 배경화면이 있습니다. 이러한 배경화면은 서로 겹치도록 설계되어 있으므로, 배경화면의 불투명도가 100%가 아닌 경우 그 아래의 배경이 표시됩니다.

상단 레이어 스택의 첫 번째 배경화면만 표시해야 하는 경우 상단 레이어 스택의 항목 식별자를 추적하면 됩니다.

추가된 요소가 상단 레이어의 첫 번째 요소가 아닌 경우, 요소를 최상위 레이어에 넣을 때 호출되는 함수는 hiddenBackdrop 클래스를 ::backdrop에 적용합니다. 이 클래스는 요소가 상단 레이어에서 삭제되면 삭제됩니다.

이 데모 예시의 코드를 확인하세요.

DevTools의 최상위 레이어 지원 디자인

DevTools의 최상위 레이어 지원 기능은 개발자가 최상위 레이어의 개념을 이해하고 최상위 레이어 콘텐츠의 변화를 시각화하는 데 도움이 됩니다. 이러한 기능을 통해 개발자는 다음을 식별할 수 있습니다.

  • 언제든지 최상위 레이어의 요소와 그 순서입니다.
  • 임의 지점의 스택 상단에 있는 요소입니다.

또한 DevTools 최상위 레이어 지원은 최상위 레이어 스택에서 배경화면 의사 요소의 위치를 시각화하는 데 도움이 됩니다. 트리 요소는 아니지만 최상위 레이어가 작동하는 방식에 중요한 역할을 하며 개발자에게 유용할 수 있습니다.

상단 레이어 지원 기능을 사용하면 다음을 수행할 수 있습니다.

  1. 언제든지 최상위 레이어 스택에 어떤 요소가 있는지 확인할 수 있습니다. 상단 레이어 표현 스택은 상단 레이어에서 요소가 추가되거나 삭제될 때 동적으로 변경됩니다.
  2. 상단 레이어 스택에서 요소 위치를 확인하세요.
  3. 최상위 레이어 요소에서 이동 트리의 배경화면 의사 요소를 최상위 레이어 표현 컨테이너의 요소 또는 배경화면 의사 요소로 나눈 다음 그 반대로 하는 것이 좋습니다.

이러한 기능의 사용 방법을 알아보겠습니다.

최상위 레이어 컨테이너

최상위 레이어 요소를 시각화할 수 있도록 DevTools는 요소 트리에 최상위 레이어 컨테이너를 추가합니다. 닫는 </html> 태그 뒤에 있습니다.

이 컨테이너를 사용하면 언제든지 최상위 레이어 스택의 요소를 관찰할 수 있습니다. 상단 레이어 컨테이너는 상단 레이어 요소와 배경화면으로 연결되는 링크의 목록입니다. 상단 레이어 표현 스택은 상단 레이어에서 요소가 추가되거나 삭제될 때 동적으로 변경됩니다.

요소 트리 또는 상단 레이어 컨테이너 내에서 상단 레이어 요소를 찾으려면 상단 레이어 컨테이너의 상단 레이어 요소 표현에서 요소 트리의 동일한 요소로 연결되는 링크를 클릭합니다.

상단 레이어 컨테이너 요소에서 상단 레이어 트리 요소로 이동하려면 상단 레이어 컨테이너에서 요소 옆에 있는 표시 버튼을 클릭합니다.

상단 레이어 컨테이너 링크에서 요소로 이동합니다.

상단 레이어 트리 요소에서 상단 레이어 컨테이너의 링크로 이동하려면 요소 옆에 있는 상단 레이어 배지를 클릭합니다.

요소에서 최상위 레이어 컨테이너 링크로 이동하기

최상위 레이어 배지를 비롯한 모든 배지를 사용 중지할 수 있습니다. 배지를 사용 중지하려면 배지를 마우스 오른쪽 버튼으로 클릭하고 배지 설정을 선택한 다음 숨기려는 배지 옆의 체크표시를 지웁니다.

배지 사용 중지

최상위 레이어 스택의 요소 순서

상단 레이어 컨테이너에는 스택에 표시되는 요소가 역순으로 표시됩니다. 스택 요소의 상단은 상단 레이어 컨테이너의 요소 목록에서 마지막 요소입니다. 이는 최상위 레이어 컨테이너 목록의 마지막 요소가 현재 문서에서 상호작용할 수 있는 요소임을 의미합니다.

트리 요소 옆에 있는 배지는 요소가 최상위 레이어에 속하는지와 스택에 있는 요소의 위치 번호를 포함하고 있는지 여부를 나타냅니다.

이 스크린샷에서 상단 레이어 스택은 두 요소로 구성되어 있으며, 두 번째 요소가 스택의 맨 위에 있습니다. 두 번째 요소를 삭제하면 첫 번째 요소가 맨 위로 이동합니다.

스택의 요소 순서입니다.

상단 레이어 컨테이너의 배경화면

위에서 언급했듯이 모든 최상위 레이어 요소에는 배경화면이라는 CSS 의사 요소가 있습니다. 이 요소에 스타일을 지정할 수 있으므로 요소를 검사하고 표현을 확인하는 것도 유용합니다.

요소 트리에서 배경화면 요소는 해당 요소가 속한 요소의 닫는 태그 앞에 있습니다. 그러나 상단 레이어 컨테이너에서 배경화면 링크는 해당 링크가 속한 상단 레이어 요소 바로 위에 표시됩니다.

배경화면 스택 위치입니다.

DOM 트리 변경사항

DevTools에서 개별 DOM 트리 요소를 생성하고 관리하는 클래스인 ElementsTreeElement는 최상위 레이어 컨테이너를 구현하기에 충분하지 않았습니다.

최상위 레이어 컨테이너를 트리에 노드로 표시하기 위해 DevTools 트리 요소 노드를 생성하는 새 클래스를 추가했습니다. 이전에는 DevTools 요소 트리 생성을 담당하는 클래스가 TreeElement마다 초기화되었으며 DOMNodebackendNodeId 및 기타 백엔드 관련 속성이 있는 클래스입니다. 그러면 backendNodeId가 백엔드에 할당됩니다.

최상위 레이어 요소에 대한 링크 목록이 있는 최상위 레이어 컨테이너 노드는 일반 트리 요소 노드로 작동해야 합니다. 하지만 이 노드는 '실제' 노드가 아니며 DOM 노드와 백엔드는 최상위 레이어 컨테이너 노드를 만들 필요가 없습니다.

최상위 레이어를 나타내는 프런트엔드 노드를 만들기 위해 DOMNode 없이 생성된 새로운 유형의 프런트엔드 노드를 추가했습니다. 이 최상위 레이어 컨테이너 요소는 DOMNode가 없는 첫 번째 프런트엔드 노드입니다. 즉, 프런트엔드에만 존재하고 백엔드는 '알 수 없습니다'. 소개하겠습니다. 다른 노드와 동일한 동작을 하기 위해 프런트엔드 노드의 동작을 담당하는 UI.TreeOutline.TreeElement 클래스를 확장하는 새 TopLayerContainer 클래스를 만들었습니다.

원하는 게재위치를 얻기 위해 요소를 렌더링하는 클래스는 TopLayerContainer<html> 태그의 다음 동위 요소로 연결합니다.

새로운 상단 레이어 배지는 요소가 상단 레이어에 있음을 나타내며 TopLayerContainer 요소에서 이 요소의 바로가기로 연결되는 링크 역할을 합니다.

초기 디자인

처음에는 요소에 대한 링크 목록을 만드는 대신 최상위 레이어 요소를 최상위 레이어 컨테이너에 복제하는 것이 계획되었습니다. 이 솔루션을 구현하지 않은 이유는 요소의 하위 요소 가져오기가 DevTools에서 작동하는 방식 때문입니다. 각 요소에는 하위 요소를 가져오는 데 사용되는 상위 포인터가 있으며 여러 포인터를 갖는 것은 불가능합니다. 따라서 제대로 펼쳐지고 트리의 여러 위치에 모든 하위 요소를 포함하는 노드가 없습니다. 일반적으로 시스템은 중복 하위 트리를 염두에 두고 빌드되지 않았습니다.

우리가 받은 침해는 해당 노드를 복제하는 대신 프런트엔드 DOM 노드에 대한 링크를 만드는 것이었습니다. DevTools에서 요소 링크 생성을 담당하는 클래스는 ShortcutTreeElement이며 UI.TreeOutline.TreeElement를 확장합니다. ShortcutTreeElement는 다른 DevTools DOM 트리 요소와 동작이 같지만 백엔드에 상응하는 노드가 없고 ElementsTreeElement에 연결되는 버튼이 있습니다. 최상위 레이어 노드의 각 ShortcutTreeElement에는 DevTools DOM 트리의 ::backdrop 의사 요소 표현으로 연결되는 하위 ShortcutTreeElement가 있습니다.

초기 디자인:

초기 디자인

Chrome DevTools 프로토콜 (CDP) 변경사항

최상위 레이어 지원을 구현하려면 CDP (Chrome DevTools Protocol)를 변경해야 합니다. CDP는 DevTools와 Chromium 간의 통신 프로토콜 역할을 합니다.

다음을 추가해야 합니다.

  • 언제든지 프런트엔드에서 호출할 명령어입니다.
  • 백엔드 측의 프런트엔드에서 트리거할 이벤트입니다.

CDP: DOM.getTopLayerElements 명령어

현재 최상위 레이어 요소를 표시하려면 최상위 레이어에 있는 요소의 노드 ID 목록을 반환하는 새로운 실험용 CDP 명령어가 필요합니다. DevTools가 열릴 때마다 또는 최상위 레이어 요소가 변경될 때마다 DevTools가 이 명령어를 호출합니다. 명령어는 다음과 같습니다.

  # 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: DOM.topLayerElementsUpdated 이벤트

최상위 레이어 요소의 최신 목록을 가져오려면 실험적인 CDP 이벤트를 트리거하도록 최상위 레이어 요소의 모든 변경사항이 필요합니다. 이 이벤트는 변경사항을 프런트엔드에 알리고 프런트엔드는 DOM.getTopLayerElements 명령어를 호출하고 새 요소 목록을 수신합니다.

이벤트는 다음과 같습니다.

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

CDP 고려사항

최상위 레이어의 CDP 지원을 구현하는 방법에는 여러 옵션이 있었습니다. 우리가 고려한 또 다른 옵션은 프런트 엔드에 맨 위 레이어 요소의 추가 또는 제거를 알리는 대신 최상위 레이어 요소의 목록을 반환하는 이벤트를 만드는 것이었습니다.

또는 topLayerElementAddedtopLayerElementRemoved 명령어 대신 두 개의 이벤트를 만들 수도 있습니다. 이 경우 요소를 수신하게 되며 프런트 엔드에서 최상위 레이어 요소의 배열을 관리해야 합니다.

현재 프런트엔드 이벤트는 getTopLayerElements 명령어를 호출하여 업데이트된 요소 목록을 가져옵니다. 이벤트가 트리거될 때마다 변경을 일으킨 요소 또는 특정 요소의 목록을 보내려는 경우, 명령을 호출하는 한 단계를 피할 수 있습니다. 그러나 이 경우 프런트엔드는 푸시되는 요소를 제어할 수 없습니다.

우리는 프런트엔드가 최상위 레이어 노드를 요청할 시기를 결정하는 것이 더 좋다고 생각하기 때문에 이런 방식으로 구현했습니다. 예를 들어 맨 위 레이어가 UI에서 접혀 있거나 사용자가 요소 트리가 없는 DevTools 패널을 사용하는 경우 트리 안쪽으로 더 깊이 들어갈 수 있는 추가 노드를 가져올 필요가 없습니다.