CSS3与页面布局学习总结(四)——页面布局大全BFC、定位、浮动、7种垂直居中方法

一、BFC与IFC

1.1、BFC与IFC概要

BFC(Block Formatting Context)即“块级格式化上下文”, IFC(Inline Formatting Context)即行内格式化上下文。常规流(也称标准流、普通流)是一个文档在被显示时最常见的布局形态。一个框在常规流中必须属于一个格式化上下文,你可以把BFC想象成一个大箱子,箱子外边的元素将不与箱子内的元素产生作用。

BFC是W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。当涉及到可视化布局的时候,Block Formatting Context提供了一个环境,HTML元素在这个环境中按照一定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。比如浮动元素会形成BFC,浮动元素内部子元素的主要受该浮动元素影响,两个浮动元素之间是互不影响的。也可以说BFC就是一个作用范围。

在普通流中的 Box(框) 属于一种 formatting context(格式化上下文) ,类型可以是 block ,或者是 inline ,但不能同时属于这两者。并且, Block boxes(块框) 在 block formatting context(块格式化上下文) 里格式化, Inline boxes(块内框) 则在 Inline Formatting Context(行内格式化上下文) 里格式化。

1.2、如何产生BFC

当一个HTML元素满足下面条件的任何一点,都可以产生Block Formatting Context:
a)、float的值不为none

b)、overflow的值不为visible

c)、display的值为table-cell, table-caption, inline-block中的任何一个

d)、position的值不为relative和static

CSS3触发BFC方式则可以简单描述为:在元素定位非static,relative的情况下触发,float也是一种定位方式。

1.3、BFC的作用与特点

a)、不和浮动元素重叠,清除外部浮动,阻止浮动元素覆盖

如果一个浮动元素后面跟着一个非浮动的元素,那么就会产生一个重叠的现象。常规流(也称标准流、普通流)是一个文档在被显示时最常见的布局形态,当float不为none时,position为absolute、fixed时元素将脱离标准流。

没有BFC的情况:

示例代码:

 View Code

运行结果:

此时的div1因为float已经产生了BFC,在div2中添加样式overflow:hidden让其产生BFC,代码如下:

复制代码
            #div2{
                 300px;
                height: 300px;
                background: lightblue;
                overflow: hidden;
            }
复制代码

运行结果:

b)、清除元素内部浮动,计算浮动元素的高度

只要把父元素设为BFC就可以清理子元素的浮动了,最常见的用法就是在父元素上设置overflow: hidden样式,对于IE6加上zoom:1就可以了(IE Haslayout)。

当一个元素的内部元素浮动时不会计算其高度,示例如下:

 View Code

运行结果:

修改div0让其触发BFC,还原高度,代码如下:

复制代码
            #div0 {
                border: 2px solid lightsalmon;
                padding: 20px;
                 400px;
                overflow: hidden;  /*让div0触发BFC*/
            }
复制代码

运行结果:

 

c)、外边距将不再与上下文之外的元素折叠 

示例代码:

 View Code

如果此时将脚本的div1与div2同时变成BFC环境,修改的css如下:

复制代码
            #div1 {
                 200px;
                height: 200px;
                background: lightgreen;
                margin-bottom: 100px;
                overflow: hidden;
            }
            
            #div2 {
                 200px;
                height: 200px;
                background: lightblue;
                margin-top: 100px;
                overflow: hidden;
            }
复制代码

执行时会发现效果还是一样,此时的div1与div2都是BFC上下文,但是要求的是:外边距将不再与上下文之外的元素折叠,按照要求,我们应该将div1与div2放在不同的上下文中,修改后的脚本如下:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>BFC与IFC</title>
        <style type="text/css">
            #div1 {
                 200px;
                height: 200px;
                background: lightgreen;
                margin-bottom: 100px;
            }
            
            #div2 {
                 200px;
                height: 200px;
                background: lightblue;
                margin-top: 100px;
            }
            #div2-outer
            {
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <h2>BFC与IFC</h2>
        <div id="div1">div1
        </div>
        <div id="div2-outer">
            <div id="div2">div2
            </div>
        </div>
    </body>
</html>
复制代码

运行结果如下:

 d)、元素会一个接一个地被垂直放置,它们的起点是一个包含块的顶部(文字不会环绕布局)

示例代码:

 View Code

没有BFC时的运行结果:

从运行结果可以看出div与p还是重叠了,只是文字被挤出,和前面提到的重叠是同一个意思,将p元素触发BFC后的效果如下图所示:

            p{
                overflow: hidden;
            }

运行结果:

1.4、IE与Layout

Layout是 IE 浏览器渲染引擎的一个组成部分。在 IE 浏览器中,一个元素要么自己对自身的内容进行组织和计算大小, 要么依赖于包含块来计算尺寸和组织内容,hasLayout 与 BFC 有很多相似之处。在IE中,元素使用“布局”概念来控制尺寸和定位,分为拥有布局和没有布局两种情况,拥有布局的元素由它控制本身及其子元素的尺寸和定位,而没有布局的元素则通过父元素(最近的拥有布局的祖先元素)来控制尺寸和定位,而一个元素是否拥有布局则由 hasLayout 属性告知浏览器,它是个布尔型变量,true 代表元素拥有布局,false 代表元素没有布局。简而言之,hasLayout 只是一个 IE 下专有的属性,hasLayout 为 true 的元素浏览器会赋予它一系列的效果。
特别注意的是,hasLayout 在 IE 8 及之后的 IE 版本中已经被抛弃,所以在实际开发中只需针对 IE 8 以下的浏览器为某些元素触发 hasLayout。

出发IE下的haslayout方法:

display: inline-block
height: (除 auto 外任何值)
(除 auto 外任何值)
float: (left 或 right)
position: absolute
writing-mode: tb-rl
zoom: (除 normal 外任意值)
min-height: (任意值)
min- (任意值)
max-height: (除 none 外任意值)
max- (除 none 外任意值)
overflow: (除 visible 外任意值,仅用于块级元素)
overflow-x: (除 visible 外任意值,仅用于块级元素)
overflow-y: (除 visible 外任意值,仅用于块级元素)
position: fixed

综合前面的内容清除浮动的写法如下:

复制代码
.floatfix{
*zoom:1;  /*在旧版本的IE浏览器缩放大小,触发haslayout*/
}
.floatfix:after{
content:"";
display:table;
clear:both;
}
复制代码

除了BFC还有IFC,GFC,FFC,是不同格式化上下文(Formatting Context)的简称,GFC是网格格式化上下文(Grid Formatting Context),FFC是弹性盒格式化上下文(Flex Formatting Context),FKC是开封菜的意思:)。

二、定位

使用css布局position非常重要,他的语法如下:

position:static | relative | absolute | fixed | center | page | sticky
默认值:static,center、page、sticky是CSS3中新增加的值。

2.1、static
可以认为静态的,默认元素都是静态的定位,对象遵循常规流。此时4个定位偏移属性不会被应用,也就是使用left,right,bottom,top将不会生效。

示例:

 View Code

运行结果:

定义偏移并未起作用。

2.2、relative

相对定位,对象遵循常规流,并且参照自身在常规流中的位置通过top,right,bottom,left这4个定位偏移属性进行偏移时不会影响常规流中的任何元素。

示例代码:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>相对定位</title>
        <style type="text/css">
            div {
                 200px;
                height: 200px;
                background: lightblue;
                margin: 10px;
            }
            #div1 {
                position: relative;  /*相对定位*/
                left:30px;  /*在自己原有位置上相对左边偏移30像素*/
                bottom: -30px;
                background: lightgreen;
            }
        </style>
    </head>
    <body>
        <div id="div1">div1
        </div>
        <div id="div2">div2
        </div>
    </body>
</html>
复制代码

运行结果:

2.3、absolute

绝对定位,对象脱离常规流,此时偏移属性参照的是离自身最近的定位祖先元素,如果没有定位的祖先元素,则一直回溯到body元素。盒子的偏移位置不影响常规流中的任何元素,其margin不与其他任何margin折叠。

元素定位参考的是离自身最近的定位祖先元素,要满足两个条件,第一个是自己的祖先元素,可以是父元素也可以是父元素的父元素,一直找,如果没有则选择body为对照对象。第二个条件是要求祖先元素必须定位,通俗说就是position的属性值为非static都行。

示例代码:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>绝对定位</title>
        <style type="text/css">
            div {
                border: 2px solid darkturquoise;
                padding: 10px;
            }
            
            #div1 {
                 400px;
                height: 400px;
            }
            
            #div2 {
                 300px;
                height: 300px;
            }
            
            #div3 {
                 200px;
                height: 200px;
                position: absolute;
                right: 5px;
                top: 5px;
            }
        </style>
    </head>

    <body>
        <div id="div1"> div1
            <div id="div2"> div2
                <div id="div3">div3
                </div>
            </div>
        </div>

    </body>

</html>
复制代码

运行结果:

 因为div3使用absolute绝对定位,它的参考对象是父元素div2,div1都不满足条件,因为两者都没有进行定位,是默认的定位值static,根据约定最终找到body,所以会出现在页面的右上角。此时如果想让div3的参照对象为div1,则可以修改代码为:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>绝对定位</title>
        <style type="text/css">
            div {
                border: 2px solid darkturquoise;
                padding: 10px;
            }
            #div1 {
                 400px;
                height: 400px;
                position: relative;  /*相对定位*/
            }
            #div2 {
                 300px;
                height: 300px;
            }
            #div3 {
                 200px;
                height: 200px;
                position: absolute;
                right: 5px;
                bottom: 5px;
            }
        </style>
    </head>
    <body>
        <div id="div1"> div1
            <div id="div2"> div2
                <div id="div3">div3
                </div>
            </div>
        </div>
    </body>
