在Nuxt 4中,如何让位于头部下方的Hero区块填满剩余的视口高度,并且在页面变长时不会出错?
我目前在用Nuxt 4 + Tailwind CSS构建一个网站,在Nuxt布局中遇到了视口单位 (dvh, vh) 和百分比高度 (h-full) 的问题。
我的布局结构基本如下:
- 一个全局的
default.vue布局 - 其中有一个
Header和一个main - 在页面的
index中渲染多段(Hero,OurTechnologies等),它们使用默认布局
当前布局看起来是这样的:
<template>
<div class="min-h-dvh grid grid-rows-[auto_1fr]">
<LayoutHeader />
<main>
<slot />
</main>
</div>
</template>
关于 index.vue:
<template>
<LayoutSectionsHomeHero />
<LayoutSectionsSeparator />
<LayoutSectionsHomeOurTechnologies />
</template>
关于 HeroSection.vue:
<template>
<section
class="homeHero__main-section h-full flex flex-col items-center justify-center" >
<h1 class="homeHero__main-title title__default text-center">
Welcome to
<br />
<span class="gradient__text bg-linear-green-1">
<span class="mt-5 inline-block">AutoAI</span>
<span class="hidden sm:inline"> - </span>
<br class="sm:hidden" />
<span>Pandemics</span>
</span>
</h1>
<p class="homeHero__welcome-paragraph text__default mt-5 text-center">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur.
</p>
<div class="homeHero__buttons-container mt-10 flex w-full flex-col gap-5">
<UiButtonsPrimary class="font-header-text">
Explore our technologies
</UiButtonsPrimary>
<UiButtonsSecondary class="font-header-text">
About us
</UiButtonsSecondary>
</div>
</section>
</template>
最后是 OurTechnologiesSection.vue
<template>
<section class="homeOurTechnologies__main-section flex flex-col items-center">
<UiCardsTool
v-for="item in tools"
:toolName="item.toolName"
:toolDescription="item.toolDescription"
:toolLink="item.toolLink"
></UiCardsTool>
</section>
</template>
<script setup lang="ts">
const tools = [
{ toolName: "Test", toolDescription: "This is test", toolLink: "/" },
{ toolName: "Test", toolDescription: "This is test", toolLink: "/" },
{ toolName: "Test", toolDescription: "This is test", toolLink: "/" },
{ toolName: "Test", toolDescription: "This is test", toolLink: "/" },
];
</script>
问题在于:
- 如果页面只包含Hero区块,一切工作正常。见下图
- Hero会按预期填充标题栏下方的剩余视口空间。
- 但一旦在其下方再添加一个区段(
OurTechnologies),Hero突然变得比视口高得多,如下图:
原因如下:
justify-center开始基于整页高度进行居中,而不仅仅是可见屏幕的高度。- Hero的内容被垂直向下推。
- DevTools中选中的元素高度变得比视口大很多。
我想要的是一个Hero区块,始终恰好填充标题栏下方剩余的可见视口区域,采用响应式布局的最佳实践(如上图第一张所示)。
哦,我也尝试过:
h-fullmin-h-fullh-dvhmin-h-dvh- CSS
calc() - 改变网格/弹性布局配置
在Hero区块里,但页面纵向增长后,行为仍然会被破坏。
*小注:如果你愿意,也请就Vue、HTML、CSS和最佳实践给我反馈。我刚开始前端开发之旅,想尽可能多地了解这个庞大的领域,也请原谅我的英文 :)
解决方案
问题在于 h-full 只有在树上每个父级元素都有确定的高度时才起作用。在你的情况下,当你添加下一个区段时,页面会变得更高,因此Hero不再只以标题栏下方的可见区域来进行测量。
我会让Hero定义自己的最小高度:
<section class="min-h-[calc(100dvh-var(--header-height))] flex flex-col items-center justify-center">
然后给头部一个已知高度,例如:
:root {
--header-height: 72px;
}
或者在Tailwind中,如果头部高度是固定的:
<section class="min-h-[calc(100dvh-72px)] flex flex-col items-center justify-center">
你的布局可以保持如下:
<div class="min-h-dvh">
<LayoutHeader />
<main>
<slot />
</main>
</div>
关键点是:在这里不要为Hero使用 h-full。h-full 取决于父级高度,而 min-h-[calc(...)] 为Hero赋予了基于视口的高度,同时仍然允许页面其余部分在其下继续。
备选方案
问题来自 h-full。
h-full 只有在所有父元素都具有定义高度时才起作用。在我的情况中,当我在Hero下再添加一个区段时,页面高度会大于视口,因此父级不再等于可见屏幕高度。
因此,Hero不再受视口限制,而是随整个页面一起增长。这就是为什么 justify-center 开始基于整页高度来居中,而不仅仅是可见区域。
只有Hero区块时,工作正常,因为页面高度等于视口,因此 h-full 也意外地按预期工作。
一个更好的解决方案是避免 h-full,改用带calc的基于视口的高度,例如:
<section class="flex flex-col items-center justify-center min-h-[calc(100dvh-72px)]">
这样Hero始终占据标题栏下方的剩余空间,即使添加更多区段也能正常工作。