谈谈布局那些事

前言

最近遇到布局的一些问题,特此归纳总结一下。

文章将从几个重要的布局概念,也是布局的原理、基础说起,最后从早期的table布局说起一直到比较新的grid布局结束,具体会粗略讲解以下几部分内容:

  1. float、positon
  2. BFC\IFC
  3. 堆叠上下文
  4. flex
  5. grid
  6. 响应式布局
  7. 著名布局

从最早有界面这个概念时,布局就应运而生,如果说内容是界面的血肉,那么布局其实就是界面的骨架,没有良好的骨架,再多堆砌的内容也只是烂泥扶不上墙而已。

随着硬件、网络情况发展,标准逐渐完善,为了满足界面布局日益增长的需求,主流的布局方式持续更新换代,新概念连续产生、浏览器兼容性的逐渐改善为我们不断带来新的利器,拜托旧时混乱低效的布局方式。

float

先从我们最熟悉的float说起吧,其实float是一个不守规矩的家伙,他会表现出正常文档流没有的一些能力,但强大的同时也会带来一些问题。

浮动(float),元素的float属性设置为left或right后,元素会从常规流中脱离,被漂浮在容器(包含块)左边或右边,浮动盒会一直漂浮到其外边缘挨到容器边缘或其他的浮动盒。

其实浮动最初的设计目的是为了一种文字环绕图片效果。

jsbin float试验

造成这个效果的原因是,元素浮动后脱离正常文档流,就会保持相对独立的状态,不会影响到后面的块级格式化上下文,但或多或少还是会有一些影响,浮动元素的line box会变短避开浮动元素。

后来人们逐渐把float布局的黑科技发扬光大,不仅仅只是用作与文字进行配合,flex前的著名布局大多都依仗float,这些后面布局方法部分会讲到,我们先看一些示例:

这是BFC + float的双栏布局,后面会讲到原理。

<main>
  <aside>aside</aside>
  <article>The list properties describe basic visual formatting of lists:
    they allow style sheets to specify the marker type (image, glyph,
    or number), and the marker position with respect to the principal
    box (outside it or within it before content). 
  </article>
</main>

<style>
  aside {
    width: 10em;
    float: left;
    background: lightblue;
    min-height: 20em;
  }
  article {
    overflow: hidden;
    background: coral;
    min-height: 20em;
  }
</style>

float + position双栏布局,比较通用、侵入性比较小的relative方案。先用负margin把被第一个元素的100%width挤下来第二个浮动元素(aside)堆叠到第一个元素上面,然后根据left属性的百分比偏移定位到父元素的padding中。

<main>
  <article>The list properties describe basic visual formatting of lists:
    they allow style sheets to specify the marker type (image, glyph,
    or number), and the marker position with respect to the principal
    box (outside it or within it before content). 
  </article>
  <aside>aside</aside>
</main>

<style>
  main {
    font-size: 14px;
    padding-left: 10em;
  }
  article {
    float: left;
    width: 100%;
    background: coral;
    min-height: 20em;
  }
  aside {
    width: 10em;
    float: left;
    margin-left: -10em;
    position: relative;
    left: -100%;
    background: lightblue;
    min-height: 20em;
  }
</style>

在上面布局的基础上,顺便再写一个CSS列元素等高的奇技淫巧。可,以看到算是只加了5行代码,首先父元素(main)overflow设置为溢出不可见,再分别将要等高的元素添加一个较大的padding-bottom值增加高度,margin-bottom拉回来

<main>
  <article>The list properties describe basic visual formatting of lists:
    they allow style sheets to specify the marker type (image, glyph,
    or number), and the marker position with respect to the principal
    box (outside it or within it before content). 
  </article>
  <aside>aside</aside>
</main>

<style>
  main {
    font-size: 14px;
    padding-left: 10em;
    overflow: hidden;
  }
  article {
    float: left;
    width: 100%;
    background: coral;
    padding-bottom: 99em;
    margin-bottom: -99em;
  }
  aside {
    width: 10em;
    float: left;
    margin-left: -10em;
    position: relative;
    left: -100%;
    background: lightblue;
    padding-bottom: 99em;
    margin-bottom: -99em;
  }
</style>

float确实流行过很长一段时间,但伴随着使用技巧的往往也还有另一句话,尽量避免使用float,因为它会造成一些副作用。

所以float都会配合clear使用,clear属性有3个常用值,left,right,both,初始值为none,应用于你想要修正其受到的浮动影响的元素,clear是指定哪一边不能与浮动元素相邻,先看一个示例效果:

<section>
  <img src="http://p0.qhimg.com/t0117c2689d8703d551.jpg"
    width="120" alt="house">
  <p>莫哈韦沙漠不仅纬度较高,而且温度要稍微低些,是命名该公园的
  短叶丝兰——约书亚树的特殊栖息地。</p>
</section>
<section style="clear:both;">
  <h1>科罗拉多沙漠</h1>
  <p>科罗拉多沙漠海拔低于3000英尺(910米),环绕着约书亚树国家
  公园的东部,其主要特征为墨西哥三齿拉瑞阿低矮丛林、墨西哥刺木、
  沙漠滨藜和包括丝兰和灌木仙人掌混合的低矮丛林的生存环境。</p>
</section>

<style>
  img {
    float: left;
    margin-right: 30px;
  }
  p {
    font-size: 14px;
    line-height: 1.8;
    margin-left: 40px;
  }
</style>

带clear的代码

再让我们看看没有clear的情况

没有clear情况

效果还是比较明显的,一般来说我们页面的内容都是按照区域严格划分的,在使用float布局后,因为float会脱离正常文档流,其副作用会对整个文章的结构造成一定影响,所以一般来说我们都会配合clear进行清除副作用影响,清除浮动后,布局的两部分内容就不会位置混乱,另一小节的内容会在浮动元素下面进行呈现,而不会跑到上面小节中。在有伪元素后,我们一般会将清除浮动的职责单独出来,不在对各种其他小节的内容滥加clear属性,我们常用的如下代码:

.clearFloat::after{
    content: ' ';
    display: block;
    clear: both;
    height: 0;
    overflow: hidden;
}

我们在享受使用float的红利时,不要忘记它所带来的隐患,注意清除浮动防止元素高度塌陷和布局混乱等,而position又是另一种不一样的情况了,它的使用会更加多样。

position

定位的原理比较简单,它给出了设定元素框相对于其正常应出现位置、父元素、另一个元素甚至浏览器窗口的位置的方式。

基本上我们常用到的定位有四种不同类型,他们会影响元素框生成的方式。

static:元素框正常生成。块级元素生成一个矩形框,作为文档流的一部分,行内元素则会创建一个或多个行框,置于其父元素中,元素会在正常文档流当前布局位置,不能设置top、right等偏移属性。

relative:元素框偏移某个距离。元素首先会持其未定位前的状态,它原本所占的空间仍保留,再按照偏移量属性在不改变页面布局的前提下改变页面位置。

absolute:元素框从文档流中完全删除,并相对于包含块进行定位,包含块可能是相对指定元素最近的position非static包含块或初始包含块,不论原来是何种类型的框,元素定位后都会生成一个块级框,同时它也可以设置margin,且不会与其他边距合并。

fixed:类似absolute,从文档流中删除,但是相对于屏幕视口进行定位。元素会在新创建的堆叠上下文中,位置只会出现在固定位置,在屏幕滚动时不会改变。

相对定位并未脱离文档流且不会影响其他元素布局,但会造成原位置留白等问题,个人认为position的应用场景大多数还是在脱离文档流上,所以absolute会应用比较多,一般套路为父元素relative而子元素absolute。下面给一个多列等高的position例子:

<main>
  <article>The list properties describe basic visual formatting of lists:
    they allow style sheets to specify the marker type (image, glyph,
    or number), and the marker position with respect to the principal
    box (outside it or within it before content). 
  </article>
  <aside>aside</aside>
</main>

<style>
  main {
    font-size: 14px;
    position: relative;
  }
  article {
    background: coral;
    margin-left: 10em;
  }
  aside {
    width: 10em;
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    background: lightblue;
  }
</style>

常规流—BFC\IFC

说了很久常规流,那常规流到底是什么?

常规流(in flow)中的box都会存在与一个格式化上下文(formatting context)中,而不同的上下文决定了他布局的基本属性。