</html>
复制代码

运行结果:

 

2.4、fixed

固定定位,与absolute一致,但偏移定位是以窗口为参考。当出现滚动条时,对象不会随着滚动。

简单的回顶端示例代码:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>固定定位</title>
        <style type="text/css">
            body{
                height: 3000px;
            }
            #top{
                 50px;
                height: 70px;
                line-height: 70px;
                text-align: center;
                background: lightblue;
                position: fixed;
                right: 1px;
                bottom: 30%;
            }
        </style>
    </head>
    <body>
        <h2 id="title">固定定位</h2>
        <div id="top"><a href="#title">回顶部</a></div>
    </body>
</html>
复制代码

运行结果:

练习:

center:
与absolute一致,但偏移定位是以定位祖先元素的中心点为参考。盒子在其包含容器垂直水平居中。(CSS3)
page:
与absolute一致。元素在分页媒体或者区域块内,元素的包含块始终是初始包含块,否则取决于每个absolute模式。(CSS3)
sticky:
对象在常态时遵循常规流。它就像是relative和fixed的合体,当在屏幕中时按常规流排版,当卷动到屏幕外时则表现如fixed。该属性的表现是现实中你见到的吸附效果。(CSS3)

2.5、z-index属性

语法:z-index: auto | <integer>
默认值:auto
适用于:定位元素。即定义了position为非static的元素
取值:
auto: 元素在当前层叠上下文中的层叠级别是0。元素不会创建新的局部层叠上下文,除非它是根元素。 
整数: 用整数值来定义堆叠级别。可以为负值。 说明:
检索或设置对象的层叠顺序。 
z-index用于确定元素在当前层叠上下文中的层叠级别,并确定该元素是否创建新的局部层叠上下文。 
当多个元素层叠在一起时,数字大者将显示在上面。

 示例:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            div {
                 200px;
                height: 200px;
                position: absolute;
            }
            #div1 {
                background: lightsalmon;
            }
            #div2 {
                background: lightgreen;
                left: 33px;
                top: 33px;
                z-index: 1;
            }
            #div3{
                background: lightblue;
                left: 66px;
                top: 66px;
            }
        </style>
    </head>
    <body>
        <div id="div1">
            div1
        </div>
        <div id="div2">
            div2
        </div>
        <div id="div3">
            div3
        </div>
    </body>
</html> 
复制代码

未指定z-index时默认运行效果:

指定div2的z-index值时的运行效果:

2.6、菜单

使用前面的内容实现了一个简单的下拉菜单,效果如下:

菜单结构:

 View Code

示例代码:

 View Code

运行结果:

2.7、:target伪类

语法:
E:target { css }
说明:
匹配相关URL指向的E元素。
解释:URL后面跟锚点#,指向文档内某个具体的元素。这个被链接的元素就是目标元素(target element),:target选择器用于选取当前活动的目标元素。只有支持CSS3的浏览器可用。

 View Code

运行结果:

通俗说就是url中的#选中的id元素将被css选择。在完成没有js的菜单,选项卡时如果不考虑ie8则可以使用这种新的办法。

三、浮动

浮动在CSS布局中饱受诟病,因为控制起来比较麻烦,但如果掌握了他的特性使用起来还是不难的,在CSS中使用float指定浮动属性值,该属性的值指出了对象是否及如何浮动,浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止。由于浮动框不在文档的标准流中,所以文档的标准流中的块框表现得就像浮动框不存在一样。float的基本语法如下:

float:none | left | right

3.1、float取值

none: 设置对象不浮动,默认值

left: 设置对象浮在左边

right: 设置对象浮在右边

3.2、float的特性

a)、浮动元素会从标准流中脱离

b)、浮动元素会触发BFC(块级元素格式化)、不影响外边距折叠

c)、 float元素会变成块标签

如果float不是none,当display:inline-table时,display的计算值为table;当display:inline | inline-block | run-in | table-* 系时,display的计算值为block,其它情况为指定值。

示例代码:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>float</title>
        <style type="text/css">
            #span1{
                 100px;
                height: 100px;
                background: lightgreen;
                float: right;
            }
        </style>
    </head>
    <body>
        <span id="span1">span1</span>
    </body>
</html>
复制代码

 不设置float时的效果:

设置向右float时的效果:

span是一个行内标签,默认设置高宽无效,但浮动后自动变成了块标签。

d)、float在绝对定位和display为none时不生效

当display为node时元素会隐藏,所以float意义不大;当position为absolute绝对定位时元素也将从标准流中脱离,元素使用偏移量移动,float特性无效。

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>float</title>
        <style type="text/css">
            #div1{
                 100px;
                height: 100px;
                background: lightgreen;
                float: right;
                position: absolute;
                bottom: 5px;
                left: 5px;
            }
        </style>
    </head>
    <body>
        <div id="div1">span1</div>
    </body>
</html>
复制代码

e)、浮动元素间会堆叠

浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止,浮动元素间的堆叠示例:

 View Code

运行结果:

f)、浮动元素不能溢出包含块

浮动元素在包含块内,当包含块的宽度不足以容下浮动的子元素时,将自动折行;垂直方向当包含块认为浮动的子元素没有高度时,子元素会溢出,BFC能解决该问题。水平方向不会溢出,垂直方向有可能会溢出。

 View Code

触发BFC时:

g)、相邻的浮动元素,left属性最前面的元素,排在最左边

从e就可以看出效果,这里不举例。

h)、相邻的浮动元素,right属性最前面的元素,排在最右边

排列在最左边的向右浮动时出现在最右边,示例如下:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>float</title>
        <style type="text/css">
            div{
                 100px;
                height: 100px;
                background: lightgreen;
                float: right;
                margin: 5px;
            }
        </style>
    </head>
    <body>
        <div id="div1">div1左
        </div>
        <div id="div2">div2中
        </div>
        <div id="div3">div3右
        </div>
    </body>
</html>
复制代码

运行效果:

i)、包含块不会计算浮动元素的高宽

示例代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>float</title>
        <style type="text/css">
            .cls1 {
                 100px;
                height: 100px;
                background: lightgreen;
                float: left;
                margin: 5px;
            }
            #div0{
                 330px;
                padding: 5px;
                border: 5px solid lightblue;
            }
        </style>
    </head>
    <body>
        <div id="div0">
            <div id="div1" class="cls1">div1
            </div>
            <div id="div2" class="cls1">div2
            </div>
            <div id="div3" class="cls1">div3
            </div>
        </div>
    </body>
</html>

运行结果:

试试这个代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>float</title>
        <style type="text/css">
            .cls1 {
                 100px;
                height: 100px;
                background: lightgreen;
                float: left;
                margin: 5px;
            }
            #div0{
                 330px;
                padding: 5px;
                border: 5px solid lightblue;
            overflow: hidden;
            }
        </style>
    </head>
    <body>
        <div id="div0">
            <div id="div1" class="cls1">div1
            </div>
            <div id="div2" class="cls1">div2
            </div>
            <div id="div3" class="cls1">div3
            </div>
        </div>
        <p>萨芬大反倒是</p>
    </body>
</html>

  

j)、浮动元素与非浮动元素会重叠,挤出块中的内容(看清楚啦,是挤出块中的内容)

示例代码:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>float</title>
        <style type="text/css">
            #div1 {
                 100px;
                height: 100px;
                background: lightblue;
                float: left;
            }
            #div2 {
                 200px;
                height: 200px;
                background: lightgreen;
            }
        </style>
    </head>
    <body>
        <div id="div1">div1
        </div>
        <div id="div2">div2
        </div>
    </body>

</html>
复制代码

运行结果:

当div1从float时从标准流中脱离开了,div2在标准流中,可以形象的认为在div2这个队列前没有元素了所以div2要向前靠,脱离标准流的元素的z方向排列时比标准流中的元素排列要靠前一些,但div2的内容被div1占用的空间挤出。

3.3、清除浮动

该属性的值指出了不允许有浮动对象的边。
clear:none | left | right | both
适用于:块级元素
取值:
none: 允许两边都可以有浮动对象 
both: 不允许有浮动对象 
left: 不允许左边有浮动对象 
right: 不允许右边有浮动对象

3.3.1、清除外部浮动

需要注意的是clear是用于控制元素本身的,不能影响别的元素,示例如下:

 View Code

运行结果:

示例中div1的清除浮动并没有效果,因为他没有办法影响div2,如果设置div2清除浮动,则元素本身会向下一行,示例代码如下:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>清除浮动</title>
        <style type="text/css">
            #div1 {
                 100px;
                height: 100px;
                background: lightblue;
                float: left;
            }
            #div2 {
                 200px;
                height: 200px;
                background: lightgreen;
                float: left;
                clear: both;  /*div2的右边与左边都不能出现浮动元素*/
            }
        </style>
    </head>
    <body>
        <div id="div1">div1</div>
        <div id="div2">div2</div>
    </body>

</html>
复制代码

 运行结果如下:

 

如果div2后面还有一个div3也将会出现前面一样的情况:

 View Code

 练习:

3.3.2、清除内部浮动

当一个包含块内部有浮动元素时,外部块不会计算浮动块的高度与宽度,为了让内部的浮动元素撑开包含块,需要还原高度,暂且称为清除内部浮动。

方法1:BFC

 View Code

方法2:增加一个空的div,清除浮动

 View Code

运行结果同方法1,要解释该方法的原理可以参考上文中的第j点。

较为通用且兼容的清除浮动写法:

复制代码
            .clearfix {
                *zoom: 1;/*在旧版本的IE浏览器缩放大小,触发haslayout(类似BFC)*/
            }
            .clearfix:after {  /*伪元素,在应用该元素后添加一个伪元素*/
                content: "";  /*内容为空*/
                display: table;   /*BFC,清除内部浮动*/
                clear: both; /*清除外部浮动*/
            }
