首页 >web前端 >html教程 >CSS定位问题(1):盒模型、浮动、BFC_html/css_WEB-ITnose

CSS定位问题(1):盒模型、浮动、BFC_html/css_WEB-ITnose

WBOY
WBOY原创
2016-06-24 11:19:281180浏览

引子:

在谈到css定位问题的时候先来看一个小问题:

已知宽度(假如:100px)div框,水平居中,左右两边分别使用div框填充.且左右div自适应.

效果如下图:

这个问题的难点主要是浏览器宽度未知,且两边div自适应宽度.

第一种实现方法,是借助css3的新属性calc,实现代码如下:

body {    margin: 0;    padding: 0;    font-size:0;}.left_div {    background-color: #62FF09;    /*calc是css3属性可以动态计算,兼容不同浏览器的类型需要加识别的前缀,非常重要的是要有空格*/    width: -webkit-calc(50% - 50px);    width: calc(50%-50px);    height: 200px;}.mid_div {    width: 100px;    height: 200px;    margin-left: -50px;    background-color: #20FFDA;    margin:0 auto;}.right_div {    background-color: #FFF81B;    height: 200px;    width: -webkit-calc(50% - 50px);}div{display:inline-block;}

第二种实现方式就是借助与display属性,将所有的div框具有table的单元格的属性. 

代码如下:

* {    padding: 0;    margin: 0;}.left_div, .mid_div, .right_div {    height: 200px;    display: table-cell;}.left_div {    width: 50%;    background: #369;}.mid_div {    //非IE识别的属性,(>=IE8)    min-width: 100px;    width: 100px;    background: #697;}.right_div {    width: 50%;    background: #126;}

这里解决问题的主要思路是当中间的宽度确定后,因为所有div是单元格所以使用50%使左右的单元格平分剩下的宽度.

1.盒模型

盒模型又分IE盒模型和非IE盒模型:看下面的一张图(来自维基百科):

由上面的图可以知道IE和非IE盒模型的区别主要是计算元素的宽度和高度不一样。

  1. IE浏览器: margin-left+width+margin-right
  2. 非IE浏览器:margin-left+border-left+padding-left+width+padding-right+border-right+margin-right

看一段代码:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>box-html</title>    <style type="text/css">        *{margin:0;padding:0;}        #body-box{            width:700px;            height:500px;            background-color:#FF00FF;            /*overflow:hidden;*/        }        .box-style{            width:500px;            height:300px;            border:10px dashed black;            background-color:red;            margin:10px 0 0 20px;            padding: 10px 10px 10px 10px;        }    </style></head><body>    <div id="body-box">        <div class="box-style">你好帅呀</div>    </div></body></html>

效果如下:

很明显我们发现一个问题,就是子元素的margin-top作用在了父元素上。

当我们给父元素添加一个overflow:hidden属性时,结果正常。

如下图:

这是为什么呢?

overflow 样式值为 非 visilbe 时,实际上是创建了 CSS 2.1 规范定义的 Block Formatting Contexts。创建了它的元素,会重新计算其内部元素位置,从而获得确切高度。这样父容器也就包含了浮动元素高度。这个名词过于晦涩,在 CSS 3 草案中被变更为名词 Root Flow,顾名思义,是创建了一个新的根布局流,这个布局流是独立的,不影响其外部元素的。实际上,这个特性与 早期 IE 的 hasLayout 特性十分相似。

经过测试在IE8以上的浏览器表现与chrome和firefox浏览器表现效果相同。但是在IE7以下浏览器不用设置这个属性就可以表现正常的效果。如下图:

很明显发现的一个问题就是IE8(包括IE8)以上浏览器的background-color是border+padding+content.而IE8(不包括)是padding+content。

再来看一个示例,代码如下:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>TestBox</title>    <style type="text/css">    body{margin:0;}    .item1{        width:200px;        height:300px;        border:2px solid #f73bd6;        padding:100px 0 0 0;    }    .item2{        width:150px;        height:200px;        margin:150px 0 0 0;        border:2px solid #f73bd6;    }    </style></head><body>    <div class="item1">        <div class="item2"></div>    </div></body></html>

我非别在非IE浏览器(且>=IE8也同样的效果)中测试的结果如下:

在IE7中的效果如下图:

关于div的最小(最大)宽度和高度在IE8(>=)之上和非IE浏览器上都实现了min-height,maxheight,min-width,max-width这四个属性。

关于body的问题:

看下面一段代码:

<style type="text/css">        *{margin:0;padding:0;}        div{            width:300px;            height:200px;            background-color:#9feb3d;        }        body{            border:5px solid #eb3dda;            background-color:#3d3deb;        }    </style><body>    <div>        <ul>            <li>你是第1个</li>            <li>你是第2个</li>            <li>你是第3个</li>            <li>你是第4个</li>            <li>你是第5个</li>        </ul>    </div></body>

并且代码的效果图如下:

由上可以知道body是一个特殊的div(盒子)。它的background-color会延伸到margin。

标准流的概念:

在不使用其他的与排列和定位相关的特殊CSS规则时,各种元素的排列规则。


2.浮动

float 属性定义元素在哪个方向浮动。以往这个属性总应用于图像,使文本围绕在图像周围,不过在 CSS 中,任何元素都可以浮动。浮动元素会生成一个块级框,而不论它本身是何种元素,且浮动元素的宽度是根据内容的宽度确定的。

看下面的一段代码:

<body>    <span class="test-float1">你好吧</span>    <span class="test-float2">我是还是吧</span></body>

然后分别对.test-float1和.test-float2应用样式,代码如下:

*{padding:0;margin:0px;}        span{            background-color:#f73bd6;            margin:0 0 0 10px;        }        .test-float1{            float:left;            height:100px;            width:20px;        }        .test-float2{            /*float:left;*/            height:100px;            width:20px;        }

效果如下:

由上面的代码我们可以得出一个结论,span作为一个行内元素本来是没有width和height属性的,但是当对行内元素使用float属性后,该元素具有了width和height属性

注意:

假如在一行之上只有极少的空间可供浮动元素,那么这个元素会跳至下一行,这个过程会持续到某一行拥有足够的空间为止。

浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止。由于浮动框不在文档的普通流中,所以文档的普通流中的块框表现得就像浮动框不存在一样。

看下面的一段代码:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>TestFloat</title>    <style type="text/css">        body{            margin:0;        }        .item1, .item2, .item3, .item4{            width:200px;            height:100px;            background-color:#d8f73b;            margin:10px 0 0 0;        }        .item1{            float:right;        }        .item2{            /*float:left;*/        }    </style></head><body>    <div id="body-div">        <div class="item1">item1</div>        <div class="item2">item2</div>        <div class="item3">item3</div>        <div class="item4">item4</div>    </div></body></html>

这个时候看到页面的结果有一个很明显的bug,如下图:

可以很明显的看到在浮动的item1和item2有一个间隔没有在一条水平线上。

这个时候就回到了我们开头的问题,我们给父级的div盒子添加overflow属性触发父级div的BFC。代码如下:

<style type="text/css">        body{            margin:0;        }        //触发父级元素的BFC        #body-div{            overflow:hidden;        }        .item1, .item2, .item3, .item4{            width:200px;            height:100px;            background-color:#d8f73b;            margin:10px 0 0 0;        }        .item1{            float:right;        }        .item2{            /*float:left;*/        }    </style>

效果如下图:

有关BFC的定义:

BFC(W3C CSS 2.1 规范中的一个概念)就是所谓的Block formatting contexts (块级格式化上下文)。创建了 BFC的元素就是一个独立的盒子,里面的子元素不会在布局上影响外面的元素,反之亦然,同时BFC仍然属于文档中的普通流。

那么怎么触发BFC呢?

  1. float 除了none以外的值
  2. overflow 除了visible 以外的值(hidden,auto,scroll )
  3. display (table-cell,table-caption,inline-block)
  4. position(absolute,fixed)
  5. fieldset元素

注意:

display:table 本身并不会创建BFC,但是它会产生匿名框(anonymous boxes),而匿名框中的display:table-cell可以创建新的BFC,换句话说,触发块级格式化上下文的是匿名框,而不是 display:table。所以通过display:table和display:table-cell创建的BFC效果是不一样的。


fieldset 元素在www.w3.org里目前没有任何有关这个触发行为的信息,直到HTML5标准里才出现。有些浏览器bugs(Webkit,Mozilla)提到过这个触发行为,但是没有任何官方声明。实际上,即使fieldset在大多数的浏览器上都能创建新的块级格式化上下文,开发者也不应该把这当做是理所当然的。CSS 2.1没有定义哪种属性适用于表单控件,也没有定义如何使用CSS来给它们添加样式。用户代理可能会给这些属性应用CSS属性,建议开发者们把这种支持当做实验性质的,更高版本的CSS可能会进一步规范这个。

BFC的特性:

1)块级格式化上下文会阻止外边距叠加当两个相邻的块框在同一个块级格式化上下文中时,它们之间垂直方向的外边距会发生叠加。换句话说,如果这两个相邻的块框不属于同一个块级格式化上下文,那么它们的外边距就不会叠加。2)块级格式化上下文不会重叠浮动元素根据规定,一个块级格式化上下文的边框不能和它里面的元素的外边距重叠。这就意味着浏览器将会给块级格式化上下文创建隐式的外边距来阻止它和浮动元 素的外边距叠加。由于这个原因,当给一个挨着浮动的块级格式化上下文添加负的外边距时将会不起作用(Webkit和IE6在这点上有一个问题——可以看这 个测试用例)。3)块级格式化上下文通常可以包含浮动触发了BFC的话,就不会被float元素覆盖,当子元素全部浮动的时候也能够正确地包含了

深入研究浮动:

来看下面的一段代码:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Document</title>    <style type="text/css">        body{margin:0;}        #body-div{            background-color:#ffff99;            border:1px solid #111111;            padding:5px;        }        #body-div div{            padding:10px;            margin:15px;            background-color:#90baff;        }        #body-div p{            border:5px dashed #111111;            background-color:#ff90ba;        }        .item1{            border:5px dashed #111111;            /*float:left;*/        }        .item2{            border:5px dashed #f73b4d;        }        .item3{            border:5px dashed #0000CD;        }    </style></head><body>    <div id="body-div">        <div class="item1">Box-1</div>        <div class="item2">Box-2</div>        <div class="item3">Box-3</div>        <p>让我们更详细地看看浮动和清理。假设希望让一个图片浮动到文本块的左边,并且希望这幅图片和文本包含在另一个具有背景颜色和边框的元素中。您可能编写下面的代码:让我们更详细地看看浮动和清理。假设希望让一个图片浮动到文本块的左边,并且希望这幅图片和文本包含在另一个具有背景颜色和边框的元素中。您可能编写下面的代码:让我们更详细地看看浮动和清理。假设希望让一个图片浮动到文本块的左边,并且希望这幅图片和文本包含在另一个具有背景颜色和边框的元素中。您可能编写下面的代码:</p>    </div></body></html>

显示效果如下图:

2.1为Box-1设置浮动

.item1{            border:5px dashed #111111;            float:left;        }

效果如下图:

可以看到标准流中的Box-2的文字在围绕着Box-1排列,而此时的Box-1的宽度不再伸展,而是能容纳下内容的最小宽度。因为此时的Box-1已经脱离了标准流,标准流中的Box-2会顶到原来Box-1的位置(也就是Box-2的左边框和Box-1的左边框重合)此时Box-2的文字会围绕着Box-1排列。

2.2为Box-2设置浮动

.item2{            border:5px dashed #f73b4d;            float:left;        }

效果如下图:

这是很容易看出Box-3和Box-1的左边框重合。Box-3的文字围绕Box-2,并且Box-1和Box-2之间的空白是两者之间的margin产生的。

2.3为Box-3设置浮动

    .item3{            border:5px dashed #0000CD;            float:left;        }

效果如下图:

这个时候可以很明显的看出三个浮动的盒子(都脱离文档流)都被P标签的盒子所包围,并且被文字环绕。

2.4设置Box-3浮动的方向

.item3{            border:5px dashed #0000CD;            float:right;        }

效果如下图:

这个时候当我把浏览器窗口的宽度逐渐的缩小到不能容纳三个div宽度的时候,会有什么效果呢?如下图:

注意:

这种效果我只在IE浏览器(

在mac下得chrome,firefox和safari当窗口缩小到一定的宽度的时候,就无法在缩小宽度。无法出现Box-3被挤到下一行的情况。

如下图:

这时如果我们设置item2右浮动item3左浮动当我缩小浏览器窗口的时候,会出现如下的情况(mac下chrome和safari中仍旧是之上的情况,缩小到一定宽度无法再缩小)。

由此我们可以得出一个结论:

当浮动的元素在一行无法显示完全时,元素会按照普通流的顺序(Dom排列顺序)被挤到下一行。

2.5浮动的边界

增加Box-1的高度,当缩小浏览器的宽度的时候,会出现如下的现象:

主要是因为这个时候Box-3的边缘被Box-1的边缘卡住的缘故。

如下图红色的地方会有三个margin值:

2.6取消浮动的影响

使用CSS属性Clear,它有三个值left,right,both。

如我们取消p元素左右两侧的浮动:

代码如下:

#body-div p{            border:5px dashed #111111;            background-color:#ff90ba;            clear:both;        }

效果如下:

2.7浮动的影响

当然浮动对父级元素也会带来影响,比如说伟大的“塌陷”,看代码:

<style type="text/css">        body{margin:0;}        #body-div{            background-color:#ffff99;            border:1px solid #111111;            padding:5px;        }        #body-div div{            padding:10px;            margin:15px;            background-color:#90baff;        }        #body-div p{            border:5px dashed #111111;            background-color:#ff90ba;            clear:both;        }        .item1{            border:5px dashed #111111;            float:left;            height:30px;        }        .item2{            border:5px dashed #f73b4d;            float:left;        }        .item3{            border:5px dashed #0000CD;            float:left;        }    </style>

效果如下图:

所有子元素的浮动不会将父级元素的高度撑开。

那么怎么解决这个问题呢?

一个很古老的办法就是在所有子元素的末尾添加一个空的div,并且设置它的clear:both。看代码如下:

#body-div  .clear-float{            clear:both;            border:0;            padding:0;            margin:0;        }

效果如下:

其实我在IE各版本浏览器和非IE浏览器中测试的效果都是如上面的效果可意很容易的发现父级的div盒子并没有被完全的撑开。

不过有大神已经研究出了clearfix的写法,可以达到最合理的效果,主要目的就是触发父级盒子自身的BFC。

版本一:

    .clearfix:after {        content: "\200B";        display: block;        height: 0;        clear: both;    }    .clearfix {        *zoom: 1;/*IE/7/6*/    }

content:”\200B”;这个参数,Unicode字符里有一个“零宽度空格”,即 U+200B,代替原来的“.”,可以缩减代码量。而且不再使用visibility:hidden。

版本二:

.clearfix:before, .clearfix:after {    content: "";    display: table;}.clearfix:after {    clear: both;}.clearfix {*zoom: 1;        /*IE/7/6 */}

经过测试在IE的各个版本的浏览器中和非IE浏览器都能够正常的得到结果。

推荐阅读:

关于作者:zhiqiang21

做认为对的事情,如果可能是错的,那就做认为自己承受得起的事情! 个人主页 · 我的文章 · 3 ·              

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn