【前端芝士树】详解CSS盒模型、BFC、OffsetWidth&ClientWidth&ScrollWidth

深刻理解CSS盒模型、BFC、OffsetWidth&ClientWidth&ScrollWidth

本文将从盒模型开始,一步步涉及一些常见的前端笔试和面试点
主要参考自第一篇文章,然而笔者在读的时候未觉详尽,便又去网上查阅了一番,扩充了其内容,但愿也能给同窗们提供一些参考。

下面本文章将会从如下几个方面谈谈盒模型。css

  • 基本概念:标准模式和怪异模式,标准模型和IE模型
  • CSS如何设置这两种模型
  • JS如何设置获取盒模型对应的宽和高
  • 实例题(根据盒模型解释边距重叠)
  • BFC(边距重叠解决方案)

1.盒模型是什么

2018搜狐前端笔试题
盒模型本质上是用以封装HTML元素的概念盒子,它包含了边距,边框,填充以及实际内容。
即由外向里是 margin, border, padding, contenthtml

2.为何会有两种不一样的盒模型(标准模式和怪异模式)

在了解两种不一样的盒模型以前,须要先了解一下为何会产生两种不一样的盒模型。前端

当年,Netscape4(译注:网景公司早期的浏览器)和IE4(微软公司早期的浏览器)实现CSS机制时,并无遵循W3C提出的标准。Netscape4 提供了糟糕的支持,而IE4 虽然接近标准,但依旧未能彻底正确的支持标准。尽管IE 5 修复了IE4 许多的问题(bugs),可是依然延续CSS实现中的其它故障(主要是盒模型(box model)问题)。面试

然而随着标准一致性变得愈来愈重要,浏览器开发商不得不面临一个艰难的抉择:逐渐遵循W3C的标准是前进的方向。可是改变现有CSS的实现,完整去遵循标准,会使许多网站或多或少受到破坏。若是浏览器忽然以正确的方式解析现存的CSS,陈旧的网站显示必然受到影响。浏览器

因而,全部的浏览器开始提供两种模式:怪异模式(即兼容模式 Quirks Mode/Compalibility Mode)服务于旧式规则,严格模式(即标准模式 Standard Mode/Strict Mode)服务于标准规则。Mac平台的IE浏览器最早实现这两种模式,Mozilla, Safari、Opera和Windows平台的IE6也相继实现了这两种模式。Windows平台的IE5和Netscape4则只提供了怪异模式。dom

选择使用哪一种模式须要一个触发器,而 “DOCTYP切换” 则用于此目的。依照标准,任何一个(X)HTML文档必须拥有一个DOCTYPE(译注:DTD(文档类型定义)是一组机器可读的规则,它们指示(X)HTML文档中容许有什么,不容许有什么,DOCTYPE正是用来告诉浏览器使用哪一种DTD,通常放在(X)HTML文档开头声明)用以告诉其余人这个文档的类型风格布局

  1. 产生于标准化浪潮之前的网页并无DOCTYPE声明。所以'没有DOCTYPE'意味着触发怪异模式:既依据旧式的CSS规则渲染网页。
  2. 相反,若是开发者明确知道包含DOCTYPE,他们应该明白他们想要怎么作。所以大部分的DOCTYPE声明将触发严格模式:即依据标准的CSS规则渲染网页。
  3. 任何新的或未知的DOCTYPE将触发严格模式。
  4. 一些页面依据怪异模式而写,可是却包含DOCTYPE。这种状况下各个浏览器依据本身的DOCTYPE规则列表来触发怪异模式。

全部IE的触发 —— 在DTD声明前加上HTML注释
<!--Let IE into quirks mode--> 只要在DTD声明前加注释或者任何标签便可
<!DOCTYPE html>xmlflex

对于以上两种不一样的网页模式,产生了两种不一样的盒模型,一个是标准模型,一个是IE模型网站

clipboard.png

clipboard.png

标准模型的宽高 = 内容(content)的宽高,ui

IE盒模型的宽高 = 内容(content) + 填充(padding) + 边框(border)的总宽高。

3.经过CSS3设置两种模型

这里用到了 CSS3 的属性 box-sizing

标准模型
box-sizing:content-box;

IE模型
box-sizing:border-box;

4.经过JavaScript获取宽高

经过JS获取盒模型对应的宽和高,有如下几种方法:
为了方便书写,如下用dom来表示获取的HTML的节点。

<div class="container">
    <div id="contentBox" class="contentBox"></div>
</div>

var body = document.getElementsByClassName('container');
var dom = document.getElementById('contentBox');

1.dom.style.width/height

  这种方式只能取到dom元素内联样式所设置的宽高,也就是说若是该节点的样式是在style标签中或外联的CSS文件中设置的话,经过这种方法是获取不到dom的宽高的。

