mirror of
https://github.com/withastro/astro.git
synced 2025-03-10 23:01:26 -05:00
Use fixed positioning on x-ray when inside of fixed containers (#9254)
* Improve highlight/tooltip positioning * add changeset * Explain the perf issue
This commit is contained in:
parent
9ea3e0b94f
commit
b750a161e0
3 changed files with 33 additions and 6 deletions
5
.changeset/grumpy-turtles-tickle.md
Normal file
5
.changeset/grumpy-turtles-tickle.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve highlight/tooltip positioning when in fixed positions
|
|
@ -15,23 +15,37 @@ export function createHighlight(rect: DOMRect, icon?: Icon) {
|
||||||
return highlight;
|
return highlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHighlightZIndex(el: Element) {
|
// Figures out the element's z-index and position, based on it's parents.
|
||||||
|
export function getElementsPositionInDocument(el: Element) {
|
||||||
let highestZIndex = 0;
|
let highestZIndex = 0;
|
||||||
|
let fixed = false;
|
||||||
let current: Element | ParentNode | null = el;
|
let current: Element | ParentNode | null = el;
|
||||||
while (current instanceof Element) {
|
while (current instanceof Element) {
|
||||||
let zIndex = Number(getComputedStyle(current).zIndex);
|
// 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) {
|
if (!Number.isNaN(zIndex) && zIndex > highestZIndex) {
|
||||||
highestZIndex = zIndex;
|
highestZIndex = zIndex;
|
||||||
}
|
}
|
||||||
|
if(style.position === 'fixed') {
|
||||||
|
fixed = true;
|
||||||
|
}
|
||||||
current = current.parentNode;
|
current = current.parentNode;
|
||||||
}
|
}
|
||||||
return highestZIndex + 1;
|
return {
|
||||||
|
zIndex: highestZIndex + 1,
|
||||||
|
fixed,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function positionHighlight(highlight: DevOverlayHighlight, rect: DOMRect) {
|
export function positionHighlight(highlight: DevOverlayHighlight, rect: DOMRect) {
|
||||||
highlight.style.display = 'block';
|
highlight.style.display = 'block';
|
||||||
|
// If the highlight is fixed, don't position based on scroll
|
||||||
|
const scrollY = highlight.style.position === 'fixed' ? 0 : window.scrollY;
|
||||||
// Make an highlight that is 10px bigger than the element on all sides
|
// Make an highlight that is 10px bigger than the element on all sides
|
||||||
highlight.style.top = `${Math.max(rect.top + window.scrollY - 10, 0)}px`;
|
highlight.style.top = `${Math.max(rect.top + scrollY - 10, 0)}px`;
|
||||||
highlight.style.left = `${Math.max(rect.left + window.scrollX - 10, 0)}px`;
|
highlight.style.left = `${Math.max(rect.left + window.scrollX - 10, 0)}px`;
|
||||||
highlight.style.width = `${rect.width + 15}px`;
|
highlight.style.width = `${rect.width + 15}px`;
|
||||||
highlight.style.height = `${rect.height + 15}px`;
|
highlight.style.height = `${rect.height + 15}px`;
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { DevOverlayHighlight } from '../ui-library/highlight.js';
|
||||||
import {
|
import {
|
||||||
attachTooltipToHighlight,
|
attachTooltipToHighlight,
|
||||||
createHighlight,
|
createHighlight,
|
||||||
getHighlightZIndex,
|
getElementsPositionInDocument,
|
||||||
positionHighlight,
|
positionHighlight,
|
||||||
} from './utils/highlight.js';
|
} from './utils/highlight.js';
|
||||||
import { createWindowElement } from './utils/window.js';
|
import { createWindowElement } from './utils/window.js';
|
||||||
|
@ -83,8 +83,16 @@ export default {
|
||||||
attachTooltipToHighlight(highlight, tooltip, islandElement);
|
attachTooltipToHighlight(highlight, tooltip, islandElement);
|
||||||
|
|
||||||
// Set the z-index to be 1 higher than the greatest z-index in the stack.
|
// Set the z-index to be 1 higher than the greatest z-index in the stack.
|
||||||
const zIndex = getHighlightZIndex(islandElement);
|
// 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 + '';
|
tooltip.style.zIndex = highlight.style.zIndex = zIndex + '';
|
||||||
|
if(fixed) {
|
||||||
|
tooltip.style.position = highlight.style.position = 'fixed';
|
||||||
|
}
|
||||||
|
|
||||||
canvas.append(highlight);
|
canvas.append(highlight);
|
||||||
islandsOverlays.push({ highlightElement: highlight, island: islandElement });
|
islandsOverlays.push({ highlightElement: highlight, island: islandElement });
|
||||||
|
|
Loading…
Add table
Reference in a new issue