复制代码

四、多种居中办法

4.1、块标签自身水平居中

当一个有宽度的块标签设置margin:0 auto时将实现自身的水平居中,示例脚本如下:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>float</title>
        <style type="text/css">
            #container {
                margin: 0 auto;
                 90%;
                background: lightblue;
                height: 200px;
            }
        </style>
    </head>
    <body>
        <div id="container">
        </div>
    </body>
</html>
复制代码

 运行结果:

4.2、块标签内对齐

text-align:start | end | left | right | center | justify | match-parent | justify-all
默认值:start
适用于:块标签
left: 内容左对齐。 
center: 内容居中对齐。 
right: 内容右对齐。 
justify: 内容两端对齐,但对于强制打断的行(被打断的这一行)及最后一行(包括仅有一行文本的情况,因为它既是第一行也是最后一行)不做处理。(CSS3) 
start: 内容对齐开始边界。(CSS3) 
end: 内容对齐结束边界。(CSS3) 
match-parent: 这个值和 inherit 表现一致,只是该值继承的 start 或 end 关键字是针对父母的 <' direction '> 值并计算的,计算值可以是 left 和 right 。(CSS3) 
justify-all: 效果等同于 justify,但还会让最后一行也两端对齐。(CSS3)

示例代码:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>float</title>
        <style type="text/css">
            #container {
                margin: 0 auto;
                 90%;
                background: lightblue;
                height: 200px;
                text-align: center;
            }
            #div1{
                 100px;
                height: 100px;
                background: lightgreen;
            }
        </style>
    </head>
    <body>
        <div id="container">
            <div id="div1">div1</div>
            Hello Center
        </div>
    </body>
</html> 
复制代码

运行结果:

这种对齐方式只针对块标签内的行内标签(inline box)与行内块标签(inline block)有将,对块标签是无效的因为块标签默认总是占整行。如果将示例中div1的显示方式修改为行内块标签(display: inline-block;),则效果如下所示:

 

在布局中经常会需要垂直居中,但没有像水平居中那么容易,这里总结出5种办法:

4.3、垂直居中方法一

当一个设置了定位的元素所有的偏移为0且margin为auto时将水平,垂直都居中,且父元素自身的高度可动态变化。

示例代码:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>居中</title>
        <style type="text/css">
            * {
                margin: 0;
                padding: 0;
            }
            
            html,
            body {
                height: 100%;
            }
            
            #div0 {
                 80%;
                height: 90%;
                border: 3px solid lightblue;
                margin: 0 auto;
                position: relative;
            }
            
            #div1 {
                 200px;
                height: 150px;
                background: lightgreen;
                position: absolute;
                /*居中开始*/
                top: 0;
                right: 0;
                bottom: 0;
                left: 0;
                margin: auto;
                /*居中结束*/
            }
        </style>
    </head>

    <body>
        <div id="div0">
            <div id="div1">

            </div>
        </div>
    </body>

</html>
复制代码

运行结果:

个人认为box偏移上下左右都为0,这时候它就不知所措了,只好待在中间。

4.4、垂直居中方法二

如果是单行文本,行高如块的高度一样时将居中,只一行,行高和元素一样高,居中。

line-height: 600px;
height: 600px;

只可以是文字等一些行内标签,图片不行,示例代码如下:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>居中</title>
        <style type="text/css">
            #div0 {
                background: lightblue;
                height: 80px;
                /*line-height:40px;*/
                font:20px/80px "microsoft yahei";
            }
        </style>
    </head>
    <body>
        <div id="div0">
            如果是单行文本,行高如块的高度一样时将居中,只一行,行高和元素一样高,居中
        </div>
    </body>

</html>
复制代码

运行结果:

 

4.5、垂直居中方法三

让元素相对父元素定位,偏移左50%,上50%,把自身向左移半个宽度,向上移半个高度,同时完成了水平与垂直方向的居中

示例代码:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>居中</title>
        <style type="text/css">
            #div0 {
                 80%;
                height: 500px;
                background: lightblue;
                position: relative;
                margin: 0 auto;
            }
            
            #div1{
                 200px;
                height: 150px;
                background: lightcoral;
                position: absolute;
                left: 50%;
                top:50%;
                margin-top: -75px;
                margin-left: -100px;
            }
        </style>
    </head>
    <body>
        <div id="div0">
            <div id="div1">
            </div>
        </div>
    </body>

</html>
复制代码

运行效果:

4.6、垂直居中方法四

在CSS有一个属性应该欺骗过很多开发者,一直认为使用了他就可以垂直居中了,但不行,这个属性就是:

语法:vertical-align:baseline | sub | super | top | text-top | middle | bottom | text-bottom | <percentage> | <length>

默认值:baseline

作用:设置或检索内联元素在行框内的垂直对其方式
适用于:内联级与 table-cell 元素
baseline: 把当前盒的基线与父级盒的基线对齐。如果该盒没有基线,就将底部外边距的边界和父级的基线对齐 
sub: 把当前盒的基线降低到合适的位置作为父级盒的下标(该值不影响该元素文本的字体大小) 
super: 把当前盒的基线提升到合适的位置作为父级盒的上标(该值不影响该元素文本的字体大小) 
text-top: 把当前盒的top和父级的内容区的top对齐 
text-bottom: 把当前盒的bottom和父级的内容区的bottom对齐 
middle: 把当前盒的垂直中心和父级盒的基线加上父级的半x-height对齐 
top: 把当前盒的top与行盒的top对齐 
bottom: 把当前盒的bottom与行盒的bottom对齐 
<percentage>: 把当前盒提升(正值)或者降低(负值)这个距离,百分比相对line-height计算。当值为0%时等同于baseline。 
<length>: 把当前盒提升(正值)或者降低(负值)这个距离。当值为0时等同于baseline。(CSS2) 说明:
设置或检索内联元素在行框内的垂直对其方式。 
对应的脚本特性为verticalAlign。

不能实现对齐的主要原因是:vertical-align这个属性的特点,它是相对兄弟级行高(line-height)来定位

 

示例代码:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>居中</title>
        <style type="text/css">
            #div0 {
                 80%;
                height: 500px;
                background: lightblue;
                position: relative;
                margin: 0 auto;
                text-align: center;
            }
            #img1{
                vertical-align: middle;
            }
            #span1{
                line-height: 500px;
            }
        </style>
    </head>
    <body>
        <div id="div0">
            <img src="img/cp.png" id="img1"/><span id="span1"></span>
        </div>
    </body>
</html>
复制代码

运行效果:

其实此处只设置父元素的行高与高度一样时也能达到上面的效果,示例代码如下:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>居中</title>
        <style type="text/css">
            #div0 {
                 80%;
                height: 500px;
                background: lightblue;
                position: relative;
                margin: 0 auto;
                text-align: center;
                line-height: 500px;
            }
            
            #img1 {
                vertical-align: middle;
            }
        </style>
    </head>

    <body>
        <div id="div0">
            <img src="img/cp.png" id="img1" />
        </div>
    </body>

</html>
复制代码

在IE8与Google浏览器中运行效果:

4.7、垂直居中方法五

4.7.1、使用div构造一个表格

示例代码:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .divTable {
                display: table;
                50%;
            }
            
            .divTr {
                display: table-row;
            }
            .divTd {
                display: table-cell;
            }
            div{
                border:1px solid blue;
            }
        </style>
    </head>

    <body>
        <div class="divTable">
            <div class="divTr">
                <div class="divTd">td11</div>
                <div class="divTd">td12</div>
            </div>
            <div class="divTr">
                <div class="divTd">td21</div>
                <div class="divTd">td22</div>
            </div>
        </div>
    </body>
</html>
复制代码

运行结果:

4.7.2、使用表格特性居中

示例代码:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>居中</title>
        <style type="text/css">
            body,
            html {
                margin: 0;
                padding: 0;
                height: 100%;
            }
            
            #div0 {
                 80%;
                height: 50%;
                background: lightblue;
                margin: 0 auto;
                display: table;  /*类似让div1为一个table*/
            }
            
            #div1{
                display: table-cell;  /*类似table中的td*/
                vertical-align: middle;   /*垂直居中*/
                text-align: center;  /*水平居中*/
            }
        </style>
    </head>

    <body>
        <div id="div0">
            <div id="div1">
                <img src="img/cp.png" id="img1" height="200" />
            </div>
        </div>
    </body>

</html>
复制代码

运行结果:

4.8、垂直居中方法六

在某些时候需要将小图片与文字对象,可以使用对齐的属性absmiddle(绝对居中),示例如下:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            #div1{
                border: 2px solid lightblue;
            }
        </style>
    </head>
    <body>
        <div class="div1">
            <img src="img/018080.png" align="absmiddle"/>电视机
        </div>
    </body>
</html>
复制代码

运行结果:

在IE8与chrome浏览器下的效果一样。

4.9、垂直居中方法七

方法与4.5非常类似,但是4.5要求知道居中元素自身的高度与宽度,这样会有一定的局限,CSS3中可以使用transform移动元素自身的宽度与高度,示例代码如下:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>居中</title>
        <style type="text/css">
            body,
            html {
                margin: 0;
                padding: 0;
                height: 100%;
            }
            
            #div0 {
                 80%;
                height: 70%;
                background: lightblue;
                margin: 0 auto;
                position: relative;
            }
            
            #img1 {
                position: absolute;
                top: 50%;
                left: 50%;
                transform:translate(-50%,-50%);
            }
        </style>
    </head>

    <body>
        <div id="div0">
                <img src="img/cp.png" id="img1"/>
        </div>
    </body>

</html>
复制代码

