你有一段文本和一个按钮,你想让文本固定在顶部,按钮固定在底部!看起来很简单。我们可以使用 CSS 的 flex
!
// HTML
<div className="layout">
<p>Lorem ipsum dolor sit amet...</p>
<button>Sign Up</button>
</div>
// CSS
.layout {
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 100vh;
}
在你的电脑上检查结果...
有问题吗?
要看到问题,你需要在真实的手机或模拟器上查看你的应用。我在本文中使用 iPhone 13(iOS 15.2)进行测试,这是测试结果:
iPhone 上的 100vh 问题(Safari)
顺便说一下,即使在 Android 手机上,它也不能像预期的那样工作:
Android 上的 100vh 问题(Chrome)
我认为在 Android Chrome 上的体验更好。无论如何,我将集中讨论最坏的情况,即 iPhone。
为什么移动设备上会出现 100vh 问题?
我稍微调查了一下这个问题,并找到了原因。简短的答案是浏览器工具栏的高度没有被考虑在内。如果你想深入了解为什么会出现这种情况,我发现这个 Stack Overflow 线程非常有帮助。
如何在移动设备上解决 100vh 问题?
我对你的第一个建议是尽可能少使用 vh
。例如,在上面的代码中,你可以使用一个粘性按钮,避免使用 vh
单位。
// HTML
<div className="layout">
<p>Lorem ipsum dolor sit amet...</p>
<button>Sign Up</button>
</div>
// CSS
.layout {
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 100vh;
}
.layout button {
position: sticky;
bottom: 0;
}
你可以在以下视频中看到结果:
粘性按钮(纵向)
在横向模式下也很好:
粘性按钮(横向)
老实说,结果很好,但你不能总是用粘性元素修复 100vh 问题。
仅使用 CSS 修复移动设备上的 100vh 问题
有时,使用 vh
单位的目的只是简单地创建与视口高度相等的节。例如,在构建着陆页面时,这是很常见的。在这些情况下,粘性位置是无法帮助的,我想介绍 fill-available
属性。它很容易使用,只要记得使用前缀和回退值:
.layout {
min-height: 100vh; /* fall-back */
min-height: -moz-available;
min-height: -webkit-fill-available;
min-height: fill-available;
}
就这么简单!这里是在 iPhone 13 上的外观视频:
使用 CSS fill-available
修复 100vh 问题
使用 CSS fill-available
修复 100vh 问题(翻转设备时有效)
使用 fill-available
修复 100vh 问题确实很简单,但我在解决这个问题时也遇到了一些问题。我认为这些问题不大,但你有权知道。
1. HTML Doctype 声明问题
在你的页面中添加 HTML <!DOCTYPE html>
声明会阻止 fill-available
在 Chrome 浏览器上正常工作。让我们看一些截图:
macOS 桌面版 Chrome
它甚至在 Android Chrome 上也无法工作:
Android 上的 Chrome
因此,为了解决这个问题,你必须从你的页面中删除文档类型声明。
2. Safari 上的垂直填充问题
将垂直填充(底部和顶部)添加到具有 min-height
(或 height
)的元素,以使其填满可用空间,会在 Safari 浏览器上导致问题,高度将不正确:
Safari 上的 fill-available
垂直填充问题
要解决这个问题,只需将你的内容包装在另一个 div
元素中,然后你就可以继续了:
// HTML
<div class="screen">
<div class="content">
...
</div>
</div>
// CSS
.screen {
background-color: mediumpurple;
min-height: 100vh;
min-height: -moz-available;
min-height: -webkit-fill-available;
min-height: fill-available;
}
.content {
color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
padding: 30px;
}
3. fill-available
不能与 calc()
一起使用
需要注意的一点是,你不能将 calc()
与 fill-available
属性一起使用!因此,以下 CSS 规则将无法工作:
min-height: calc(-webkit-fill-available / 2);
如果你需要在元素上使用一半的可用高度,例如,你必须使用 JavaScript。## 使用 JavaScript 修复移动设备上的 100vh 问题
你可以使用窗口的 innerHeight
属性,将你的元素的 height
(或 minHeight
)设置为 window.innerHeight
。看看下面的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
...
</style>
</head>
<body>
<div id="intro">
<h1>Hello World!</h1>
<h2>The height of this area is equal to...</h2>
</div>
...
<script>
(function () {
const el = document.getElementById('intro');
el.style.minHeight = window.innerHeight + 'px';
})();
</script>
</body>
</html>
你可以在下面的视频中看到结果:
使用 JavaScript 修复 100vh 问题
现在,我们来用一种时髦的方式来实现这个。一些开发人员喜欢根据窗口的 inner height 定义一个 CSS 变量,并使用该变量来样式化他们想要的元素。以下是实现此目的的 JavaScript 代码:
// Calculate 1vh value in pixels
// based on window inner height
var vh = window.innerHeight * 0.01;
// Set the CSS variable to the root element
// Which is equal to 1vh
document.documentElement.style.setProperty('--vh', vh + 'px');
以下是设置元素高度的 CSS 代码:
min-height: calc(var(--vh) * 100);
最后一件事是在窗口调整大小或设备方向更改时重新计算这个值。完整的 JavaScript 代码将是:
function calculateVh() {
var vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', vh + 'px');
}
// Initial calculation
calculateVh();
// Re-calculate on resize
window.addEventListener('resize', calculateVh);
// Re-calculate on device orientation change
window.addEventListener('orientationchange', calculateVh);
以上代码与先前的代码完全相同,无需分享视频。
在我看来,你应该首先采用 CSS 解决方案。我的意思是,这是一个仅使用 CSS 的解决方案,只有在必要时才使用 JavaScript!
评论(0)