Skip to content

Commit d598cd5

Browse files
fix: view port problem
1 parent a24fc35 commit d598cd5

1 file changed

Lines changed: 169 additions & 15 deletions

File tree

packages/webgal/index.html

Lines changed: 169 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
background: black;
1414
}
1515

16+
html {
17+
--ios-safe-area-top: env(safe-area-inset-top, 0px);
18+
--ios-safe-area-right: env(safe-area-inset-right, 0px);
19+
--ios-safe-area-bottom: env(safe-area-inset-bottom, 0px);
20+
--ios-safe-area-left: env(safe-area-inset-left, 0px);
21+
}
22+
1623
.html-body__effect-background {
1724
height: 100vh;
1825
width: 100vw;
@@ -134,15 +141,16 @@
134141

135142
html.ios-phone-viewport,
136143
html.ios-phone-viewport body {
144+
width: 100%;
145+
height: 100%;
137146
overflow: hidden;
138147
overscroll-behavior: none;
139148
background: black;
140149
}
141150

142151
html.ios-phone-viewport body {
143-
width: 2560px;
144-
height: 1440px;
145-
position: relative;
152+
position: fixed;
153+
inset: 0;
146154
}
147155

148156
html.ios-phone-viewport #ebg {
@@ -156,7 +164,6 @@
156164
position: absolute;
157165
top: 0;
158166
left: 0;
159-
transform: none !important;
160167
transform-origin: top left;
161168
}
162169
</style>
@@ -201,6 +208,9 @@
201208
const titleEnter = document.querySelector('.html-body__title-enter');
202209
const effectBackground = document.querySelector('.html-body__effect-background');
203210
let viewportMeta = document.querySelector('meta[name="viewport"]');
211+
let iosPhoneLayoutFrame = 0;
212+
let touchStartX = 0;
213+
let touchStartY = 0;
204214

205215
window.__WEBGAL_DEVICE_INFO__ = { isIOS, isIOSPhone };
206216

@@ -213,6 +223,152 @@
213223
return viewportMeta;
214224
};
215225