运行结果:

transform用于设置或检索对象的转换,参数translate()指定对象的2D translation(2D平移)。第一个参数对应X轴,第二个参数对应Y轴。如果第二个参数未提供,则默认值为0

五、示例下载

github:https://github.com/zhangguo5/CSS3_3

一、负边距与浮动布局

1.1、负边距

所谓的负边距就是margin取负值的情况,如margin:-100px,margin:-100%。当一个元素与另一个元素margin取负值时将拉近距离。常见的功能如下:

1.1.1、向上移动

当多个元素同时从标准流中脱离开来时,如果前一个元素的宽度为100%宽度,后面的元素通过负边距可以实现上移。当负的边距超过自身的宽度将上移,只要没有超过自身宽度就不会上移,示例如下:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>负边距</title>
        <style type="text/css">
            * {
                margin: 0;
                padding: 0;
            }
            
            #div1 {
                height: 100px;
                background: lightblue;
                 100%;
                float: left;
            }
            
            #div2 {
                height: 100px;
                background: lightgreen;
                 30%;
                float: left;
                margin-left: -100%;
            }
        </style>
    </head>

    <body>
        <div id="div1">div1
        </div>
        <div id="div2">div2
        </div>
    </body>

</html>
复制代码

margin-left:-29%时运行效果:

margin-left:-30%时运行效果:

margin-left:-100%时运行效果:

1.1.2、去除列表右边框

开发中常需要在页面中展示一些列表,如商品展示列表等,如果我们要实现如下布局:

 

示例代码:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>负边距</title>
        <style type="text/css">
            * {
                margin: 0;
                padding: 0;
            }
            
            #div1 {
                 800px;
                margin: 0 auto;
                border: 3px solid lightblue;
                overflow: hidden;
                margin-top: 10px;
            }
            
            .box {
                 180px;
                height: 180px;
                margin: 0 20px 20px 0;
                background: lightgreen;
                float: left;
            }
        </style>
    </head>

    <body>
        <div id="div1">
            <div class="box">
            </div>
            <div class="box">
            </div>
            <div class="box">
            </div>
            <div class="box">
            </div>
            <div class="box">
            </div>
            <div class="box">
            </div>
            <div class="box">
            </div>
            <div class="box">
            </div>
        </div>
    </body>

</html>
复制代码

运行后的结果:

但是上面的效果中右边多出了20px的距离,底下多出20px空白,解决方法如下:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>负边距</title>
        <style type="text/css">
            * {
                margin: 0;
                padding: 0;
            }
            #div1 {
                 780px;
                height: 380px;
                margin: 0 auto;
                border: 3px solid lightblue;
                overflow: hidden;
                margin-top: 10px;
            }
            .box {
                 180px;
                height: 180px;
                margin: 0 20px 20px 0;
                background: lightgreen;
                float: left;
            }
            #div2{
                margin-right: -20px;
            }
        </style>
    </head>
    <body>
        <div id="div1">
            <div id="div2">
                <div class="box">
                </div>
                <div class="box">
                </div>
                <div class="box">
                </div>
                <div class="box">
                </div>
                <div class="box">
                </div>
                <div class="box">
                </div>
                <div class="box">
                </div>
                <div class="box">
                </div>
            </div>
        </div>
    </body>
</html>
复制代码

方法是使用了边距折叠,可以在前面的文章中查看到细节,基本原理如下图所示:

1.1.3、负边距+定位,实现水平垂直居中

具体请参考《CSS3与页面布局学习总结(三)——BFC、定位、浮动、7种垂直居中方法》

1.1.4、去除列表最后一个li元素的border-bottom

方法一:

 View Code

方法二:

使用CSS3中的新增加选择器,选择最后一个li,不使用类样式,好处是当li的个数不确定时更加方便。

如果li的border-bottom颜色与ul的border颜色是一样的时候,在视觉上是被隐藏了。如果其颜色不一致的时候还是有问题,给ul写个overflow:hidden;就可以解决这个问题。

练习:

1.2、双飞翼布局

经典三列布局,也叫做圣杯布局【Holy Grail of Layouts】是Kevin Cornell在2006年提出的一个布局模型概念,在国内最早是由淘宝UED的工程师传播开来,在中国也有叫法是双飞翼布局,它的布局要求有几点:

1、三列布局,中间宽度自适应,两边定宽; 
2、中间栏要在浏览器中优先展示渲染; 
3、允许任意列的高度最高;
4、要求只用一个额外的DIV标签; 
5、要求用最简单的CSS、最少的HACK语句;

在不增加额外标签的情况下,圣杯布局已经非常完美,圣杯布局使用了相对定位,以后布局是有局限性的,而且宽度控制要改的地方也多。在淘宝UED(User Experience Design)探讨下,增加多一个div就可以不用相对布局了,只用到了浮动和负边距,这就是我们所说的双飞翼布局,实现的代码如下:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>双飞翼</title>
        <style type="text/css">
            * {
                margin: 0;
                padding: 0;
            }
            
            body,
            html {
                height: 100%;
                font: 20px/40px "microsoft yahei";
                color: white;
            }
            
            #container {
                 90%;
                margin: 0 auto;
                height: 100%;
            }
            
            #header,
            #footer {
                height: 12.5%;
                background: deepskyblue;
            }
            
            #main {
                height: 75%;
            }
            
            #center,
            #left,
            #right {
                height: 100%;
                float: left;
            }
            
            #center {
                 100%;
                background: lightgreen;
            }
            
            #right {
                background: lightblue;
                 20%;
                margin-left: -20%;
            }
            
            #left {
                background: lightcoral;
                 20%;
                margin-left: -100%;
            }
            
            #main-inner {
                padding-left: 20%;
            }
        </style>
    </head>
    <body>
        <div id="container">
            <div id="header">
                header
            </div>
            <div id="main">
                <div id="center">
                    <div id="main-inner">
                        center
                    </div>
                </div>
                <div id="left">
                    left
                </div>
                <div id="right">
                    right
                </div>
            </div>
            <div id="footer">
                footer
            </div>
        </div>
    </body>
</html>
复制代码

运行效果:

示例中增加一个main-inner的目的是因为当left上移时与center重叠了,left覆盖了center,通过main-inner的padding将left占用的位置空出。

1.3、多栏布局

1.3.1、栅格系统

栏栅格系统就是利用浮动实现的多栏布局,在bootstrap中用的非常多,这里以一个980像素的宽实现4列的栅格系统,示例代码如下:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>栅格系统</title>
        <style type="text/css">
            * {
                padding: 0;
                margin: 0;
            }
            
            html,
            body {
                height: 100%;
            }
            
            #container {
                 980px;
                margin: 0 auto;
                height: 10%;
            }
            
            #container div {
                height: 100%;
            }
            
            .col25 {
                 25%;
                background: lightgreen;
                float: left;
            }
            
            .col50 {
                 50%;
                background: lightblue;
                float: left;
            }
            
            .col75 {
                 75%;
                background: lightcoral;
                float: left;
            }
        </style>
    </head>

    <body>
        <div id="container">
            <div class="col50">
                A
            </div>
            <div class="col50">
                B
            </div>
            <div class="col25">
                C
            </div>
        </div>
    </body>

</html>
复制代码

运行结果:

同样的原理可以轻易扩展到8列,10列,16列的栅格系统。

1.3.2、多列布局

栅格系统并没有真正实现分栏效果(如word中的分栏),CSS3为了满足这个要求增加了多列布局模块,如果需要实现多列布局模块先看看这几个CSS3属性:

column-count:<integer> | auto
功能:设置或检索对象的列数 
适用于:除table外的非替换块级元素, table cells, inline-block元素
<integer>: 用整数值来定义列数。不允许负值 
auto: 根据 <' column-width '> 自定分配宽度

column-gap:<length> | normal
功能:设置或检索对象的列与列之间的间隙 
适用于:定义了多列的元素
计算值:绝对长度值或者normal

column-rule:<' column-rule-width '> || <' column-rule-style '> || <' column-rule-color '>
功能:设置或检索对象的列与列之间的边框。与border属性类似。 
适用于:定义了多列的元素

columns:<' column-width '> || <' column-count '>
功能:设置或检索对象的列数和每列的宽度
适用于:除table外的非替换块级元素, table cells, inline-block元素
<' column-width '>: 设置或检索对象每列的宽度 
<' column-count '>: 设置或检索对象的列数

示例代码:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>多列布局</title>
        <style type="text/css">
            #div1{
                column-count: 3;  /*分3栏*/
                column-gap: 40px;  /*栏间距*/
                column-rule: 2px solid lightgreen;  /*栏间分隔线,与border设置类似*/
                line-height: 26px;
                font-size: 14px;
                height: 500px;
                background: lightcyan;
            }
        </style>
    </head>
    <body>
        <div id="div1">
            CSS即层叠样式表(Cascading StyleSheet)。 在网页制作时采用层叠样式表技术,可以有效地对页面的布局、字体、颜色、背景和其它效果实现更加精确的控制。 只要对相应的代码做一些简单的修改,就可以改变同一页面的不同部分,或者页数不同的网页的外观和格式。CSS3是CSS技术的升级版本,CSS3语言开发是朝着模块化发展的。以前的规范作为一个模块实在是太庞大而且比较复杂,所以,把它分解为一些小的模块,更多新的模块也被加入进来。这些模块包括: 盒子模型、列表模块、超链接方式 、语言模块 、背景和边框 、文字特效 、多栏布局等。CSS即层叠样式表(Cascading StyleSheet)。 在网页制作时采用层叠样式表技术,可以有效地对页面的布局、字体、颜色、背景和其它效果实现更加精确的控制。 只要对相应的代码做一些简单的修改,就可以改变同一页面的不同部分,或者页数不同的网页的外观和格式。CSS3是CSS技术的升级版本,CSS3语言开发是朝着模块化发展的。以前的规范作为一个模块实在是太庞大而且比较复杂,所以,把它分解为一些小的模块,更多新的模块也被加入进来。这些模块包括: 盒子模型、列表模块、超链接方式 、语言模块 、背景和边框 、文字特效 、多栏布局等。
        </div>
    </body>