<div id="contentBox" class="contentBox" style="width: 100px;"></div>
console.log('Dom.style.width:' + dom.style.width); //100px

2.dom.currentStyle.width/height

  这种方式获取的是在页面渲染完成后的结果,就是说不论是哪一种方式设置的样式,都能获取到,但这种方式只有IE浏览器支持。

console.log('Dom.currentStyle.width:' +  dom.currentStyle.width); //Cannot read property 'width' of undefined

3.window.getComputedStyle(dom).width/height

  这种方式的原理和2是同样的,这个能够兼容更多的浏览器,通用性好一些。

console.log('Window.getComputedStyle(dom).width' + window.getComputedStyle(dom).width); //100px

4.dom.getBoundingClientRect().width/height

getBoundingClientRect 用于获取某个元素相对于视窗的位置集合
经过计算元素的位置,来获取对应的宽高

console.log('Dom.getBoundingClientRect().width: ' + dom.getBoundingClientRect().width); //160

5.dom.offsetWidth/offsetHeight

对象所在元素的实际宽度

console.log('Dom.offsetWidth: ' + dom.offsetWidth); //160

具体状况如图所示
其中,盒模型为标准模型,元素内容宽度为100px, padding宽度为10px,border宽度为20px, margin宽度为30px
clipboard.png

5.DOM属性之 OffsetWidth / ClientWidth / ScrollWidth

  1. OffsetWidth 对象所在元素的实际宽度

    dom.offsetWidth = dom_content + padding + border(包含滚动条)+ margin
  2. ClientWidth 对象内容的可视区域的宽度

    dom.clientWidth = dom_content + padding(不包含滚动条)
  3. ScrollWidth 对象的实际内容的宽度(包含滚动区域中未显示彻底的部分)

    dom.scrollWidth = real_content + padding

6.边距重叠

什么是边距重叠

以下图,父元素没有设置margin-top,而子元素设置了margin-top:20px;能够看出,父元素也一块儿有了边距。

clipboard.png

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        *{
            margin:0;
            padding:0;
        }
        .demo{
            height:100px;
            background: #eee;
        }
        .parent{
            height:200px;
            background: #88f;
        }
        .child{
            height:100px;
            margin-top:20px;
            background: #0ff;
            width:200px;
        }
    </style>
</head>
<body>
    <section class="demo">
        <h2>此部分是能更容易看出让下面的块的margin-top。</h2>
    </section>
    <section class = "parent">
        <article class="child">
            <h2>子元素</h2>
            margin-top:20px;
        </article>
        <h2>父元素</h2>
            没有设置margin-top
    </section>
</body>
</html>

7.边距重叠解决方案(BFC)

首先要明确BFC是什么意思,其全英文拼写为 Block Formatting Context 直译为“块级格式化上下文”

BFC的原理

  • 内部的box会在垂直方向,一个接一个的放置 每一个元素的margin box的左边,与包含块border
  • box的左边相接触(对于从作往右的格式化,不然相反)
  • box垂直方向的距离由margin决定,属于同一个bfc的两个相邻box的margin会发生重叠 bfc的区域不会与浮动区域的box重叠
  • bfc是一个页面上的独立的容器,外面的元素不会影响bfc里的元素,反过来,里面的也不会影响外面的
  • 计算bfc高度的时候,浮动元素也会参与计算

怎么去建立BFC

  • float属性不为none(脱离文档流)
  • position为absolute或fixed
  • display为inline-block,table-cell,table-caption,flex,inine-flex
  • overflow设置为scroll/hidden/overlay/auto
  • 根元素

应用场景

  1. 自适应两栏布局
  2. 清除内部浮动
  3. 防止垂直margin重叠

看一个垂直margin重叠例子

<div class="container">
    <div class="backgroundDom">
        <div class="top">&nbsp;Top margin-bottom: 30px</div>
        <div class="bottom">&nbsp;Bottom margin-top: 50px</div>
    </div>
</div>

.top{
    margin-bottom:30px;
}
.bottom{
    margin-top: 50px;
}
.top, .bottom{
    width: 100%;
    height: 100px;
    line-height: 100px;
    background: cornflowerblue;
}

效果图

clipboard.png

用BFC能够解决垂直margin重叠的问题

方法一 采用float或者position设置为absolute/fixed 脱离文档流

float: left;
position: absolute;// 或者fixed

方法二 设置display为inline-block,table-cell,table-caption,flex,inine-flex

display: inline-block;

clipboard.png

方法三 添加一个父元素包裹,并设置overflow为scroll/hidden/overlay/auto

<div class="container">
    <div class="backgroundDom">
        <div class="top">&nbsp;Top margin-bottom: 30px</div>
        <div style="overflow: hidden">
            <div class="bottom">&nbsp;Bottom margin-top: 50px</div>
        </div>
    </div>
</div>

clipboard.png

参考连接

相关文章
相关标签/搜索