多年来,我一直在参考 Matthew James Taylor 的文章来解决一个问题:无论主内容的长度如何,都能将网页页脚保持在页面底部。这种方法需要为页脚设置明确的高度,虽然不具有可伸缩性,但在 Flexbox 出现之前是一个非常好的解决方案。
如果你主要从事 SPA 开发,你可能会对这个问题仍然存在感到困惑,但在以下情况下,你仍然有可能发现页脚浮起来了:
- 登录页面
- 博客/新闻文章(没有广告...)
- 流程的中间页面,如确认操作
- 产品列表页面
- 日历事件详情页面
译注:SPA 是单页 Web 应用(single page web application)的英文缩写。
现代 CSS 中有两种方法可以解决这个问题:flexbox 和 grid。
下面的演示默认是使用 flexbox 实现的。你可以尝试将 $method 变量的值切换成 grid 看一下另一种方案的效果。
Flexbox 方案
这种方案是使用下面的样式定义实现的:
body {
min-height: 100vh;
display: flex;
flex-direction: column;
}
footer {
margin-top: auto;
}
/* 可选 */
main {
margin: 0 auto;
/* 或: align-self: center */
max-width: 80ch;
}
工作原理
首先,我们设置 min-height: 100vh 确保 body 元素的高度至少为屏幕高度。如果内容较短,这是不会有溢出的(例外:某些移动浏览器),并且这使得高度可以随内容拉升。
设置 flex-direction: column 可以保持正常文档流的行为,即在保持堆叠块级元素(这里假设 body 的直接子元素都是块元素)。
译注:这里是说,未设置
display: flex;时的文档流行为是body的直接子元素会按照它们在源代码中的顺序垂直堆叠(假设都为块元素),设置flex-direction: column内保持这种行为。
flexbox 的优势在于利用 margin: auto 的行为。这个奇怪的技巧使得外边距会填充元素与其临近兄弟元素间的空间。设置 margin-top: auto 有效地将页脚推到屏幕的底部。
陷阱
在演示中,我给 main 元素添加了轮廓,以说明使用 flexbox 方案时,main元素不会填充高度。这就是我们必须设置 margin-top: auto 的原因。这对你来说可能不重要,但如果你觉得这重要,请参阅 grid 方案,它会拉伸 main 元素以填充可用空间。
Grid 方案
此方案通过设置以下样式来实现:
body {
min-height: 100vh;
display: grid;
grid-template-rows: auto 1fr auto;
}
/* 可选 */
main {
margin: 0 auto;
max-width: 80ch;
}
工作原理
在这个方案中,我保留了 min-height: 100vh,但之后我们使用 grid-template-rows 设置了正确的排列方式。
此方案的技巧在于使用特殊的网格单位 fr。fr 表示 “fraction”,使用它请求浏览器计算可用于该行或该列的空间“分数”。在本例中,它会填充页眉和页脚之间的所有可用空间,这就解决了 flexbox 方案中的“陷阱”。
哪种方案更好?
看过 grid 方案,你可能会有一瞬间认为它显然更更好。然而,如果你需要在页眉和页脚之间添加了更多元素,你就得更新的模板(或确保总是有一个包装元素,如 div,以不影响任何嵌套的语义/层次结构)。
译注:更新模板是说:添加元素之后就不只是三行了,
grid-template-rows: auto 1fr auto;自然不起作用,你需要更新模板设置新添加元素得行高。或者说保持行数为三不变,只是页眉和页脚之间的元素使用div一类的元素包裹。
另一方面,flexbox 方法可用于具有多个块元素的多个模板的中间部分: 例如,一系列 <article> 元素,而不是单个 <main> 元素用于存档页面。
译注:这是说,对于需要多个块元素时,如一系列
<article>元素,使用 flexbox 是方便的,使用 grid 可能需要更多的设置。
因此,与所有技术一样,哪种方案更好取决于项目:) 但我们都可以同意,拥有这些现代 CSS 布局方法真是 amazing!