226+
const parseInset = (value) => {
227+
const parsed = Number.parseFloat(value);
228+
return Number.isFinite(parsed) ? parsed : 0;
229+
};
230+
231+
const getSafeAreaInsets = () => {
232+
const computedStyle = window.getComputedStyle(html);
233+
return {
234+
top: parseInset(computedStyle.getPropertyValue('--ios-safe-area-top')),
235+
right: parseInset(computedStyle.getPropertyValue('--ios-safe-area-right')),
236+
bottom: parseInset(computedStyle.getPropertyValue('--ios-safe-area-bottom')),
237+
left: parseInset(computedStyle.getPropertyValue('--ios-safe-area-left')),
238+
};
239+
};
240+
241+
const applyIOSPhoneLayout = () => {
242+
const safeArea = getSafeAreaInsets();
243+
const viewportWidth = window.innerWidth;
244+
const viewportHeight = window.innerHeight;
245+
const usableWidth = Math.max(viewportWidth - safeArea.left - safeArea.right, 1);
246+
const usableHeight = Math.max(viewportHeight - safeArea.top - safeArea.bottom, 1);
247+
const scale = Math.max(Math.min(usableWidth / targetWidth, usableHeight / targetHeight), 0.01);
248+
const left = safeArea.left + Math.max((usableWidth - targetWidth * scale) / 2, 0);
249+
const top = safeArea.top + Math.max((usableHeight - targetHeight * scale) / 2, 0);
250+
const transform = `translate(${left}px, ${top}px) scale(${scale})`;
251+
252+
if (effectBackground) {
253+
effectBackground.style.transform = '';
254+
}
255+
for (const element of [root, titleEnter]) {
256+
if (element) {
257+
element.style.transform = transform;
258+
}
259+
}
260+
};
261+
262+
const scheduleIOSPhoneLayout = () => {
263+
if (iosPhoneLayoutFrame) {
264+
window.cancelAnimationFrame(iosPhoneLayoutFrame);
265+
}
266+
iosPhoneLayoutFrame = window.requestAnimationFrame(() => {
267+
iosPhoneLayoutFrame = 0;
268+
applyIOSPhoneLayout();
269+
});
270+
};
271+
272+
const canScrollInDirection = (element, deltaX, deltaY) => {
273+
const style = window.getComputedStyle(element);
274+
const overflowY = style.overflowY;
275+
const overflowX = style.overflowX;
276+
const canScrollY = /(auto|scroll|overlay)/.test(overflowY) && element.scrollHeight > element.clientHeight + 1;
277+
const canScrollX = /(auto|scroll|overlay)/.test(overflowX) && element.scrollWidth > element.clientWidth + 1;
278+
279+
if (Math.abs(deltaY) >= Math.abs(deltaX) && canScrollY) {
280+
const maxScrollTop = element.scrollHeight - element.clientHeight;
281+
if (deltaY > 0 && element.scrollTop > 0) return true;
282+
if (deltaY < 0 && element.scrollTop < maxScrollTop) return true;
283+
}
284+
285+
if (Math.abs(deltaX) > Math.abs(deltaY) && canScrollX) {
286+
const maxScrollLeft = element.scrollWidth - element.clientWidth;
287+
if (deltaX > 0 && element.scrollLeft > 0) return true;
288+
if (deltaX < 0 && element.scrollLeft < maxScrollLeft) return true;
289+
}
290+
291+
return false;
292+
};
293+
294+
const findScrollableAncestor = (startElement, deltaX, deltaY) => {
295+
let current = startElement;
296+
while (current && current !== body) {
297+
if (current instanceof HTMLElement && canScrollInDirection(current, deltaX, deltaY)) {
298+
return current;
299+
}
300+
current = current.parentElement;
301+
}
302+
return null;
303+
};
304+
305+
const installIOSPhoneGestureGuards = () => {
306+
const blockEvent = (event) => {
307+
event.preventDefault();
308+
};
309+
310+
document.addEventListener(
311+
'gesturestart',
312+
(event) => {
313+
blockEvent(event);
314+
},
315+
{ passive: false },
316+
);
317+
document.addEventListener(
318+
'gesturechange',
319+
(event) => {
320+
blockEvent(event);
321+
},
322+
{ passive: false },
323+
);
324+
document.addEventListener(
325+
'gestureend',
326+
(event) => {
327+
blockEvent(event);
328+
},
329+
{ passive: false },
330+
);
331+
332+
document.addEventListener(
333+
'touchstart',
334+
(event) => {
335+
if (event.touches.length > 1) {
336+
blockEvent(event);
337+
return;
338+
}
339+
const touch = event.touches[0];
340+
if (touch) {
341+
touchStartX = touch.clientX;
342+
touchStartY = touch.clientY;
343+
}
344+
},
345+
{ passive: false },
346+
);
347+
348+
document.addEventListener(
349+
'touchmove',
350+
(event) => {
351+
if (event.touches.length > 1) {
352+
blockEvent(event);
353+
return;
354+
}
355+
const touch = event.touches[0];
356+
if (!touch) {
357+
return;
358+
}
359+
const deltaX = touch.clientX - touchStartX;
360+
const deltaY = touch.clientY - touchStartY;
361+
const target = event.target instanceof Element ? event.target : null;
362+
const scrollableAncestor = target ? findScrollableAncestor(target, deltaX, deltaY) : null;
363+
364+
if (!scrollableAncestor) {
365+
blockEvent(event);
366+
}
367+
},
368+
{ passive: false },
369+
);
370+
};
371+
216372
const resize = () => {
217373
const h = window.innerHeight; // 窗口高度
218374
const w = window.innerWidth; // 窗口宽度
@@ -293,17 +449,15 @@
293449
if (isIOSPhone) {
294450
html.classList.add('ios-phone-viewport');
295451
body.classList.add('ios-phone-viewport');
296-
ensureViewportMeta().content = `width=${targetWidth}, height=${targetHeight}, user-scalable=no, viewport-fit=cover`;
297-
if (effectBackground) {
298-
effectBackground.style.transform = '';
299-
}
300-
for (const element of [root, titleEnter]) {
301-
if (element) {
302-
element.style.left = '0';
303-
element.style.top = '0';
304-
element.style.transform = 'none';
305-
}
306-
}
452+
ensureViewportMeta().content = 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover';
453+
installIOSPhoneGestureGuards();
454+
scheduleIOSPhoneLayout();
455+
window.addEventListener('load', scheduleIOSPhoneLayout);
456+
window.addEventListener('resize', scheduleIOSPhoneLayout);
457+
window.addEventListener('orientationchange', () => {
458+
scheduleIOSPhoneLayout();
459+
setTimeout(scheduleIOSPhoneLayout, 300);
460+
});
307461
} else {
308462
ensureViewportMeta().content = 'width=device-width, initial-scale=0.22, minimum-scale=0.01, maximum-scale=1';
309463
}

0 commit comments

Comments
 (0)