除了根元素、浮动元素和绝对定位元素,其他元素都在常规流中,这三种元素又被称为脱离常规流(out of flow)的元素

下面详细说一下两种上下文—BFC和IFC。

BFC

BFC(Block Formatting Context),即块级格式化上下文,是web页面可视化css渲染的结果,在触发上下文布局的区域出现的所有内容都会遵循特定上下文规则进行相对独立的布局展示。

BFC具体表现为:

  1. 盒子在包含块中是一个接一个的垂直放置
  2. 盒子的左边缘会紧贴容器的左边,两个兄弟盒之间的竖直距离由margin决定,但同一个BFC内垂直margin会合并,我们一般会分两个BFC防止margin折叠
  3. 可以和浮动进行配合,浮动不会影响到BFC外部的元素,这也是清除浮动的方法之一,设置父元素BFC后,BFC不会与浮动元素重叠,可以理解为浮动就被限制在了这个相对独立的上下文中,同时父元素高度塌陷等问题也就不复存在。

BFC的创建方法是:

  1. 浮动
  2. 绝对定位框
  3. 非块级的块容器(inline-block、table-cells,table-captions等)
  4. overflow属性非visible

这里要注意的是,是这些元素触发了BFC的创建,而不是这些元素是BFC,可以理解为这些是触发CSS机制的入口,类似关键字’be strict’。

最后总结一下BFC的常见作用:

1.双栏布局

<!-- 双栏布局 -->
    <div class="a"></div>
<div class="b"></div>
  <style>
    .a{
      background-color:green;
      float:left;
      width:200px;
      height:100px;
    }
    .b{
      background-color:red;
      height:200px;
      overflow:hidden;
    }
  </style>

2.清除浮动,双栏布局基础上嵌套一个div即可让双栏布局分行,同时没有高度塌陷问题

<div style="overflow:hidden;">
      <div class="a"></div>
    </div>
  <div class="b"></div>
  <style>
    .a{
      background-color:green;
      float:left;
      width:200px;
      height:100px;
    }
    .b{
      background-color:red;
      height:200px;
      overflow:hidden;
    }
  </style>

3.防止margin折叠

<!-- 防止margin折叠,一个块被一个块级格式化上下文包裹才不会折叠 -->
<div class="container">
    <div class="a"></div>
  </div>
  <div class="a"></div>
  <style>
    .a{
      background-color:green;
      width:200px;
      height:100px;
      margin:50px;
    }
    .container{
      height:200px;
      overflow:hidden;
    }
  </style>

IFC

很明显的,针对BFC的场景、API等会比IFC多一些,同时块级元素更加符合我们的思维习惯,也更加容易控制,所以我们可能会对BFC更加熟悉,而在IFC中你就必须和复杂且看似不可控的机制(vertical-align等)打交道,所以很多时候我们会回避IFC的一些事情,但在完整的布局里其实是很难回避的。

IFC(Inline Formatting Context),即行级格式化上下文,根据标准中说道,在一个IFC中,从父级元素的顶部开始,盒子一个接一个横向排列,此时,横向的margin、border、padding在这些盒子中都是有效的。这些盒子有可能通过不同方式垂直对齐:

  1. 他们底部或者顶部可以对齐
  2. 他们内部的文字基线可以对齐

如果一个矩形区域,包含一些排列成一条线的盒子,那这个矩形区域会被称为line box。当一个line box放不下上下文内所有盒子时,那么剩余盒子会被分到多个垂直堆叠的line box里面(也就是我们常见的一行字放不下那么它会自动换行),如果一个line box无法分割(单词、inline-block),该元素会被作为一个整体决定分布在哪一个line box(同样这样会被特殊换行规则或者white-space的nowrap等属性影响)。

示例如下:

<p style="background-color:silver; width:100px; ">
    <span style="border:1px solid blue; font-size:50px;">text in span</span>
    <em style="border:1px solid yellow; font-size:30px; vertical-align:top;">great1</em>
</p>

可以看到由于行框宽度限制(100px),第一个 SPAN 元素形成的行内框,被分割成了 3 段。

多个line box

一个line box内的盒子横向分布由text-align决定,而vertical-align则负责定义盒子所处line box的垂直对齐关系,line-height 根据与line box的对齐关系即vertical-align确定,默认为baseline之间的距离。

