往 html 文件里第一行加上 DOCTYPE html 会导致什么

没想到吧!看上去只是个文档类型标记,看上去像是个注释的样子,但实际上会改变 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

结合这个答案以及其他资料,我总结出两点:

  1. doctype 标识是为了告诉编辑器 / 浏览器,这个文档是 html5 标准的,在 html5 之前,doctype 标识并不长这样。
  2. 如果浏览器发现第一行是 <!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 2 (w3c.github.io)

CSS Box Sizing Module Level 3 (w3c.github.io)

总结:

  1. 如果 min-height 或者 max-height 和 height 同时存在,则 height 不生效。
  2. 如果 html 元素的高度为百分比,则这个百分比基于浏览器的高度计算。
  3. 如果一个元素的高度为百分比,但是其父元素的高度是不确定的(受子元素影响),则该元素的高度与 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%,然后让其被子元素撑开就可以了。

作者: 梁小顺

脑子不太好用的普通人。 顺带一提性格也有点古怪。 在老妈子和厌世肥宅中来回切换。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据