css布局

学习css的主要目的是为了记住各种属性么?NO,最重要的是理解css的定位机制与盒子模型。

接下来,从布局的角度来学习css的定位机制和盒子模型,学习之前还是先来提几个问题

  • 1.进行css布局前为什么要学习定位机制和盒子模型?
  • 2.在实际的工作中到会用到哪些css布局?

1.css基础

1.1 盒子模型

css是用来为页面元素添加样式的,在最开始的时候,开发网页是先将各个尺寸定下来,然后使用最传统的position/float把元素挪到对应的位置,页面上的元素就好像一个个盒子一样,很明显能够得出一个结论:盒子模型是布局的基础,所以在学习css布局前要先来学习盒子模型,盒子模型包括content,padding,border,margin四大部分,如下图:

盒子模型一般分为标准盒子模型和IE盒子模型,前者由w3c规定,后者由微软规定,这两种盒子模型可以通过box-sizing来进行切换,它们最大的区别就是width属性作用的范围,标准盒子的width=content,IE盒子的width=content + padding + border,看下图:

除了标准盒子和IE盒子这种分类方法,一般还将盒子模型分成块级盒子模型和行内盒子模型,这个是根据不同的display属性值划分的,下面是display的可能取值:

块级盒子模型的图在上面已经贴出了,下面是行内盒子模型的图:

1.1.1 盒子模型的margin负值

前面说了盒子模型包括什么内容,对于任意的盒子模型来说,它的四部分内容可以给它们设值也可以不设值,这四个值中margin部分有很多可以探讨的内容,比如它可以设置负值,这一部分之所以复杂,是因为它与display的不同值混合时会有很多不同的情况,比如margin设负值后可能会带来重叠,那具体重叠的情况是怎样的?说不同的重叠情况前,先来理解一下,margin负值是什么意思?margin的值其实是相对于基线来进行移动,对于top,left方向,它们是以其他元素的边框为基线,对于right,bottom方向它们是以自身border为基线,具体看下图:

接下来看看不同的display会对margin重叠造成什么影响

  • 1.表现(测试地址:https://demo.xiaohuochai.site...)

    • 1.1 block元素可以使用四个方向的margin值
    • 1.2 inline元素使用上下方向的margin值无效

  • 1.3 inline-block使用上下方向的margin负值看上去无效

  • 2.重叠(测试地址:https://demo.xiaohuochai.site...)

    • 2.1 两个block元素重叠时,后面元素可以覆盖前面元素的背景,但无法覆盖其内容

  • 2.2 当两个inline元素,或两个line-block元素,或inline与inline-block元素重叠时,后面元素可以覆盖前面元素的背景和内容

  • 2.3 当inline元素(或inline-block元素)与block元素重叠时,inline元素(或inline-block元素)覆盖block元素的背景,而内容的话, 后面的元素覆盖前面的元素

  • 3.浮动(测试地址:https://demo.xiaohuochai.site...)

    • 3.1 block元素与浮动元素重叠时,其边框和背景在该浮动元素之下显示,而内容在浮动元素之上显示

  • 3.2 inline或inline-block元素与浮动元素重叠时,其边框、背景和内容都在该浮动元素之上显示

  • 4.定位(测试地址:https://demo.xiaohuochai.site...)

    • 4.1 定位元素(position不为static)覆盖其他元素的背景和内容

  • 4.2 将relative属性值应用于inline元素,由于无法改变其行内元素的本质,所以其上下margin依然存在问题

1.1.2 盒子模型的边距合并

margin合并(collapse)是指块级元素的上外边距与下外边距有时会合并为单个外边距,这种现象只发生在和当前文档流方向的相垂直的方向上,它分为同级元素和父子元素两种,首先是同级元素,具体代码如下:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        .center{            width: 500px;            background: pink;            margin: 80px auto;            padding: 10px;        }    </style></head><body>    <div class="center">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam mollitia aut eaque nihil eos rem suscipit error id nesciunt saepe? Deserunt aspernatur, iusto facere sequi doloribus accusantium porro odio alias.</div>    <div class="center">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam mollitia aut eaque nihil eos rem suscipit error id nesciunt saepe? Deserunt aspernatur, iusto facere sequi doloribus accusantium porro odio alias.</div></body></html>

接着是父子元素,具体代码如下:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        .center{            width: 500px;            background: pink;            margin: 80px auto;        }        .inCenter{            background: blue;            margin: 40px 0;            padding: 10px;        }    </style></head><body>    <div class="center">        <div class="inCenter">hello</div>    </div>    </body></html>

1.1.3 盒子模型的margin居中

最后这个比较简单,是在布局中常用的一种水平居中的方法,当页面元素的宽度是确定的值的时候,设置margin:0 auto;元素会进行居中,这是因为auto代表左右自适应,具体代码如下:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        .center{            width: 500px;            background: pink;            margin: 80px auto;            padding: 10px;        }    </style></head><body>    <div class="center">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam mollitia aut eaque nihil eos rem suscipit error id nesciunt saepe? Deserunt aspernatur, iusto facere sequi doloribus accusantium porro odio alias.</div></body></html>

1.1.4 BFC

前面出现的边距重叠我们只是列出了问题但是没有解决,这是因为要解决这样的问题,需要了解另外一个知识,这个知识涉及到了定位机制的内容BFC,写在这里,就作为一个承前启后的部分,那BFC到底是什么?

BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

简单来说,BFC就是页面上单独开的一块渲染区域,有的人把它叫做css世界的结界,非常的形象,那它是如何被触发的?又为什么能解决边距重叠?
首先是触发规则:

  • 根元素
  • float属性不为none
  • position为absolute或fixed
  • display为inline-block, table-cell, table-caption, flex, inline-flex
  • 不为visible

接着是渲染规则:

  • 内部的Box会在垂直方向,一个接一个地放置。
  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
  • 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
  • 的区域不会与float box重叠。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 计算BFC的高度时,浮动元素也参与计算

最后看它怎样解决边距重叠,同样的代码,只需要添加一句overflow:hidden触发BFC,之所以能解决重叠是因为触发了新的bfc后与外部环境就隔开了,彼此不会影响。

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        .center1{            width: 500px;            background: pink;            margin: 80px auto;            padding: 10px;        }        .wrapper{            overflow: hidden;        }        .center2{            width: 500px;            background: pink;            margin: 80px auto;            padding: 10px;        }    </style></head><body>    <div class="center1">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam mollitia aut eaque nihil eos rem suscipit error id nesciunt saepe? Deserunt aspernatur, iusto facere sequi doloribus accusantium porro odio alias.</div>    <div class="wrapper">    <div class="center2">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam mollitia aut eaque nihil eos rem suscipit error id nesciunt saepe? Deserunt aspernatur, iusto facere sequi doloribus accusantium porro odio alias.</div>    </div></body></html>

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        .center{            width: 500px;            background: pink;            margin: 80px auto;            overflow:hidden;        }        .inCenter{            background: blue;            margin: 40px 0;            padding: 10px;        }    </style></head><body>    <div class="center">        <div class="inCenter">hello</div>    </div>    </body></html>

1.2 定位机制

1.2.1 position定位

上面说了盒子模型,知道了css操纵的内容具体是什么样的,接下来就需要把这些盒子放在页面上,在css的定位机制中,position:absolute、relative、static、fixed有这几个取值,先来看看这些取值的不同
position:absolute是将元素以浏览器视口为原点或者以最近的定位元素为原点来进行定位,具体看下面的代码:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        .wrapper{            width:500px;            height:500px;            background: pink;            margin:200px 500px;        }        .absolute{            width: 100px;            height:100px;            position:absolute;            top:50px;            left:50px;            background: green;        }    </style></head><body>  <div class="wrapper">        <div class="absolute">absolute</div>  </div></body></html>

接着是position:relative,他是相对于自身的位置进行偏移,具体看下面的代码:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        .wrapper{            width:500px;            height:500px;            background: pink;            margin:200px 500px;        }        .relative{            width: 100px;            height:100px;            position:relative;            top:50px;            left:50px;            background: green;        }    </style></head><body>  <div class="wrapper">        <div class="relative">relative</div>  </div></body></html>

1.2.2 float定位

上面的是position定位流,除了position定位流,css还有float定位流,原本css发明这个属性并不是用来定位的,但是它确实在定位时很方便,css的float定位会发生高度坍塌,也就是当设置了float时,会使得原本的元素脱离原来的div,使用上面说的BFC就可以解决这个问题,设置clear也可以解决,具体看下面的代码:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        .wrapper{            background: pink;            margin:200px 500px;            border:1px solid #000;            /*overflow:hidden;*/        }        .clear{            clear:both;        }        .float{            width: 100px;            height:100px;            float:left;            background: green;        }    </style></head><body>  <div class="wrapper">        <div class="float">relative</div>          //<div class="clear"></div>  </div></body></html>

2.css布局实战

2.2.1 传统布局

经过上面的基础知识,对于css的盒子模型和定位机制有了比较好的理解,接下来,就可以来检验一下,完成这几种布局需求:

  • 2栏布局
  • 圣杯布局
  • 高度自适应布局
  • 水平垂直居中布局

1.2栏布局:一遍定宽一遍自适应/一栏不定宽,一栏自适应/

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        body,div{padding: 0 ;margin-bottom: ;:20px;}    .left,.right{height: 200px;}    .left{float: left;width: 200px;background-color:skyblue;}    .right{margin-left: 200px; background-color: greenyellow;}    </style></head><body>      <div class="left">left固定200px</div>    <div class="right">right自适应</div></body></html>

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        body,div{padding: 0 ;margin:0;}    .left,.right{height: 200px;padding: 10px;}    .left{float: left;background-color:skyblue;}    .right{overflow:hidden;background-color: yellow;}    </style></head><body>      <div class="left">left不固定</div>    <div class="right">right自适应</div></body></html>

2.圣杯布局:上中(左中右)下

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        .top{    width: 100%;    height: 40px;    background-color: #cccccc;}.footer{    width: 100%;    height: 50px;    background-color: #abdc44;}/*左右固定,中间自适应*//*Start*/.container{    width: 100%;    height: 100%;    position: relative;}.left{    position: absolute;    left: 0;    top: 0;    width: 400px;    height: 600px;    background-color: black;}.center{    width: auto;    /*如果没有这一句,那么,center这个div的文字就不会自动换行*/    margin: 0 400px;    height: 600px;    background-color: yellow;}.right{    position: absolute;    top: 0;    right: 0;    width: 400px;    height: 600px;    background-color: red;}/*End*/    </style></head><body>      <div class="top">this is top</div><div class="container">    <div class="left">this is left</div>    <div class="center">this is center</div>    <div class="right">this is right</div></div><div class="footer">this is footer</div></body></html>


3.高度自适应布局:高度自适应

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>        .container {            width: 1200px;            background: pink;            overflow: hidden;        }div.item {    float:left;    width:300px;    padding-bottom: 5000000px;    margin-bottom: -500000px;    background: blue;    border:1px solid #000;}    </style></head><body>      <div class="container">        <div class="item">aaa</div>        <div class="item">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officia excepturi porro debitis quisquam corporis illum dolorum doloribus, similique esse veritatis harum hic, voluptatem veniam necessitatibus neque, animi, alias incidunt quasi!</div>        <div class="item">sss</div>      </div></body></html>

5.水平垂直居中定位:已知宽高/未知宽高

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>#father {        width: 500px;        height: 300px;        background-color: skyblue;        position: relative;}     #son {        width: 100px;        height: 100px;        background-color: green;        position: absolute;        left: 50%;        top: 50%;        margin-left: -50px;        margin-top: -50px;}</style></head><body>    <div id="father">    <div id="son">我是块级元素</div></div></body></html>

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>demo</title>    <style>    #father {        width: 500px;        height: 300px;        background-color: skyblue;        position: relative;}     #son {        background-color: green;        position: absolute;        left: 50%;        top: 50%;        transform: translateX(-50%) translateY(-50%);    }</style></head><body>    <div id="father">    <div id="son">我是块级元素</div></div></body></html>

2.2.2 flex布局

不知道大家实现刚才的一系列的布局是什么感受,我的感受是累,那有没有一种好用的布局方式,不用去使用各种属性来自我创造直接就能来用呢?flex布局
Flex的基本概念就是容器和轴,容器包括外层的父容器和内层的子容器,父容器设为flex后,它的所有子元素自动成为容器成员

父容器属性:    flex-direction    flex-wrap    flex-flow    justify-content    align-items    align-content子容器属性:    order    flex-grow    flex-shrink    flex-basis    flex    align-self

是的,它就是这么简单,接下来把上面的布局实现一下,看它到底多方便

  • 2列布局
<!DOCTYPE html><html><head><meta charset="utf-8"> <title>css3转换</title> <style>     .grid {        display: flex;        margin: 20px;    }    .grid-cell0 {        border-radius:20px;        width: 200px;        height:180px;        background:#eee;        margin:10px;        text-align:center;    }    .grid-cell1 {        flex:1;        border-radius:20px;        width: 200px;        height:180px;        background:#eee;        margin:10px;        text-align:center;    }    .grid-cell2 {        border-radius:20px;        height:180px;        background:#eee;        margin:10px;        text-align:center;    }    .grid-cell3 {        flex:1;        border-radius:20px;        width: 200px;        height:180px;        background:#eee;        margin:10px;        text-align:center;    }</style></head><body>    <div class="grid">        <div class="grid-cell0">固定</div>        <div class="grid-cell1">自适应</div>    </div>    <div class="grid">        <div class="grid-cell2">不固定</div>        <div class="grid-cell3">自适应</div>    </div></body></html>

  • 圣杯布局
<!DOCTYPE html><html><head><meta charset="utf-8"> <title>css3转换</title> <style>     * {        margin: 0;        padding: 0;        text-align: center;            }    .holy-grid {        display: flex;        flex-direction: column;        min-height: 100vh; /* 相对于视口的高度。视口被均分为100单位的vh */    }    header, footer {        text-align: center;        flex: 0 0 100px;        height:100px;        background: #aaa;    }        .holy-grid-content {        display: flex;        flex: 1;    }    .holy-grid-content-items {        flex: 1;    }    .holy-grid-content-left {        flex: 0 0 150px;        background:blue;        text-align: center;    }    .holy-grid-content-right {        flex: 0 0 150px;        background:pink;        text-align: center;    }</style></head>    <body class="holy-grid">    <header class="holy-grid-items">#header</header>    <div class="holy-grid-content holy-grid-items">        <div class="holy-grid-content-items holy-grid-content-left">            # left        </div>        <div class="holy-grid-content-items holy-grid-content-center">            # center        </div>        <div class="holy-grid-content-items holy-grid-content-right">            # right        </div>    </div>    <footer class="holy-grid-items">#footer</footer></body></html>

  • 高度自适应布局
<!DOCTYPE html><html><head>  <meta charset="UTF-8">  <title>flex 嵌套 之 高度自适应</title>  <style media="screen">    body, html {        height: 90%;    }    .flex {        display: -webkit-flex;        display: flex;        flex-direction: column;    }    .item {        flex: auto;    }    .overflow {        overflow: auto;    }    .outer {        height: 70%;        border: 1px solid silver;    }    .contener {        background: pink;        border: 1px solid silver;    }    .contener>div{        padding: 5px;    }  </style></head><body>  <h1>flex 嵌套布局</h1><div class="flex outer">  <div style="background-color: silver; padding: 10px;">外容器 自适应内容的区域 ... ...</div>  <div class="flex item overflow" style="padding: 15px;"> <!-- 嵌套的item加flex样式 及 overflow: auto属性 -->    <div class="flex contener overflow">                  <!-- overflow: auto 高度自适应必须 -->      <div style="background-color: yellow;">        <h3>内容器 - 头部信息</h3>      </div>      <div class="item overflow">                         <!-- overflow: auto 高度自适应必须 -->        内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>          内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>            内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>内容溢出滚动部分 <br>      </div>      <div style="background-color: yellow;">        <h3>内容器 - 尾部信息</h3>      </div>    </div>  </div></div></body></html>

  • 水平垂直居中
<!DOCTYPE html><html><head><meta charset="utf-8"> <title>css3转换</title> <style>    #father {        width: 500px;        height: 300px;        background-color: skyblue;        display: flex;        justify-content: center;        align-items: center;}     #son {        background-color: green;}</style></head><body>    <div id="father">    <div id="son">我是块级元素</div></div></body></html>

除了上面的这些布局,他还能实现均匀布局,非均匀布局

<!DOCTYPE html><html><head><meta charset="utf-8"> <title>css3转换</title> <style>     .grid {        display: flex;        margin: 20px;    }    .grid-cell {        flex: 1;         border-radius:20px;        height:180px;        background:#eee;        margin:10px;        text-align:center;    }</style></head><body>    <div class="grid">        <div class="grid-cell">cell1</div>        <div class="grid-cell">cell2</div>        <div class="grid-cell">cell3</div>    </div>    <div class="grid">        <div class="grid-cell">cell1</div>        <div class="grid-cell">cell2</div>    </div></body></html>

<!DOCTYPE html><html><head><meta charset="utf-8"> <title>css3转换</title> <style>     .grid {        display: flex;    }    .grid-cell,.cell-full,.cell-1of2,.cell-1of3 {        border-radius:20px;        height:180px;        background:#eee;        margin:10px;        text-align:center;    }    .grid-cell {        flex: 1;    }    .cell-full {        flex: 0 0 100%;        }    .cell-1of2 {        flex: 0 0 50%;    }    .cell-1of3 {        flex: 0 0 33.3333%;    }    .cell-1of4 {        flex: 0 0 25%;    }</style></head><body>    <div class="grid">        <div class="grid-cell cell-1of2">flex</div>        <div class="grid-cell">flexxxxxx</div>        <div class="grid-cell">sdfsdf</div>    </div>    <div class="grid">        <div class="grid-cell cell-1of3">flex</div>        <div class="grid-cell">flexxxxxx</div>        <div class="grid-cell">sdfsdf</div>    </div>    <div class="grid">        <div class="grid-cell cell-1of4">flex</div>        <div class="grid-cell">flexxxxxx</div>        <div class="grid-cell">sdfsdf</div>    </div></body></html>

经过这个过程,终于找到了一种适合的布局方法,这种方法适用于pc端和移动端,在移动端布局的时候,会经常听到rem布局,这是什么意思?要说明这个,还需要先来说说css中的单位,css常见的单位如下:

然后再来说说浏览器适配问题,通过百度流量统计研究院的数据可知,现在浏览器主流尺寸是:

  • PC端(1920*1080)
  • 移动端(640*360)

在开发网页时,针对PC端和移动端适配有2种方案

  • ①写两套代码,用JS判断设备后使用对应代码
  • ②写一套代码,用媒体查询判断后修改样式,一般以1200为界限。`

针对这些情况,常见的移动端布局有rem布局
最后就来演示一下rem

function intiSize(){//获取当前浏览器窗口宽度(这里的实质就是body宽度)var win_w=document.body.offsetWidth;//定义变量 var fontSize;if(win_w>640){ fontSize=24; }else{//如果浏览器窗口宽度(这里的实质就是body宽度)值小于320,取320win_w=Math.max(320,win_w); fontSize=win_w/320*12 }//设置根元素的大小 document.getElementsByTagName('html')[0].style.fontSize=fontSize+'px';}//浏览器窗口宽度发生变化时条用这个函数,方便与改变窗口大小时候调试onresize=intiSize;intiSize();

在上面动态的获取了设备宽度,然后根据设计尺寸和设备尺寸的比例来设置了fontsize,这个意思就是1rem = win_w/320*12px,这样在写页面的时候只要写rem这个单位,自适应问题就迎刃而解了,这就是rem,一个相对尺寸

ok,css布局完毕

本篇资料来源贴在下面,大家去看看:
行内盒子模型: https://biaoyansu.com/9.15
浅谈margin负值: https://zhuanlan.zhihu.com/p/...
css单位: http://www.w3school.com.cn/cs...