<p style="background-color:silver; width:500px; ">
    <span style="border:1px solid blue; font-size:50px;">text in span</span>
    <em style="border:1px solid yellow; font-size:30px; vertical-align:top;">great1</em>
</p>

vertical-align对齐关系

<p style="background-color:silver; width:500px;overflow:hidden; text-align:center;">
    <span style="border:1px solid blue; font-size:50px; float:left;">FLOAT</span>
    <em style="border:1px solid yellow; font-size:30px;">great1</em>
    <span style="border:1px solid yellow;">good</span>
</p>

text-align对齐关系

同一个IFC中通常line box有相同宽度,但浮动可能会使其变化,浮动元素存在在line box 和 contain box之间。

示例如下:

<p style="background-color:silver; width:500px; overflow:hidden; ">
    <span style="border:1px solid blue; font-size:50px; float:left;">FLOAT</span>
    <em style="border:1px solid yellow; font-size:30px;">great1</em>
    <span style="border:1px solid yellow;">good</span>
</p>

结构关系

层叠上下文

层叠上下文(stacking context)是HTML元素的三维概念,这些HTML元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的z轴上延伸,HTML元素依据其自身属性按照优先级顺序占用层叠上下文的空间。

堆叠上下文的背景和最负的(z-index最小)定位的堆叠上下文位于堆叠的底部,而最正(z-index最大)定位的堆叠上下文位于堆叠的顶部。

堆叠上下文跟前面的BFC和IFC其实也有相似之处,都是根据一定条件创建,包含块及其内容成为一个相对独立的、符合特定规则的界面布局单元,同时包含块又处在其父元素的上下文中。

常见生成方法:

  1. root元素
  2. z-index不为auto的定位元素
  3. 设置了某些CSS3的属性,如transform、opacity、animation等

总体绘制顺序:

  1. 形成该上下文的元素的 border 和 background
  2. z-index 为负值的子堆叠上下文
  3. 常规流内的块级元素非浮动子元素
  4. 非定位的浮动元素
  5. 常规流内非定位行级元素
  6. z-index 为 0 的子元素或子堆叠上下文
  7. z-index 为正数的子堆叠上下文

总结一下:

  1. 给一个 HTML 元素定位和 z-index 赋值创建一个层叠上下文,(opacity 值不为 1 的也是相同)。
  2. 层叠上下文可以包含在其他层叠上下文中,并且一起创建一个有层级的层叠上下文。
  3. 每个层叠上下文完全独立于它的兄弟元素:当处理层叠时只考虑子元素。
  4. 每个层叠上下文是自包含的:当元素的内容发生层叠后,整个该元素将会在父层叠上下文中按顺序进行层叠。

flex

以上我们基本讲了一下传统的布局解决方法,基于盒模型,组合使用display + float + position属性。问题可以解决,但有些很简单的功能实现起来却十分复杂(没有专门或统一的解决方案),因为这些其实并不是专门为解决布局问题而生或者只是部分(简单)布局的解决方案,本质上它们只是布局的hack而已。

这些常用功能却完全可以被设计的很简单。随着布局需求的日渐增强,2009年,w3c提出了专门为布局而生的flex语法,从此以后我们就可以使用简洁、强大、响应式的布局方案了,当然flex特性还是不能够兼容一些老的浏览器的。

caniuse flex 兼容性

创建弹性盒子很简单,只需要

.flexBox{
    display: flex;
}

下面就可享受Flexbox可控制子元素的福利了,可以在父元素使用如下 API 控制子元素:

  1. 水平或垂直排成一行 flex-direction
  2. 控制子元素对齐方式 justify-content align-items align-content
  3. 控制子元素的宽度、高度 flex-grow flex-shrink
  4. 控制子元素显示顺序 order
  5. 控制子元素是否折行 flex-warp

flex-direction是选择哪个方向是排列方向(即主轴),默认水平为主轴。有如下属性值

  1. row 默认水平排列
  2. row-reverse 水平反向排列
  3. column 垂直排列
  4. column-reverse 垂直反向排列
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>

<style>
  ul {
    display: flex;
    flex-direction: column-reverse;
    padding: 0;
    background: lightgray;
  }
  li {
    list-style: none;
    padding: 1em;
    background: lightblue;
  }