</html>
复制代码

运行结果:

二、弹性布局(Flexbox)

假设在项目中有一个这样的需求:同一行有3个菜单,每个菜单占1/3的宽度,怎么实现?

可能你会这样实现:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>flex</title>
        <style type="text/css">
            * {
                padding: 0;
                margin: 0;
                list-style: none;
            }
            
            html,
            body {
                height: 100%;
            }
            
            #menu {
                 980px;
                margin: 0 auto;
            }
            #menu li{
                 33.3%;
                float: left;
            }
        </style>
    </head>

    <body>
        <ul id="menu">
            <li><a href="#" class="item">公司简介</a></li>
            <li><a href="#" class="item">商品展示</a></li>
            <li><a href="#" class="item">后台管理</a></li>
        </ul>
    </body>

</html>
复制代码

结果:

上面的办法有明显的不足就是可扩展性太差,因为如果再添加一项就会有一个菜单项会换行,解决方法是:CSS3中提供了强大的弹性盒布局。示例:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>flex</title>
        <style type="text/css">
            * {
                padding: 0;
                margin: 0;
                list-style: none;
            }
            
            html,
            body {
                height: 100%;
            }
            
            #menu {
                 980px;
                margin: 0 auto;
                display: flex;  /*当前块为弹性盒*/
            }
            #menu li{
                flex: auto;  /*弹性盒中的单项*/
                float: left;
            }
            #menu li a{
                display:block;
                height: 26px;
                line-height: 26px;
                border:1px solid cornflowerblue;
                margin-right: 2px;
                text-decoration: none;
                text-align: center;
            }
        </style>
    </head>

    <body>
        <ul id="menu">
            <li><a href="#" class="item">公司简介</a></li>
            <li><a href="#" class="item">商品展示</a></li>
            <li><a href="#" class="item">后台管理</a></li>
            <li><a href="#" class="item">企业文化</a></li>
            <li><a href="#" class="item">在线咨询</a></li>
        </ul>
    </body>

</html>
复制代码

运行结果:

display属性值flex: 将对象作为弹性伸缩盒显示

flex:none | <flex-grow> <flex-shrink > || <flex-basis>
功能:设置或检索弹性盒模型对象的子元素如何分配空间
适用于:flex子项
none: none关键字的计算值为: 0 0 auto 
<flex-grow>: 用来指定扩展比率,即剩余空间是正值时此「flex子项」相对于「flex容器」里其他「flex子项」能分配到空间比例。
在「flex」属性中该值如果被省略则默认为「1」 
<flex-shrink>: 用来指定收缩比率,即剩余空间是负值时此「flex子项」相对于「flex容器」里其他「flex子项」能收缩的空间比例。
在收缩的时候收缩比率会以伸缩基准值加权
在「flex」属性中该值如果被省略则默认为「1」 
<flex-basis>: 用来指定伸缩基准值,即在根据伸缩比率计算出剩余空间的分布之前,「flex子项」长度的起始数值。
在「flex」属性中该值如果被省略则默认为「0%」
在「flex」属性中该值如果被指定为「auto」,则伸缩基准值的计算值是自身的 <width> 设置,如果自身的宽度没有定义,则长度取决于内容。

示例:如下情况每个元素的计算宽是多少

复制代码
<ul class="flex">
 <li>a</li>
 <li>b</li>
 <li>c</li>
</ul>
复制代码
.flex{display:flex;800px;margin:0;padding:0;list-style:none;}
.flex :nth-child(1){flex:1 1 300px;}
.flex :nth-child(2){flex:2 2 200px;}
.flex :nth-child(3){flex:3 3 400px;}

本例定义了父容器宽(即主轴宽)为800px,由于子元素设置了伸缩基准值flex-basis,相加300+200+400=900,那么子元素将会溢出900-800=100px;
由于同时设置了收缩因子,所以加权综合可得300*1+200*2+400*3=1900px;
于是我们可以计算a,b,c将被移除的溢出量是多少:
a被移除溢出量:(300*1/1900)*100,即约等于16px
b被移除溢出量:(200*2/1900)*100,即约等于21px
c被移除溢出量:(400*3/1900)*100,即约等于63px
最后a,b,c的实际宽度分别为:300-16=284px, 200-21=179px, 400-63=337px

可见算法比较麻烦,简单的做法如下:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>flex</title>
        <style type="text/css">
            * {
                padding: 0;
                margin: 0;
                list-style: none;
            }
            html,
            body {
                height: 100%;
            }
            #menu {
                 980px;
                margin: 0 auto;
                display: flex;
                /*当前块为弹性盒*/
            }
            #menu li {
                float: left;
            }
            #menu li a {
                display: block;
                height: 26px;
                line-height: 26px;
                border: 1px solid cornflowerblue;
                margin-right: 2px;
                text-decoration: none;
                text-align: center;
            }
            .a {
                flex: 1;
            }
            .b {
                flex: 2;
            }
            .c {
                flex: 3;
            }
        </style>
    </head>
    <body>
        <ul id="menu">
            <li class="a">
                <a href="#" class="item">公司简介</a>
            </li>
            <li class="b">
                <a href="#" class="item">商品展示</a>
            </li>
            <li class="c">
                <a href="#" class="item">后台管理</a>
            </li>
        </ul>
    </body>
</html>
复制代码

运行结果:

Flex容器可以设置属性flex-flow,取值为row,row-reverse,column,column-reverse四种值
row:显示在一行中

row-reverse:显示在一行中,反转

column:显示在一列中

column-reverse:显示在一列中 反转

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>flex</title>
        <style type="text/css">
            * {
                padding: 0;
                margin: 0;
                list-style: none;
            }
            html,
            body {
                height: 100%;
                padding-top :20px;
            }
            #menu {
                 980px;
                margin: 0 auto;
                display: flex;
                /*当前块为弹性盒*/
                flex-flow: row-reverse;
                /*子项在一行中显示,反转*/
            }
            #menu li {
                flex: auto;
            }
            #menu li a {
                display: block;
                height: 26px;
                line-height: 26px;
                border: 1px solid cornflowerblue;
                margin-right: 2px;
                text-decoration: none;
                text-align: center;
            }
        </style>
    </head>
    <body>
        <ul id="menu">
            <li class="a">
                <a href="#" class="item">A公司简介</a>
            </li>
            <li class="b">
                <a href="#" class="item">B商品展示</a>
            </li>
            <li class="c">
                <a href="#" class="item">C后台管理</a>
            </li>
        </ul>
    </body>
</html>
复制代码

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>flex</title>
        <style type="text/css">
            * {
                padding: 0;
                margin: 0;
                list-style: none;
            }
            html,
            body {
                height: 100%;
                padding-top :20px;
            }
            #menu {
                margin: 0 auto;
                display: flex;
                /*当前块为弹性盒*/
                flex-flow: column-reverse;
                height: 200px;
                overflow: hidden;
            }
            #menu li{
                border: 1px solid cornflowerblue;
                margin-bottom: 5px;
                text-align: center;
            }
            #menu li a {
                text-decoration: none;
                vertical-align: middle;
            }
            .a{
                flex: 1;
            }
            .b{
                flex: 2;
            }
            .c{
                flex: 3;
            }
        </style>
    </head>
    <body>
        <ul id="menu">
            <li class="a">
                <a href="#" class="item">A公司简介</a>
            </li>
            <li class="b">
                <a href="#" class="item">B商品展示</a>
            </li>
            <li class="c">
                <a href="#" class="item">C后台管理</a>
            </li>
        </ul>
    </body>
</html>
复制代码

三、流式布局(Fluid)

固定布局和流式布局在网页设计中最常用的两种布局方式。固定布局能呈现网页的原始设计效果,流式布局则不受窗口宽度影响,流式布局使用百分比宽度来限定布局元素,这样可以根据客户端分辨率的大小来进行合理的显示。

固定布局效果:

流式布局效果:

利用前面的知识点可以实现这两种布局,这里就不去实现了

三、瀑布流布局

瀑布流布局是流式布局的一种。是当下比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。最早采用此布局的网站是Pinterest,逐渐在国内流行开来。

3.1、常见瀑布流布局网站

鼻祖:Pinterest
通用类:豆瓣市集,花瓣网,我喜欢,读图知天下
美女图片:图丽网
时尚资讯类:看潮网
时尚购物类:蘑菇街,美丽说,人人逛街,卡当网
品牌推广类:凡客达人
家居o2o类:新巢网小猫家
微博社交类: 都爱看
搞笑图片类:道趣儿
艺术收藏类:微艺术
潮流图文分享:荷都分享网

3.2、特点

优点

1、有效的降低了界面复杂度,节省了空间:我们不再需要臃肿复杂的页码导航链接或按钮了。

2、对触屏设备来说,交互方式更符合直觉:在移动应用的交互环境当中,通过向上滑动进行滚屏的操作已经成为最基本的用户习惯,而且所需要的操作精准程度远远低于点击链接或按钮。

3、更高的参与度:以上两点所带来的交互便捷性可以使用户将注意力更多的集中在内容而不是操作上,从而让他们更乐于沉浸在探索与浏览当中。

缺点

1. 有限的用例:
无限滚动的方式只适用于某些特定类型产品当中一部分特定类型的内容。
例如,在电商网站当中,用户时常需要在商品列表与详情页面之间切换,这种情况下,传统的、带有页码导航的方式可以帮助用户更稳妥和准确的回到某个特定的列表页面当中。

