没想到吧!看上去只是个文档类型标记,看上去像是个注释的样子,但实际上会改变 css 执行的方式捏!
我真的佛了(。
书承上回,我总算是弄好了 npm install 导致的问题,但是很快就遇到了一个新的问题。
在写 vue 界面的时候,需要一个高度宽度都占满显示器窗口的容器来放背景图片,一开始是可以生效的,但是在我改了一些 css 代码之后,它就不生效了。
原来的代码:
<!DOCTYPE html>
<html>
<head>
<style>
html, body {
margin: 0;
}
html {
height: 100%;
}
body {
height: 100%;
}
#app {
height: 100%;
background-color: pink;
}
</style>
</head>
<body>
<div id="app">啊</div>
</body>
</html>
但是,我希望 body 是一个可以通过内容来变长的元素,就像这样:
所以我把 body 的 height: 100% 改成了 min-height: 100%,但结果是:
进去一看,发现 app 元素的高度由全屏变成了刚好容纳子元素。
更神奇的是,当我去掉第一行的 <!doctype html> 后,#app 又恢复成全屏了:
在我的认识里,<!doctype html> 就只是个类似于注释的东西,不会对代码的实际表现有任何影响,但事实告诉我并不是如此。
于是我只好探索一下这究竟是怎么回事。
解谜篇
<!DOCTYPE html> 的作用
由于这个问题实在是有点冷门,我只找到了这么一个答案:
css – Why does height 100% work when DOCTYPE is removed? – Stack Overflow
结合这个答案以及其他资料,我总结出两点:
- doctype 标识是为了告诉编辑器 / 浏览器,这个文档是 html5 标准的,在 html5 之前,doctype 标识并不长这样。
- 如果浏览器发现第一行是 <!DOCTYPE html>,则会以标准模式(standards mode)去渲染这个网页,如果没有这行,则会以怪咖模式(quirks mode)渲染这个网页。
Quirks Mode and Standards Mode – HTML: HyperText Markup Language | MDN (mozilla.org)
在标准模式下,浏览器会按照 html5 设定的标准来渲染整个网页。而怪咖模式会为了兼容以前的一些老浏览器,选择一些与标准相悖的方式去渲染网页。
这样就明白了,doctype 确实会对实际效果产生影响。我的代码在怪咖模式下会产生与我的期待相符的结果,但是在标准模式下并不会。
Height attribute in CSS with Standards Mode
那么就来到了第二个问题,为什么标准模式的表现与我期待的不符?
在 CSS 中,如果某个元素的 height 属性如果被指定了一个百分比值(percentage value),那么这个元素的高度则是 父元素的高度 * 百分比。
body 的高度是浏览器的高度,我又把 #app 的高度设定为了 100%,那为什么 #app 的高度却不是浏览器的高度呢?
只能翻翻 CSS 标准看看 CSS 标准怎么说了:
CSS Box Sizing Module Level 3 (w3c.github.io)
总结:
- 如果 min-height 或者 max-height 和 height 同时存在,则 height 不生效。
- 如果 html 元素的高度为百分比,则这个百分比基于浏览器的高度计算。
- 如果一个元素的高度为百分比,但是其父元素的高度是不确定的(受子元素影响),则该元素的高度与 auto 表现一致。
分析
一开始,html 的高度是 100%,所以 html 的高度是确定的,那就是浏览器的高度。
然后,body 的高度是 100%,所以 body 和其父元素 html 的高度是一样的。
最后,#app 的高度是 100%,所以 #app 的高度和其父元素 body 的高度是一样的。
这样就达到一个 #app 高度和屏幕高度一致的效果。
但在我把 body 的高度修改为 min-height: 100% 之后:
html 的高度仍是 100%,所以 html 的高度仍是确定的,那就是浏览器的高度。
body 的 min-height 为 100%,也就是说 body 的高度至少和 html 一致,但并不是固定的,根据内部子元素的变化,body 的 height 可能超过 100%。所以 body 的 height 是一个不确定值。
#app 的 height 为 100%,但由于其父元素 body 的高度是个不确定值,所以 #app 的高度表现和 auto 一致,所以 #app 的高度为刚好被子元素撑开的样子。
至此,分析完毕。
后记
到后来我发现,想要达成我之前想的那个效果,并不需要对 body 使用 min-height: 100%。
因为元素的 overflow 属性默认是 visible,所以就算 #app 的高度超过了 body,也还是可见的,那只需要把 #app 的 min-hegiht 属性设置为 100%,然后让其被子元素撑开就可以了。