</style>

flex-grow定义每一个子元素在盒子内的弹性,即扩展剩余盒子的能力,默认为0,响应式布局的利器

<ul>
  <li class="item-1">Item 1</li>
  <li class="item-2">Item 2</li>
  <li class="item-3">Item 3</li>
</ul>

<style>
  ul {
    display: flex;
    padding: 0;
    background: lightgray;
  }
  li {
    list-style: none;
    padding: 1em;
  }
  .item-1 {
    background: lightblue;
    flex-grow: 1;
  }
  .item-2 {
    background: lightgreen;
    flex-grow: 1;
  }
  .item-3 {
    background: coral;
  }
</style>

flex-shrink定义元素收缩能力,默认为1

<ul>
  <li class="item-1">Item 1 content</li>
  <li class="item-2">Item 2 content</li>
  <li class="item-3">Item 3 content</li>
</ul>

<style>
  ul {
    display: flex;
    padding: 0;
    background: lightgray;
  }
  li {
    list-style: none;
    padding: 1em;
  }
  .item-1 {
    background: lightblue;
    flex-grow: 1;
    flex-shrink: 0;
  }
  .item-2 {
    background: lightgreen;
    flex-grow: 1;
  }
  .item-3 {
    background: coral;
  }
</style>

flex-wrap元素在主轴方向排列时能否换行,有如下属性值:

  1. nowarp 不换行,元素按主轴方向大小的比例挤在一行或一列
  2. warp 换行
  3. warp-reverse 按侧轴方向倒序排列
<ul>
  <li class="item-1">Item 1 content</li>
  <li class="item-2">Item 2 content</li>
  <li class="item-3">Item 3 content</li>
  <li class="item-4">Item 4 content</li>
</ul>

<style>
  ul {
    display: flex;
    flex-wrap: wrap;
    padding: 0;
    background: lightgray;
  }
  li {
    list-style: none;
    padding: 1em;
    width: 33%;
    box-sizing: border-box;
  }
</style>

justify-content定义子元素沿主轴方向的摆放方式

  1. flex-start 向正方向对齐
  2. flex-end 向反方向对齐
  3. center 居中对齐
  4. space-between 两边对齐
  5. space-around 空间环绕对齐,元素块两边各有类似相等margin大小的东西
<ul>
  <li class="item-1">Item 1 content</li>
  <li class="item-2">Item 2 content</li>
  <li class="item-3">Item 3 content</li>
</ul>

<style>
  ul {
    display: flex;
    justify-content: space-between;
    padding: 0;
    background: lightgray;
  }
  li {
    list-style: none;
    padding: 1em;
  }
  .item-1 {
    background: lightblue;
  }
  .item-2 {
    background: lightgreen;
  }
  .item-3 {
    background: coral;
  }
</style>

align-items定义在侧轴方向的对齐方式,默认stretch,另外子元素可以使用align-self定义自身,优先级高

  1. flex-start
  2. flex-end
  3. center
  4. baseline
  5. stretch
<ul>
  <li class="item-1">Item 1 content</li>
  <li class="item-2">Item 2 content</li>
  <li class="item-3">Item 3 content Item 3 content Item 3 content
    Item 3 content</li>
</ul>

<style>
  ul {
    display: flex;
    padding: 0;
    background: lightgray;
  }
  li {
    list-style: none;
    padding: 1em;
  }
  .item-1 {
    background: lightblue;
    flex-shrink: 0
  }
  .item-2 {
    background: lightgreen;
    flex-shrink: 0
  }
  .item-3 {
    background: coral;
  }
</style>
<ul>
  <li class="item-1">Item 1 content</li>
  <li class="item-2">Item 2 content</li>
  <li class="item-3">Item 3 content Item 3 content Item 3 content
    Item 3 content</li>
</ul>

<style>
  ul {
    display: flex;
    padding: 0;
    background: lightgray;
    align-items: flex-start;
  }
  li {
    list-style: none;
    padding: 1em;
  }
  .item-1 {
    background: lightblue;
    flex-shrink: 0;
    align-self: flex-end;
  }
  .item-2 {
    background: lightgreen;
    flex-shrink: 0;
  }
  .item-3 {
    background: coral;
  }
