diff --git a/packages/astro/src/runtime/client/dev-overlay/entrypoint.ts b/packages/astro/src/runtime/client/dev-overlay/entrypoint.ts index ffd9ea32b5..fa3020b03c 100644 --- a/packages/astro/src/runtime/client/dev-overlay/entrypoint.ts +++ b/packages/astro/src/runtime/client/dev-overlay/entrypoint.ts @@ -127,7 +127,7 @@ document.addEventListener('DOMContentLoaded', async () => { box-shadow: 0px 0px 0px 0px rgba(19, 21, 26, 0.30), 0px 1px 2px 0px rgba(19, 21, 26, 0.29), 0px 4px 4px 0px rgba(19, 21, 26, 0.26), 0px 10px 6px 0px rgba(19, 21, 26, 0.15), 0px 17px 7px 0px rgba(19, 21, 26, 0.04), 0px 26px 7px 0px rgba(19, 21, 26, 0.01); width: 192px; padding: 8px; - z-index: 9999999999; + z-index: 2000000010; transform: translate(-50%, 0%); position: fixed; bottom: 72px; diff --git a/packages/astro/src/runtime/client/dev-overlay/overlay.ts b/packages/astro/src/runtime/client/dev-overlay/overlay.ts index e1240f8b41..8a5cda453d 100644 --- a/packages/astro/src/runtime/client/dev-overlay/overlay.ts +++ b/packages/astro/src/runtime/client/dev-overlay/overlay.ts @@ -58,7 +58,7 @@ export class AstroDevOverlay extends HTMLElement { bottom: 0px; left: 50%; transform: translate(-50%, 0%); - z-index: 9999999999; + z-index: 2000000010; display: flex; flex-direction: column; align-items: center; diff --git a/packages/astro/src/runtime/client/dev-overlay/plugins/audit/index.ts b/packages/astro/src/runtime/client/dev-overlay/plugins/audit/index.ts index fc9a1e6d35..094640f9bb 100644 --- a/packages/astro/src/runtime/client/dev-overlay/plugins/audit/index.ts +++ b/packages/astro/src/runtime/client/dev-overlay/plugins/audit/index.ts @@ -3,6 +3,7 @@ import type { DevOverlayHighlight } from '../../ui-library/highlight.js'; import { attachTooltipToHighlight, createHighlight, + getElementsPositionInDocument, positionHighlight, } from '../utils/highlight.js'; import { createWindowElement } from '../utils/window.js'; @@ -198,6 +199,18 @@ export default { const rect = originalElement.getBoundingClientRect(); const highlight = createHighlight(rect, 'warning'); const tooltip = buildAuditTooltip(rule, originalElement); + + // Set the highlight/tooltip as being fixed position the highlighted element + // is fixed. We do this so that we don't mistakenly take scroll position + // into account when setting the tooltip/highlight positioning. + // + // We only do this once due to how expensive computed styles are to calculate, + // and are unlikely to change. If that turns out to be wrong, reconsider this. + const { isFixed } = getElementsPositionInDocument(originalElement); + if (isFixed) { + tooltip.style.position = highlight.style.position = 'fixed'; + } + attachTooltipToHighlight(highlight, tooltip, originalElement); canvas.append(highlight); diff --git a/packages/astro/src/runtime/client/dev-overlay/plugins/utils/highlight.ts b/packages/astro/src/runtime/client/dev-overlay/plugins/utils/highlight.ts index 73d7fe1127..6ad37aad2a 100644 --- a/packages/astro/src/runtime/client/dev-overlay/plugins/utils/highlight.ts +++ b/packages/astro/src/runtime/client/dev-overlay/plugins/utils/highlight.ts @@ -15,28 +15,21 @@ export function createHighlight(rect: DOMRect, icon?: Icon) { return highlight; } -// Figures out the element's z-index and position, based on it's parents. +// Figures out the element's position, based on it's parents. export function getElementsPositionInDocument(el: Element) { - let highestZIndex = 0; - let fixed = false; + let isFixed = false; let current: Element | ParentNode | null = el; while (current instanceof Element) { - // This is the expensive part, we are calling getComputedStyle which triggers layout // all the way up the tree. We are only doing so when the app initializes, so the cost is one-time // If perf becomes an issue we'll want to refactor this somehow so that it reads this info in a rAF let style = getComputedStyle(current); - let zIndex = Number(style.zIndex); - if (!Number.isNaN(zIndex) && zIndex > highestZIndex) { - highestZIndex = zIndex; - } if (style.position === 'fixed') { - fixed = true; + isFixed = true; } current = current.parentNode; } return { - zIndex: highestZIndex + 1, - fixed, + isFixed, }; } @@ -57,12 +50,9 @@ export function attachTooltipToHighlight( originalElement: Element ) { highlight.shadowRoot.append(tooltip); - // Track the original z-index so that we can restore it after hover - const originalZIndex = highlight.style.zIndex; (['mouseover', 'focus'] as const).forEach((event) => { highlight.addEventListener(event, () => { - highlight.style.zIndex = '9999999999'; tooltip.dataset.show = 'true'; const originalRect = originalElement.getBoundingClientRect(); const dialogRect = tooltip.getBoundingClientRect(); @@ -80,7 +70,6 @@ export function attachTooltipToHighlight( (['mouseout', 'blur'] as const).forEach((event) => { highlight.addEventListener(event, () => { tooltip.dataset.show = 'false'; - highlight.style.zIndex = originalZIndex; }); }); } diff --git a/packages/astro/src/runtime/client/dev-overlay/plugins/xray.ts b/packages/astro/src/runtime/client/dev-overlay/plugins/xray.ts index 5b73270296..714c80c2e8 100644 --- a/packages/astro/src/runtime/client/dev-overlay/plugins/xray.ts +++ b/packages/astro/src/runtime/client/dev-overlay/plugins/xray.ts @@ -108,15 +108,14 @@ export default { const highlight = createHighlight(rect); const tooltip = buildIslandTooltip(island); - // Set the z-index to be 1 higher than the greatest z-index in the stack. - // And also set the highlight/tooltip as being fixed position if they are inside - // a fixed container. We do this so that we don't mistakenly take scroll position - // into account when setting their position. - // We are only doing both of these things once, as they are relatively expensive - // to calculate, and are unlikely to change. If that turns out to be wrong, reconsider this. - const { zIndex, fixed } = getElementsPositionInDocument(islandElement); - tooltip.style.zIndex = highlight.style.zIndex = zIndex + ''; - if (fixed) { + // Set the highlight/tooltip as being fixed position the highlighted element + // is fixed. We do this so that we don't mistakenly take scroll position + // into account when setting the tooltip/highlight positioning. + // + // We only do this once due to how expensive computed styles are to calculate, + // and are unlikely to change. If that turns out to be wrong, reconsider this. + const { isFixed } = getElementsPositionInDocument(islandElement); + if (isFixed) { tooltip.style.position = highlight.style.position = 'fixed'; } diff --git a/packages/astro/src/runtime/client/dev-overlay/ui-library/highlight.ts b/packages/astro/src/runtime/client/dev-overlay/ui-library/highlight.ts index 6a1b914a8b..16d02df0cc 100644 --- a/packages/astro/src/runtime/client/dev-overlay/ui-library/highlight.ts +++ b/packages/astro/src/runtime/client/dev-overlay/ui-library/highlight.ts @@ -21,6 +21,7 @@ export class DevOverlayHighlight extends HTMLElement { width: 100%; height: 100%; position: absolute; + z-index: 2000000000; } .icon { diff --git a/packages/astro/src/runtime/client/dev-overlay/ui-library/tooltip.ts b/packages/astro/src/runtime/client/dev-overlay/ui-library/tooltip.ts index 6a8e19b0d9..9f7224ca47 100644 --- a/packages/astro/src/runtime/client/dev-overlay/ui-library/tooltip.ts +++ b/packages/astro/src/runtime/client/dev-overlay/ui-library/tooltip.ts @@ -32,7 +32,7 @@ export class DevOverlayTooltip extends HTMLElement { font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 14px; margin: 0; - z-index: 9999999; + z-index: 2000000001; max-width: 45ch; width: fit-content; min-width: 30ch;