2. 额外的复杂度:
那些用来打造无限滚动的JS库虽然都自称很容易使用,但你总会需要在自己的产品中进行不同程度的定制化处理,以满足你们自己的需求;另外这些JS库在浏览器和设备兼容性等方面的表现也参差不齐,你必须做好充分的测试与调整工作。

3. 再见了,页脚:
如果使用了比较典型的无限滚动加载模式,这就意味着你可以和页脚说拜拜了。
最好考虑一下页脚对于你的网站,特别是用户的重要性;如果其中确实有比较重要的内容或链接,那么最好换一种更传统和稳妥的方式。
千万不要耍弄你的用户,当他们一次次的浏览到页面底部,看到页脚,却因为自动加载的内容突然出现而无论如何都无法点击页脚中的链接时,他们会变的越发愤怒。

5. SEO:

集中在一页当中动态加载数据,与一页一页的输出相比,究竟那种方式更利于SEO,这是你必须考虑的问题。对于某些以类型网站来说,在这方面进行冒险是很不划算的。

6. 关于页面数量的印象:
其实站在用户的角度来看,这一点并非负面;不过,如果对于你的网站来说,通过更多的内容页面展示更多的相关信息(包括广告)是很重要的策略,那么单页无限滚动的方式对你并不适用。

3.3、masonry实现瀑布流布局

masonry是一个响应式网格布局库(非jQuery)。(Cascading grid layout library)

如果使用CSS+JavaScript当然可以实现瀑布流布局,但相对麻烦,masonry是一个javascript插件,通过该插件可以轻松实现瀑布流布局,和CSS中float的效果不太一样的地方在 于,float先水平排列,然后再垂直排列,使用Masonry则垂直排列元素,然后将下一个元素放置到网格中的下一个开发区域。这种效果可以最小化处理 不同高度的元素在垂直方向的间隙。

官网:http://masonry.desandro.com/

源码:https://github.com/desandro/masonry

3.3.1、下载并引用masonry

可以去官网或github下载“masonry.pkgd.min.js”,将下载到的插件添加到项目中,并在页面中添加引用,如下所示:

<script src="js/masonry/masonry.pkgd.min.js" type="text/javascript" charset="utf-8"></script>

CDN:

<script src="https://unpkg.com/masonry-layout@4.1/dist/masonry.pkgd.js"></script>
<!-- or -->
<script src="https://unpkg.com/masonry-layout@4.1/dist/masonry.pkgd.min.js"></script>

3.3.2、准备内容

在页面中使用HTML+CSS准备需要使用瀑布流显示的内容,如下所示:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>瀑布流布局</title>
        <style type="text/css">
            #grid {
                 1000px;
                margin: 0 auto;
            }
            
            .grid-item {
                 200px;
                float: left;
            }
            
            .a {
                background: lightblue;
                height: 200px;
            }
            
            .b {
                background: lightcoral;
                height: 300px;
            }
            
            .c {
                background: lightgreen;
                height: 500px;
            }
            
            .d {
                background: lightsalmon;
                height: 350px;
            }
            
            .e {
                background: lightseagreen;
                height: 150px;
            }
        </style>
    </head>

    <body>
        <div id="grid">
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
        </div>
        <script src="js/masonry/masonry.pkgd.min.js" type="text/javascript" charset="utf-8"></script>
    </body>

</html>
复制代码

没有使用瀑布流布局时的效果:

3.3.3、初始化插件

使用jQuery:

复制代码
$('.grid').masonry({
  // options...
  itemSelector: '.grid-item',
  columnWidth: 200
});
复制代码

原生JavaScript:

复制代码
// init with element
var grid = document.querySelector('.grid');
var msnry = new Masonry( grid, {
  // options...
  itemSelector: '.grid-item',
  columnWidth: 200
});
复制代码

使用HTML属性:

复制代码
<div class="grid" data-masonry='{ "itemSelector": ".grid-item", "columnWidth": 200 }'>
  <div class="grid-item"></div>
  <div class="grid-item"></div>
  ...
</div>
复制代码

常用属性如下:

复制代码
itemSelector : '.item',//瀑布流布局中的单项选择器
columnWidth : 240 ,//一列的宽度
isAnimated:true,//使用jquery的布局变化,是否启用动画
animationOptions:{
//jquery animate属性 渐变效果 Object { queue: false, duration: 500 }
},
gutterWidth:0,//列的间隙 Integer
isFitWidth:true,//是否适应宽度 Boolean
isResizableL:true,//是否可调整大小 Boolean
isRTL:false,//是否使用从右到左的布局 Boolean
复制代码

初始化代码如下:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>瀑布流布局</title>
        <style type="text/css">
            #grid {
                 1000px;
                margin: 0 auto;
            }
            
            .grid-item {
                 200px;
                float: left;
            }
            
            .a {
                background: lightblue;
                height: 200px;
            }
            
            .b {
                background: lightcoral;
                height: 300px;
            }
            
            .c {
                background: lightgreen;
                height: 500px;
            }
            
            .d {
                background: lightsalmon;
                height: 350px;
            }
            
            .e {
                background: lightseagreen;
                height: 150px;
            }
        </style>
    </head>

    <body>
        <div id="grid">
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>

            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
            <div class="grid-item a">
            </div>
            <div class="grid-item b">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item e">
            </div>
            <div class="grid-item c">
            </div>
            <div class="grid-item d">
            </div>
            <div class="grid-item e">
            </div>
        </div>
        <script src="js/masonry/masonry.pkgd.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var msnry = new Masonry('#grid', {
                itemSelector: '.grid-item',
                columnWidth: 200
            });
        </script>
    </body>

</html>
复制代码

运行结果:

3.3.4、使用了图片的瀑布流

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>瀑布流布局</title>
        <style type="text/css">
            #grid {
                 1000px;
                margin: 0 auto;
            }
        </style>
    </head>

    <body>
        <div id="grid">
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(1).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(2).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(3).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(4).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(11).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(12).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(5).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(6).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(7).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(8).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(11).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(12).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(9).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(10).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(11).jpg" width="200" />
                </a>
            </div>
            <div class="grid-item">
                <a href="#">
                    <img src="img/h/h(12).jpg" width="200" />
                </a>
            </div>
        </div>
        <script src="js/masonry/masonry.pkgd.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            window.onload = function() {
                var msnry = new Masonry('#grid', {
                    itemSelector: '.grid-item',
                    columnWidth: 200
                });
            }
        </script>
    </body>

</html>
复制代码

运行结果:

注意:上面的示例中我们使用了window.onload事件,原因是如果图片没有加载完成就执行瀑布流布局会引起堆叠的问题,其实就是初始化是没有检测到图片的高度,window.onload在有许多图片的环境下会有性能问题,这里给大家介绍另一个组件。

3.4、imagesLoaded 图片加载

imagesLoaded 是一个用于来检测网页中的图片是否载入完成的 JavaScript 工具库。支持回调的获取图片加载的进度,还可以绑定自定义事件。可以结合 jQuery、RequireJS 使用。

官网:http://imagesloaded.desandro.com/

源码:https://github.com/desandro/imagesloaded

示例代码:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>imagesLoaded – 检测网页中的图片是否加载</title>
    </head>

    <body>
        <div id="div1">
            <img src="img/h/h(2).jpg" width="300" /><img src="img/h/h(1).jpg" width="300" />
        </div>
        <script src="js/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="js/imagesloaded-master/imagesloaded.pkgd.min.js" type="text/javascript" charset="utf-8"></script>
        <script>
            imagesLoaded(document.querySelector('#div1'), function(instance) {
                alert('所有的图片都加载完成了');
            });

            $('#div1').imagesLoaded()
                .always(function(instance) {
                    console.log('all images loaded');
                })
                .done(function(instance) {
                    console.log('all images successfully loaded');
                })
                .fail(function() {
                    console.log('all images loaded, at least one is broken');
                })
                .progress(function(instance, image) {
                    var result = image.isLoaded ? 'loaded' : 'broken';
                    console.log('image is ' + result + ' for ' + image.img.src);
                });
        </script>
    </body>

</html>
复制代码

运行结果:

3.5、Infinite Scroll 滚动分页

Infinite Scroll也是基于jQuery插件,是一个用于滚动分页的插件(当移动滚动条时将动态加载更多内容),有网友称这种效果为”无刷新无分页完美瀑布流”展现方式。

官网:http://infinite-scroll.com/

源码:https://github.com/infinite-scroll/infinite-scroll

常用属性:

复制代码
$('#masonny-div').infinitescroll({
    navSelector  : "#next",   // 页面分页元素(成功后会被隐藏)
    nextSelector : "#next a", // 需要点击的下一页链接,和2的html要对应
    itemSelector : ".item"  , // ajax回来之后,每一项的selecter
    animate      : true,      //加载完毕是否采用动态效果
    extraScrollPx: 100,       //向下滚动的像素,必须开启动态效果
    // debug     : true,      //调试的时候,可以打开
    bufferPx     : 5,         //提示语展现的时长,数字越大,展现时间越短
    loading: {
        finishedMsg: '没有更多内容了', //当加载失败,或者加载不出内容之后的提示语
        img:  'loading-new.gif',   //自定义loadding的动画图
        msgText : '正在加载中...',    //加载时的提示语
        },
    },
    function( newElements, opt ) {
       //成功后执行自定义的函数
       //如果需要对新内容进行加工,就在这里实现
    }
};
复制代码

属性与事件官网有详细的说明这里只列出来了部分,下面是官网列出的选择:

复制代码
$('.selector').infinitescroll({
  loading: {
    finished: undefined,
    finishedMsg: "<em>Congratulations, you've reached the end of the internet.</em>",
                img: null,
    msg: null,
    msgText: "<em>Loading the next set of posts...</em>",
    selector: null,
    speed: 'fast',
    start: undefined
  },
  state: {
    isDuringAjax: false,
    isInvalidPage: false,
    isDestroyed: false,
    isDone: false, // For when it goes all the way through the archive.
    isPaused: false,
    currPage: 1
  },
  behavior: undefined,
  binder: $(window), // used to cache the selector for the element that will be scrolling
  nextSelector: "div.navigation a:first",
  navSelector: "div.navigation",
  contentSelector: null, // rename to pageFragment
  extraScrollPx: 150,
  itemSelector: "div.post",
  animate: false,
  pathParse: undefined,
  dataType: 'html',
  appendCallback: true,
  bufferPx: 40,
  errorCallback: function () { },
  infid: 0, //Instance ID
  pixelsFromNavToBottom: undefined,
  path: undefined, // Can either be an array of URL parts (e.g. ["/page/", "/"]) or a function that accepts the page number and returns a URL
  maxPage:undefined // to manually control maximum page (when maxPage is undefined, maximum page limitation is not work)
});
复制代码

3.5.1、异步加载普通页面

p1.html页面:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .item {
                height: 200px;
            }
        </style>
    </head>
    <body>
        <h2>产品列表</h2>
        <div id="items">
            <p class="item">产品一</p>
            <p class="item">产品一</p>
            <p class="item">产品一</p>
            <p class="item">产品一</p>
            <p class="item">产品一</p>
            <p class="item">产品一</p>
        </div>
        <a href="p2.html" id="next">下一页</a>
        <script src="../js/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../js/infinite-scroll/jquery.infinitescroll.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            $('#items').infinitescroll({
                navSelector: "#next",  // 页面分页元素(成功后会被隐藏)
                nextSelector: "a#next",  // 需要点击的下一页链接,和2的html要对应
                itemSelector: ".item",  // ajax回来之后,每一项的selecter,比如每篇文章都有item这个class
                debug: true,  //是否调试
                dataType: 'html',  //数据类型
                maxPage: 3,  //最大页数
                path: function(index) {  //路径
                        return "p" + index + ".html";
                }
            }, function(newElements, data, url) {  //成功后的回调
                //console.log("路径:" + url);
                $(newElements).css('background-color', '#ffef00');
                // $(this).append(newElements);
            });
        </script>
    </body>

</html>
复制代码

p2.html页面:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>P2</title>
    </head>
    <body>
        <p class="item">产品二</p>
        <p class="item">产品二</p>
        <p class="item">产品二</p>
        <p class="item">产品二</p>
        <p class="item">产品二</p>
        <p class="item">产品二</p>
    </body>
</html>
复制代码

p3.html页面:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>P3</title>
    </head>
    <body>
        <p class="item">产品三</p>
        <p class="item">产品三</p>
        <p class="item">产品三</p>
        <p class="item">产品三</p>
        <p class="item">产品三</p>
        <p class="item">产品三</p>
    </body>
</html>
复制代码

运行效果:

3.5.2、异步加载json并解析

m1.html页面:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>相册</title>
        <style type="text/css">
            .item {
                float: left;
                min-height: 300px;
            }
        </style>
    </head>
    <body>
        <h2>相册</h2>
        <div id="items">
            <p class="item"><img src="../img/i/1.jpg" /></p>
            <p class="item"><img src="../img/i/2.jpg" /></p>
            <p class="item"><img src="../img/i/3.jpg" /></p>
            <p class="item"><img src="../img/i/4.jpg" /></p>
            <p class="item"><img src="../img/i/5.jpg" /></p>
            <p class="item"><img src="../img/i/6.jpg" /></p>
        </div>
        <a href="m2.json" id="next"></a>
        <script src="../js/jquery-1.11.3.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../js/infinite-scroll/jquery.infinitescroll.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            $('#items').infinitescroll({
                navSelector: "#next",
                nextSelector: "a#next",
                itemSelector: ".item",
                debug: true,
                dataType: 'json',
                maxPage: 3,
                appendCallback:false,
                path: function(index) {
                    return "m" + index + ".json";
                }
            }, function(data) {
                
                for(var i=0;i<data.length;i++){
                    $("<p class='item'><img src='../img/i/"+data[i]+".jpg' /></p>").appendTo("#items");
                }
                
            });
        </script>
    </body>
</html>
复制代码

m2.json数据:

[7,8,9,10,11,12]

m3.json数据:

[13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]

运行结果:

因为没有使用瀑布流布局所以有点不规整,这里主要演示分页。

作业:

完成一个瀑布流+延迟加载图片的相册或商品列表,要求图片大小不一,示例

1、有后台,通过ajax加载后台的json

2、200条数据以上

3、使用技术参考:masonry+imagesloaded+infinitescroll

四、响应式布局(Responsive)

4.1、媒介类型

@media早在css2.1中就有了,用于判断媒介类型,如screen屏幕,print打印机,projection投影仪,all表示所有,当然还有许多不常用的。可以指定CSS在什么样的媒介中应用,如只在打印时应用某些样式,如:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>打印</title>
        <!--该样式只会应用在打印时-->
        <style type="text/css" media="print">
            .noprint
            {
                display:none;
            }
            div{
                font-size:30px;
            }
        </style>
    </head>
    <body>
        <div>
            Installing Cordova Cordova command-line runs on Node.js and is available on NPM. Follow platform specific guides to install additional platform dependencies. Open a command prompt or Terminal, and type npm install -g cordova.
        </div>
        <button onclick="print();" class="noprint">打印</button>
    </body>
</html>
复制代码

不使用媒介时运行效果:

 使用媒介时运行效果:

4.2、媒介查询的应用位置(Media Queries)

a)、内部样式

@media screen and (800px){ … }

b)、导入样式

@import url(example.css) screen and (800px);

c)、链接样式
<link media="screen and (800px)" rel="stylesheet" href="example.css" />

d)、XML中应用样式
<?xml-stylesheet media="screen and (800px)" rel="stylesheet" href="example.css" ?>

4.3、Media Queries Hello World

在页面上放一个层,当屏幕大小在100-640之间时

示例代码:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>媒介查询</title>
        <style type="text/css">
            #div1 {
                background: lightblue;
                height: 100px;
            }
            
            @media only screen and (min- 100px) and (max- 640px) {
                #div1 {
                    background: lightgreen;
                    height: 200px;
                }
            }
        </style>
    </head>

    <body>
        <div id="div1">
            Hello World!
        </div>
    </body>

</html>
复制代码

全屏时的运行效果:

缩小浏览器的效果:

4.4、媒介查询语法

@media queries是CSS3中引入的,不仅可以实现媒介类型的查询可以实现设备特性的查询,可以简单认为是对CSS2.1中的media的增强,基本语法如下:

@media [not|only] media_type and feature

not:取反操作

only:让不支持media query的设备但读取media type类型的浏览器忽略这个样式

media_type:是媒介类型,具体如下:

feature:定义设备特性,多数允许加前缀min-,max-,多个条件可以使用and连接,and两侧需要空格。

常见写法:

            @media only screen and (min- 320px) and (max- 640px) {
            }
复制代码
@media (min-device-1024px) and (max-989px),screen and (max-device-480px),(max-device-480px) and (orientation:landscape),(min-device-480px) and (max-device-1024px) and (orientation:portrait) {
   CSS样式...
}
复制代码

and表示与,条件要同时满足;逗号表示或。

4.5、响应式栅格系统(Responsive)

在前面的布局中我们学习栅格系统,这里通过媒介查询实现响应式栅格系统,脚本如下:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>响应式栅格</title>
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
        <style type="text/css">
            * {
                margin: 0;
                padding: 0;
            }
            
            html,
            body {
                height: 100%;
                font: 20px/20px "microsoft yahei";
            }
            
            div {
                min-height: 100px;
            }
            
            .row {
                 800px;
                background: deepskyblue;
                margin: 0 auto;
            }
            
            .row:after {
                content: ' ';
                display: table;
                clear: both;
            }
            
            .col25 {
                 25%;
                background: lightgreen;
            }
            
            .col50 {
                 50%;
                background: lightcoral;
            }
            
            .col75 {
                 75%;
                background: lightblue;
            }
            
            [class*=col] {
                float: left;
            }
            /*0-480手机*/
            
            @media only screen and (max-480px) {
                .row {
                     100%;
                }
                [class*=col] {
                    float: none;
                    margin-top: 5px;
                     100%;
                }
            }
            /*480-960平板,手机横屏*/
            @media only screen and (min- 480px) and (max- 960px) {
                .row {
                     480px;
                }
            }
            /*960PC屏幕*/
            @media only screen and (min-960px) {
                .row {
                     960px;
                }
            }
        </style>
    </head>

    <body>
        <div id="container">
            <div id="header" class="row">
                header
            </div>
            <div id="main" class="row">
                <div id="left" class="col25">left</div>
                <div id="center" class="col50">center</div>
                <div id="right" class="col25">right</div>
            </div>
            <div id="footer" class="row">
                footer
            </div>
        </div>
    </body>

</html>
复制代码

示例代码中通过@media设置了多个断点,当满足条件时样式会应用,达到响应式的目的,屏幕大960时: 

480-960之间的效果:

 在手机上模拟的效果:

4.6、respond.js

respond.js是一个用于让IE8以下浏览器支持@media queries的插件,也就是使用Respond.js能让IE6-8支持CSS3 Media Query。Bootstrap里面就引入了这个JS文件,压缩后只有3KB。该脚本循环遍历页面上的所有 CSS 引用,并使用媒体查询分析 CSS 规则。然后,该脚本会监控浏览器宽度变化,添加或删除与 CSS 中媒体查询匹配的样式。最终结果是,能够在原本不支持的浏览器上运行媒体查询。