</style>

align-content定义多行内容在容器内侧轴方向的对齐

  1. flex-start
  2. flex-end
  3. center
  4. space-between
  5. space-around
  6. strentch

order指定摆放时的顺序,从小到大,默认0

<ul>
  <li class="item-1">Item 1</li>
  <li class="item-2">Item 2</li>
  <li class="item-3">Item 3</li>
</ul>

<style>
  ul {
    display: flex;
    padding: 0;
    background: lightgray;
  }
  li {
    list-style: none;
    padding: 1em;
  }
  .item-1 {
    background: lightblue;
  }
  .item-2 {
    background: lightgreen;
    order: 1;
  }
  .item-3 {
    background: coral;
  }
</style>

Grid

Grid,又称CSS栅格布局,是一个基于栅格的二维布局系统,旨在彻底改变基于网格用户界面的设计。跟我们在类似ant-design、element-ui等组件库中见到的一样,它确实提供了强大而又简洁的语法,当然兼容性目前不算特别好。

caniuse grid 兼容性

grid跟flex的语法“一脉相承”却又“创意十足”,简单的声明之后即可享用

.container{
    display: grid;
}

在定义完栅格布局后,会为它的内容生成一个栅格格式上下文(grid formatting context),下面即可用超强的 API 进行布局:

  1. grid-template-columns grid-template-rows 定义栅格区域的行和列,得到初始二维布局
  2. grid-template-areas 通过指定栅格子元素的名字来定义栅格模板,栅格子元素通过 grid-area 来定义自己的名字
  3. grid-column-gap gird-row-gap 定义栅格线的大小,可以理解为行、列间隙
  4. justify-items align-items 定义栅格子元素中的内容与列、行的对齐关系
  5. align-content justify-content 定义栅格内容区域整体大小与栅格整体区域的对其关系
  6. grid-auto-columns grid-auto-rows 定义自动生成的栅格分区(也称隐式栅格轨迹)的大小
  7. grid-auto-flow 如果你的栅格没有显式在栅格中设置位置,自动放置算法便会生效。这个属性控制自动放置算法的运作。

具体详情介绍可以看参考文献中的 Grid布局完全指南

响应式布局

viewport

响应式图片 max-width: 100%

背景图片 background-size: cover\contain

保持高度比 hack

height:0; padding-top:50%;
padding百分比参照父元素宽度,当父元素与当前元素宽度相同时,即可随意塑造比例
两栏自适应布局

float BFC
绝对定位
模拟table
flex布局
media query 针对不同媒体情况选择不同样式

width
height
device-width
device-height
device-pixel-ratio
orientation

rem

CSS3中引入了许多新单位,给我们带来了极大便利,比如rem、em、vw等,它使我们的相对单位更加灵活,布局更加方便。

移动端比较常用的是rem布局,rem单位本身是的基准值是跟元素的 font-size 属性,也就是说

1rem 等价于 16px(html元素默认的font-size值)

根据其原理,那么只需要在不同分辨率设置不同的font-size就可以复用一套代码了

    (function(){
        let viewWidth = window.innerWidth,
          htmlElem = document.documentElement;

        console.log(window.innerWidth, window.innerHeight);
        htmlElem.style.fontSize = viewWidth / 15 + "px";

        window.addEventListener('resize', function(){
          viewWidth = window.innerWidth;
          htmlElem.style.fontSize = viewWidth / 15 + "px";
        })
      })()

这样在一套CSS代码中,我们就可以保证一个元素永远相对于视口占比多少了,总结一下就是:根据设计图适配多端、等比缩放。

以上我们使用 js进行 rem 计算,其实得到的结果就是视口的十五分之一的 px 大小,而这恰巧是 vw 的定义,因为vw的兼容性不是特别好,所以我们用 rem 实际是进行了 polyfill

1vw = device-width / 100

另外 rem 布局也有其一定的局限性:

  1. 字体大小与页面缩放比例不是线性关系,所以需要另外设置一套字体使用的大小,我一般媒体查询大概确定不同 body 元素的 font-size大小,然后子元素使用 em 单位进行布局。
  2. rem 的弹性布局有一定限制,过宽或过窄等极限情况容易走形,我一般都是多设置断点,多用 media query。

