首页
Preview

为什么不应该依赖CSS的100vh?

你有一段文本和一个按钮,你想让文本固定在顶部,按钮固定在底部!看起来很简单。我们可以使用 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 &lt;!DOCTYPE html&gt; 声明会阻止 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!

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
一个人玩
先找到想要的,然后出发

评论(0)

添加评论