要注意的问题:

if CSS files are encoded in UTF-8 with Byte-Order-Mark, they will not work with Respond.js in IE7 or IE8.

微软的utf-8格式且BOM的文件会出问题,BOM格式文档头3个字节就是BOM,会影响程序对文档的处理。

最近有测试发现IE8还是出现了问题,动画@keyframe中的@符号造成的影响会使respond.js失效,因此,在使用respond.js时,尽量就不要用CSS3动画。

下载地址:https://github.com/scottjehl/Respond/

引入方法:

<!--[if lt IE 9]>
<script src="html5shiv.js"></script>
<script src="respond.min.js"></script>
<![endif]-->

4.7、移动优先(Mobile First)

a)、桌面优先(优雅降级)

这是一种传统的做法,开发项目时优先PC端,然后再通过一些hack的方法让项目正常运行在移动端,所谓的降级可以简单认为就是将一些信息隐藏,因为移动端的可视范围有限,必须给用户提供简洁核心的内容。

b)、移动优先(渐进增强)

a)、对于产品设计师,一个新产品先设计移动版,然后才是桌面版。

b)、对于工程师,一个新产品,先开发移动版,然后才是桌面版本。

这样的好处是能把握好最核心最关键内容,让界面简洁。

练习1:

请模拟如下的响应式显示效果,要求兼容各种设备:

练习2:

模拟:http://cordova.apache.org/头部

PC端效果:

移动端效果:

4.8、视区(viewport)

4.8.1、需要设置viewport的原因

viewport也称视口,PC上是指浏览器窗口的可视区域。先了解两个概念:

可见视口(visual viewport):浏览器窗口的可视区域

布局视口(layout viewport):CSS在应用时所设置的布局最大宽度。布局视口可以大于可见视口。

移动设备上的viewport都是要大于浏览器可视区域的、这样就会产生一个默认缩放的结果,请看示例如下: 

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>viewport</title>
    </head>
    <body>
        <p>
            viewport也称视口,PC上是指浏览器窗口的可视区域。先了解两个概念: 可见视口(visual viewport):浏览器窗口的可视区域 布局视口(layout viewport):CSS在应用时所设置的布局最大宽度。布局视口可以大于可见视口。
        </p>
    </body>
</html>
复制代码

运行效果:

在手机上显示的效果:

以上是iphone5显示的效果,字体根本看不清楚原因如下:

CSS中的1px并不等于设备的1px,PC中CSS的1个像素往往都是对应着电脑屏幕的1个物理像素
CSS中的像素是逻辑上的px
屏幕上的像素是物理上的px,两者有区别
要考虑PPI,pixels per inch每英寸像素数
当PPI为90时每个像素为0.011英寸
iPhone4的PPI为326,如果CSS像素再和设备像素保持对应,人眼将很难看清较小的字体或者图案。

移动设备上的viewport分为layout viewport、visual viewport和ideal viewport 三类,ideal viewport是最适合移动设备的viewport,ideal viewport的宽度等于移动设备的屏幕宽度,也就是宽度为100%的效果。ideal viewport 的意义在于,无论在何种分辨率的屏幕下,那些针对ideal viewport 而设计的网站,不需要用户手动缩放,也不需要出现横向滚动条,都可以完美的呈现给用户。
http://viewportsizes.com/ 各种设备ideal viewport
就是相同英寸下正常分辨率的PC机的物理像素!一般为72px/英寸,即每英寸宽或高的屏幕有72个物理颜色点。

移动设备默认的viewport是layout viewport,也就是那个比屏幕要宽的viewport,但在进行移动设备网站的开发时,我们需要的是ideal viewport。

4.8.2、设置viewport的方法

利用meta标签对viewport进行控制,如:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

参数解释:

示例:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>viewport</title>
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    </head>
    <body>
        <p>
            viewport也称视口,PC上是指浏览器窗口的可视区域。先了解两个概念: 可见视口(visual viewport):浏览器窗口的可视区域 布局视口(layout viewport):CSS在应用时所设置的布局最大宽度。布局视口可以大于可见视口。
        </p>
    </body>
</html>
复制代码

效果:

4.8.3、小节

首先如果不设置meta viewport标签,那么移动设备上浏览器默认的宽度(布局视口)值为800px,980px,1024px等这些,总之是大于屏幕宽度(可见视口)的。这里的宽度所用的单位px都是指css中的px,它跟代表实际屏幕物理像素的px不是一回事。

每个移动设备浏览器中都有一个理想的宽度(ideal viewport),这个理想的宽度是指css中的宽度,跟设备的物理宽度没有关系,在css中,这个宽度就相当于100%的所代表的那个宽度。

一般在head中加上如下的meta即可:

<meta name="viewport" content="width=device-width, initial-scale=1" />

五、REM实现响应式布局

rem是CSS3新引进来的一个度量单位,相对长度单位。相对于根元素(即html元素)font-size计算值的倍数,如:

height:2rem;,则高度的大小为32px(字体默认为16px,chrome最小为12px),如果根元素的字体为15px,则结果为30px。

页面中的尺寸都以html元素的font-size为相对单位,为默认设置为20px,如果需要一个200px的大小则使用10rem,然后当屏幕大小变化时通过javascript或media queries修改字体大小。

5.1、使用javascript设置相对尺寸

示例代码:

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>rem</title>
        <meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <style>
            html {
                height: 100%;
                 100%;
                font-family: 'Microsoft YaHei';
                font-size: 20px;
                overflow: hidden;
                outline: 0;
            }
            
            body {
                height: 100%;
                margin: 0;
                overflow: hidden;
                -webkit-user-select: none;
                /*取消用户选择*/
                 100%;
            }
            
            header,
            footer {
                 100%;
                line-height: 1.5rem;
                font-size: 1rem;
                color: #000;
                border: 1px solid #ccc;
                text-align: center;
                background-color: #ccc;
            }
            
            .bd {
                margin-top: 1rem;
                margin-bottom: .5rem;
                margin-right: -.5rem;
                font-size: 0;
            }
            
            .bd:after {
                clear: both;
            }
            
            .box {
                 5rem;
                height: 5rem;
                display: inline-block;
                margin-right: .5rem;
                margin-bottom: .5rem;
            }
            
            .blue-box {
                background-color: #06c;
            }
            
            .org-box {
                background-color: #1fc195;
            }
        </style>

    </head>

    <body>
        <header>我是头部</header>
        <div class="bd">
            <div class="box blue-box"></div>
            <div class="box org-box"></div>
            <div class="box blue-box"></div>
            <div class="box org-box"></div>
            <div class="box blue-box"></div>
            <div class="box org-box"></div>
            <div class="box blue-box"></div>
            <div class="box org-box"></div>
            <div class="box blue-box"></div>
        </div>

        <footer>我是页脚</footer>
        <script>
            //定义一个方法并执行
            (function(doc, win) {
                //获得文档的根节点html
                var docEl = doc.documentElement;
                //如果window中存在orientationchange对象,则取orientationchange,否则取resize
                //为了事件绑定
                resizeEvt = 'orientationchange' in win ? 'orientationchange' : 'resize';
                //定义一个方法,重新计算font-size大小
                var recalc = function() {
                    //页面的宽度
                    var clientWidth = docEl.clientWidth;
                    //如果没有宽度则退出
                    if(!clientWidth) return;
                    //重新计算font-size大小,假定320的宽度时字体大小为20;,当页面变化时重新设置字体大小
                    docEl.style.fontSize = 20 * (clientWidth / 320) + 'px';
                };
                //如果浏览器不支持添加事件监听则结束
                if(!doc.addEventListener) return;
                //添加事件监听,指定事件处理函数的时期或阶段(boolean)true表示在捕获事件执行,false表示冒泡时执行
                win.addEventListener(resizeEvt, recalc, false);
                //当Dom树加载完成时执行计算,DOMContentLoaded事件要在window.onload之前执行
                doc.addEventListener('DOMContentLoaded', recalc, false);
            })(document, window);
        </script>
    </body>

</html>
复制代码

运行效果:

5.2、使用媒介查询设置字体尺寸

示例代码:

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>rem and media queries</title>
        <meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <style>
            html {
                height: 100%;
                 100%;
                font-family: 'Microsoft YaHei';
                font-size: 20px;
                overflow: hidden;
                outline: 0;
            }
            
            .box {
                 5rem;
                height: 5rem;
                display: inline-block;
                margin-right: .5rem;
                margin-bottom: .5rem;
            }
            
            .blue-box {
                background-color: #06c;
            }
            
            .org-box {
                background-color: #1fc195;
            }
            
            @media only screen and (max- 300px) {
                html {
                    font-size: 10px;
                }
            }
            @media only screen and (min- 300px) and (max- 640px) {
                html {
                    font-size: 20px;
                }
            }
            @media only screen and (min- 640px) and (max- 960px) {
                html {
                    font-size: 30px;
                }
            }
            @media only screen and (min- 960px){
                html {
                    font-size: 40px;
                }
            }
        </style>
    </head>
    <body>
        <div class="bd">
            <div class="box blue-box"></div>
            <div class="box org-box"></div>
            <div class="box blue-box"></div>
            <div class="box org-box"></div>
            <div class="box blue-box"></div>
            <div class="box org-box"></div>
            <div class="box blue-box"></div>
            <div class="box org-box"></div>
            <div class="box blue-box"></div>
        </div>
    </body>
</html>
复制代码

运行结果:

 

六、示例下载

github:https://github.com/zhangguo5/CSS3_4.git

原文地址:https://www.cnblogs.com/libin-1/p/6136459.html