如果字体要采用 emm 单位进行布局,那么还要注意一些 em 单位的问题:

  1. 浏览器默认 font-size 大小是 16px ,所有元素的 font-size 初始值是 inherit
  2. 如果你显式改变了 font-size 初始值,那么 em 的基准对象就是自身 font-size
  3. 如果没有显式改变了 font-size 初始值,那么 em 的基准对象就是父元素 font-size 的计算值,不论父元素是显式定义还是 inherit 计算得到

哪些年我们步过的局

1.绝对定位法

  HTML代码如下:

  

Left

  
Main

  
Right

  CSS代码如下:

  //简单的进行CSS resetbody,html{ height:100%; padding: 0px; margin:0px;
  }
  //左右绝对定位.left,.right{ position: absolute; top:0px; background: red; height:100%;
  }.left{ left:0; width:100px;
  }.right{ right:0px; width:200px;
  }
  //中间使用margin空出左右元素所占据的空间.main{ margin:0px 100px 200px 0px; height:100%; background: blue;
  }
  该方法有个明显的缺点,就是如果中间栏含有最小宽度限制,或是含有宽度的内部元素,当浏览器宽度小到一定程度,会发生层重叠的情况。

  2. 圣杯布局

  HTML代码如下:

  //注意元素次序
  

Main

  
Left

  
Right

  CSS代码如下:

  //习惯性的CSS resetbody,html{ height:100%; padding: 0; margin: 0}
  //父元素body空出左右栏位body { padding-left: 100px; padding-right: 200px;
  }
  //左边元素更改.left { background: red; width: 100px; float: left; margin-left: -100%; position: relative; left: -100px; height: 100%;
  }
  //中间部分.main { background: blue; width: 100%; height: 100%; float: left;
  }
  //右边元素定义.right { background: red; width: 200px; height: 100%; float: left; margin-left: -200px; position: relative; right: -200px;
  }
  相关解释如下:

  (1)中间部分需要根据浏览器宽度的变化而变化,所以要用100%,这里设左中右向左浮动,因为中间100%,左层和右层根本没有位置上去

  (2)把左层margin负100后,发现left上去了,因为负到出窗口没位置了,只能往上挪

  (3)按第二步这个方法,可以得出它只要挪动窗口宽度那么宽就能到最左边了,利用负边距,把左右栏定位

  (4)但由于左右栏遮挡住了中间部分,于是采用相对定位方法,各自相对于自己把自己挪出去,得到最终结果

  3. 双飞翼布局

  HTML代码如下:

  


  
Main

  

  
Left

  
Right

  CSS代码如下:

  //CSS reset
body,html { height:100%; padding: 0; margin: 0}body { /padding-left:100px;/
  /padding-right:200px;/}
.left { background: red; width: 100px; float: left; margin-left: -100%; height: 100%; /position: relative;/
  /left:-100px;/}
.main { background: blue; width: 100%; float: left; height: 100%;
  }
.right { background: red; width: 200px; float: left; margin-left: -200px; height: 100%; /position:relative;/
  /right:-200px;/}
  //新增inner元素
.inner { margin-left: 100px; margin-right: 200px;
  }
  圣杯布局实际看起来是复杂的后期维护性也不是很高,在淘宝UED的探讨下,出来了一种新的布局方式就是双飞翼布局,代码如上。增加多一个div就可以不用相对布局了,只用到了浮动和负边距。和圣杯布局差异的地方已经被注释。

  4. 浮动

  HTML代码如下:

  //注意元素次序
  

Left

  
Right

  
Main

  CSS代码如下:

  //CSS resetbody,html { height:100%; padding: 0; margin: 0}
  //左栏左浮动.left { background: red; width: 100px; float: left; height: 100%;
  }
  //中间自适应.main { background: blue; height: 100%; margin:0px 100px 200px 0px;
  }
  //右栏右浮动.right { background: red; width: 200px; float: right; height: 100%;
  }
  这种方式代码足够简洁与高效,也容易理解

参考文献

  1. KB010: 常规流( Normal flow )
  2. float详解
  3. A Complete Guide to Flexbox
  4. Grid布局完全指南
  5. 5 种常用布局的 flex 实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值