如何在屏幕方向更改后在 iOS Safari 上保持应用程序全屏显示
How to keep an app fullscreen on iOS Safari after screen orientation changes
我构建了一个 SPA,该 SPA 应始终占用目标浏览器组的 100% 屏幕高度 - iOS(移动)Safari。 height:100vh
在 iOS Safari 上无法正常工作 -
https://css-tricks.com/css-fix-for-100vh-in-mobile-webkit/
关于使用某些资源的建议解决方案 -webkit-fill-available
没有帮助。
因此,我决定用JS控制app容器的高度:
const [height, setHeight] = useState(window.innerHeight);
const handleWindowSizeChange = () => {
setHeight(window.innerHeight);
};
useEffect(() => {
window.addEventListener("resize", handleWindowSizeChange);
return () => window.removeEventListener("resize", handleWindowSizeChange);
}, []);
return (
<div className="App" style={{ height: height }}>
<header className="top"></header>
<div className="main"></div>
<footer className="bottom"><button>Click</button></footer>
</div>
我的解决方案一直有效,直到我们将屏幕从纵向旋转到横向,然后再旋转回纵向。在这些旋转之后,我们在屏幕视图的底部有一个间隙,就在应用程序页脚的正下方。如果我们打开,可以注意到相同的行为
一个演示 - https://react-div-100vh.vercel.app/ 一个应该解决问题的包,并进行相同的屏幕旋转。
浏览器:Safari 14.6 iOS/iPhone 7
视口高度在 iOS Safari 上很棘手。
根据用例,-webkit-fill-available
可以工作 (see article)。
我大部分时间都必须使用这个 JavaScript/CSS var
修复:
.my-element {
height: 25vh;
height: calc(25 * var(--vh, 1vh));
}
<script type="application/javascript">
function handleResize () { window.document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`); }
window.onresize = handleResize
handleResize()
</script>
灵感:https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
import React from 'react'
const getHeight = () => {
const html = document?.documentElement
return Math.max(window?.innerHeight, html?.clientHeight, html?.offsetHeight)
}
const getWidth = () => {
const html = document?.documentElement
return Math.max(window?.innerWidth, html?.clientWidth, html?.offsetWidth)
}
const isIPad = (platform, maxTouchPoints) =>
maxTouchPoints && maxTouchPoints > 2 && /MacIntel/.test(platform)
const isIPhoneOrIPad = (platform, touchpoints) =>
platform === 'iPhone' ||
/iPad/.test(platform) ||
isIPad(platform, touchpoints)
const isIDevice = isIPhoneOrIPad(
window?.navigator?.platform,
window?.navigator?.maxTouchPoints,
)
const isIOSPWA = window.navigator['standalone'] === true
const MyApp = (props) => {
const rafTimer = React.useRef(null)
const timer = React.useRef(null)
React.useEffect(() => {
if (!isIDevice) return
const iosHack = () => {
const height = getHeight()
const width = getWidth()
document.body.style.minHeight = `${height}px`
document.body.style.maxHeight = `${height}px`
if (!isIOSPWA && height > width) {
clearTimeout(timer.current)
timer.current = setTimeout(() => {
const height = getHeight()
document.body.style.minHeight = `${height}px`
document.body.style.maxHeight = `${height}px`
clearTimeout(timer.current)
timer.current = setTimeout(() => {
const height = getHeight()
document.body.style.minHeight = `${height}px`
document.body.style.maxHeight = `${height}px`
}, 300)
}, 300)
}
}
cancelAnimationFrame(rafTimer.current)
rafTimer.current = requestAnimationFrame(iosHack)
return () => {
cancelAnimationFrame(rafTimer.current)
clearTimeout(timer.current)
}
})
return <div>{props.children}</div>
}
export default MyApp
解决方案只是对 HTML
、Body
和 #root
使用 %
而不是 vh
(以防万一 react-apps使用 create-react-app) 元素创建:
html,
body,
#root {
height: 100%;
}
在此之后,根元素中的内容会占据整个屏幕的高度,并会在浏览器切换时进行调整 appear/disappear。 (在 iOS Safari 15.3.1 和 Chrome iOS v99.0.4844.59 上测试)
来源:The article about CSS Reset from and the course of the same author
我构建了一个 SPA,该 SPA 应始终占用目标浏览器组的 100% 屏幕高度 - iOS(移动)Safari。 height:100vh
在 iOS Safari 上无法正常工作 -
https://css-tricks.com/css-fix-for-100vh-in-mobile-webkit/
关于使用某些资源的建议解决方案 -webkit-fill-available
没有帮助。
因此,我决定用JS控制app容器的高度:
const [height, setHeight] = useState(window.innerHeight);
const handleWindowSizeChange = () => {
setHeight(window.innerHeight);
};
useEffect(() => {
window.addEventListener("resize", handleWindowSizeChange);
return () => window.removeEventListener("resize", handleWindowSizeChange);
}, []);
return (
<div className="App" style={{ height: height }}>
<header className="top"></header>
<div className="main"></div>
<footer className="bottom"><button>Click</button></footer>
</div>
我的解决方案一直有效,直到我们将屏幕从纵向旋转到横向,然后再旋转回纵向。在这些旋转之后,我们在屏幕视图的底部有一个间隙,就在应用程序页脚的正下方。如果我们打开,可以注意到相同的行为 一个演示 - https://react-div-100vh.vercel.app/ 一个应该解决问题的包,并进行相同的屏幕旋转。
浏览器:Safari 14.6 iOS/iPhone 7
视口高度在 iOS Safari 上很棘手。
根据用例,-webkit-fill-available
可以工作 (see article)。
我大部分时间都必须使用这个 JavaScript/CSS var
修复:
.my-element {
height: 25vh;
height: calc(25 * var(--vh, 1vh));
}
<script type="application/javascript">
function handleResize () { window.document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`); }
window.onresize = handleResize
handleResize()
</script>
灵感:https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
import React from 'react'
const getHeight = () => {
const html = document?.documentElement
return Math.max(window?.innerHeight, html?.clientHeight, html?.offsetHeight)
}
const getWidth = () => {
const html = document?.documentElement
return Math.max(window?.innerWidth, html?.clientWidth, html?.offsetWidth)
}
const isIPad = (platform, maxTouchPoints) =>
maxTouchPoints && maxTouchPoints > 2 && /MacIntel/.test(platform)
const isIPhoneOrIPad = (platform, touchpoints) =>
platform === 'iPhone' ||
/iPad/.test(platform) ||
isIPad(platform, touchpoints)
const isIDevice = isIPhoneOrIPad(
window?.navigator?.platform,
window?.navigator?.maxTouchPoints,
)
const isIOSPWA = window.navigator['standalone'] === true
const MyApp = (props) => {
const rafTimer = React.useRef(null)
const timer = React.useRef(null)
React.useEffect(() => {
if (!isIDevice) return
const iosHack = () => {
const height = getHeight()
const width = getWidth()
document.body.style.minHeight = `${height}px`
document.body.style.maxHeight = `${height}px`
if (!isIOSPWA && height > width) {
clearTimeout(timer.current)
timer.current = setTimeout(() => {
const height = getHeight()
document.body.style.minHeight = `${height}px`
document.body.style.maxHeight = `${height}px`
clearTimeout(timer.current)
timer.current = setTimeout(() => {
const height = getHeight()
document.body.style.minHeight = `${height}px`
document.body.style.maxHeight = `${height}px`
}, 300)
}, 300)
}
}
cancelAnimationFrame(rafTimer.current)
rafTimer.current = requestAnimationFrame(iosHack)
return () => {
cancelAnimationFrame(rafTimer.current)
clearTimeout(timer.current)
}
})
return <div>{props.children}</div>
}
export default MyApp
解决方案只是对 HTML
、Body
和 #root
使用 %
而不是 vh
(以防万一 react-apps使用 create-react-app) 元素创建:
html,
body,
#root {
height: 100%;
}
在此之后,根元素中的内容会占据整个屏幕的高度,并会在浏览器切换时进行调整 appear/disappear。 (在 iOS Safari 15.3.1 和 Chrome iOS v99.0.4844.59 上测试)
来源:The article about CSS Reset from and the course of the same author