CSS布局的基本原理:盒模型、display、postion和float

作者: David

继续之前,你现在需要了解最基本的CSS知识,比如:

  • CSS用以描述HTML文档的样式,让页面更加美观
  • 如何引入CSS代码
  • CSS的基本语法
  • 如何使用CSS的选择器

这里我们来理解一下CSS的基本原理。先想象一下如果自己来开发一个CSS的渲染引擎,我们会怎么来做?得到了HTML元素构成的一个树状结构,首先要做的事情是不是就要在一个页面上把各个HTML元素按照一定的顺序排列出来?所以我们就先从如何排列HTML元素开始了解吧。

盒模型

如果不写任何CSS代码,HTML文档中的元素是按照出现顺序显示的,从上到下,从左到右。这是很自然的处理方式,我们在纸上或者在电脑上写文章也都是按照这种顺序。

具体到一个特定HTML元素的显示,它会被呈现为一个矩形,CSS标准中称之为Box。一个HTML元素占据空间的大小由盒模型决定。在盒模型中,一个盒子由内容、内边距、边框和外边距共同构成,其尺寸也是这四部分的尺寸之和。

看下面的代码:


<style>
.box {
  width: 100px;
  height: 100px;
  border: 10px solid blue;
  padding: 30px;
  margin: 40px;
  background: yellow;
}
</style>

<div class="box"></div>

这段代码的效果如下:



在Chrome的开发者工具中我们可以直观地看到class为box的div元素的盒模型,如下图所示:


在上面这个例子中:

  • 内容区域是最内部的浅蓝色方框部分,是由width: 100px; height: 100px;定义的,即高为100px,宽为100px
  • 内边距区域由padding属性定义
  • 边框区域由border属性定义
  • 外边距区域由margin属性定义

margin和padding都有上、右、下、左四个方向的宽度,四个方向的宽度大小可以分别设置。比如对于padding对应有padding-top, padding-right, padding-bottom, padding-left,margin同理。

注意,例子中width属性定义的是内容的宽度,不包含边距、边框。然而在IE中width定义的是内容+内边距+边框的宽度。 IE的做法相对更加符合直观的感觉。width的计算方式是由box-sizing属性来定义的,如果设置一个元素为box-sizing: border-box; ,元素的内边距和边框就会包含在width宽度内。

如果想要页面上所有的元素都以相同的方式定义高度和宽度,可以使用如下代码:


* {
    box-sizing: border-box;
}

HTML元素类型

HTML元素占据一个矩形区域,接下来你可能会问一个问题,相同层次的两个HTML元素,它们是在同一行左右排列,还是分布在不同的行上下排列呢?这时我们需要了解一下HTML元素的两种类型了。

HTML中的标签元素分为两种类型:

  • 块(block)元素
  • 行内(inline)元素

块元素的特点有:

  1. 每个块元素都从新的一行开始,独占一行
  2. 元素的高度、宽度、行高以及顶和底边距等属性都可设置
  3. 默认的高度与父元素的宽度一致,即width默认为100%
  4. 可以容纳行内元素和其他块元素

比如<div>、<p>、<ol>、<ul>、<table>、<form>等元素都是块元素。

行内元素具有如下特点:

  1. 和其他行内元素都在一行上
  2. 元素的高度、宽度、行高及顶部和底部边距等属性不可设置
  3. 元素不能设置高度,宽度就是它包含的文字或图片的宽度
  4. 行内元素只能容纳文本或者其他行内元素

比如<a>、<span>、<br>、<em>、<strong>等元素都是行内元素。

来看一个简单的例子,如下代码,在class为parent的<div>下分别有四个元素,一个<span>,一个<a>和两个<div>:

<style>
.box {
  width: 50px;
  height: 50px;
  border: 20px solid blue;
  padding: 30px;
  margin: 40px auto;
  background: yellow;
}
.parent {
  padding: 10px;
  border:1px solid green;
  text-align:center;
}
</style>
<div class="parent">
  <span>天码营</span>
  <a href="https://course.tianmaying.com/spring-mvc">Spring MVC实战训练</a>
  <div class="box"></div>
  <div class="box"></div>
</div>

这段代码的显示效果如下:




<span>和<a>元素是行内元素,因此它们在同一行。而<div>元素是块元素,两个<div>各自独占一行。

所以浏览器渲染页面时,碰到行内元素就会向右排列,处理块元素就会向下排列。但是这样简单的排列方式是很难做出复杂的布局的,所以这时候我们需要display属性了。

设置元素的显示方式:display属性

行内元素与块元素也可以相互转化,在CSS中将行内元素可以通过display: block设置为以块元素的方式显示,我们还可以继续设置该元素的长宽等原本不能设置的属性。同样,我们也可以设置块元素的display属性为display: inline,这样块元素就可以再同一行显示了。

比如如下代码:

<style>
.box {
  border: 2px solid blue;
  background: yellow;
  padding: 5px;
  display: inline; /*将div设置为inline*/
}
.parent {
  padding: 10px;
  border:1px solid green;
  text-align:center;
}
.parent a, .parent span {
  display: block; /*设置为block*/
  margin: 50px;
}
</style>

<div class="parent">
  <span>天码营</span>
  <a href="https://course.tianmaying.com/spring-mvc">Spring MVC实战训练</a>
  <div class="box">12345</div>
  <div class="box">67890</div>
</div>

显示效果如下:



通过把<span>和<a>元素设置为display: block可以让它们各自占据一行;而把<div>元素设置为display:inline可以让它们在一行内排列。对于大部分HTML元素来说,如果设置display:inline,它的高、宽、行高、上下边距就无法设置了。

display还有其它取值,除了block和inline,其中另外两种很常见的取值为:

  • none: 隐藏元素;
  • inline-block:以block的方式渲染,以inline的方式放置;

none是最容易理解的取值。当一个元素的display属性被设为none时,该元素不会被渲染,也不会占位,就像不存在一样。对布局不会产生任何影响。它和visibility属性不一样。把display设置成none不会保留元素本该显示的空间,但是visibility: hidden;还会保留。

display: inline-block修饰的元素称之为行内块元素,它们会像行内元素一样在同一行显示,又可以像块元素一样设置高、宽、行高、边距。

比如在上面的例子中,如果将<div>设置为display: inline-block,我们就可以设置高度和宽度了,如下代码:

<style>
.box {
border: 2px solid blue;
background: yellow;
padding: 5px;
width: 200px; /*div设置为inline-block时,可以设置宽度*/
height: 50px; /*div设置为inline-block时,可以设置高度*/
display: inline-block; /*将div设置为inline-block*/
}
.parent {
padding: 10px;
border:1px solid green;
text-align:center;
}
.parent a, .parent span {
display: block; /*设置为block*/
margin: 50px;
}
</style>

<div class="parent">
<span>天码营</span>
<a href="http://course.tianmaying.com/spring-mvc">Spring MVC实战训练</a>
<div class="box">12345</div>
<div class="box">67890</div>
</div>



设置元素位置:postion属性

目前为止我们已经了解了块元素、行内元素和行内块元素默认的显示方式,它们会按照流的方式从上往下从左往右进行布局,每一个元素都会获得自己的显示位置。如果你希望修改元素默认的定位行为,那就需要position属性了。

postion属性具有如下取值:

  • inhert:规定应该从父元素继承 position 属性的值

  • static:默认值。没有定位,元素出现在正常的流中,会忽略top, bottom, left, right 或者 z-index等移动元素位置的声明

  • relative:相对于元素本身正常位置(即static方式下的位置)进行定位,比如right:10px 会让元素的向右侧移动20 像素

  • absolute:绝对定位,相对于第一个非static的祖先元素进行定位,元素的位置通过 left, top, right 以及bottom 属性进行设置。

  • fixed:生成绝对定位的元素,相对于浏览器窗口进行定位。元素的位置通过 left, top, right 以及 bottom 属性进行规定。

一个HTML网页都可以看成是由一层一层页面元素堆叠起来的,如下图所示:


这里X轴和Y轴定义的是在页面上的位置,而Z轴则定义的是层叠的层次,对应于z-index的值,如果两个元素在XY平面上有重叠,则z-index值大的元素会覆盖值更小的元素。

position: relative 的元素依然在普通流中,位置是正常位置,只不过可以通过设置left、right等属性移动元素,这种移动是会影响其他元素的位置的。

但是对于postion: absolute和position: fixed的元素,具有以下特性:

  • 该元素往 Z 轴方向上移了一层,元素脱离了普通流,所以不再占据原来那层的空间,还会覆盖下层的元素。如果不想覆盖下层的元素,可以减少z-index的值以达到效果。
  • 该元素将变为块级元素,相当于给该元素设置了 display: block;,比如给一个内联元素,如 <span> ,设置 absolute之后发现它可以设置宽高了。
  • 如果该元素是块级元素,元素的宽度由原来的 width: 100%(占据一行),变为了 auto。

如下代码:


<style>
.box1 {
  width: 100px;
  height: 100px;
  margin: 40px auto;
  background: blue;
}
.box2 {
  width: 100px;
  height: 100px;
  margin: 40px auto; 
  background: red;
  position: relative;
  left: 50px;
}
.box3 {
  width: 30px;
  height: 30px;
  background: yellow;
  position: fixed;
  right: 50px;
  bottom: 50px;
}
.parent {
  padding: 10px;
  border:1px solid green;
  text-align:center;
}
</style>
<div class="parent">
  <div class="box1"></div>
  <div class="box2"></div>
  <div class="box3"></div>
</div>

会显示如下效果






  • 蓝色方块为默认定位
  • 红色方块为relative相对定位,相对于默认定位的位置,向右侧移动了50px
  • 黄色方块的fixed定位,始终会出现在页面的右下角(之前你是不是一直奇怪右下角一直有个黄色方块?)。

更复杂的浮动布局:float属性

除了absolute和fixed定位,还有一种方法可以使得元素脱离普通文档流,那就是float属性了。顾名思义,你可以让一个元素在页面流中浮起来,不占据原来元素的空间。

float的取值一共有四个:

  • left:向左浮动
  • right:向右浮动
  • none:不浮动
  • inherit:继承父元素值

设置了float属性的元素具有以下一些特点:

  • 浮动元素的下一个兄弟元素会紧贴到该元素之前的非浮动元素之后;如果下一个兄弟元素如果也设置了同一浮动方向,则会紧随该元素之后显示。
  • 如果该元素的下一个兄弟元素中有内联元素(通常是文字),则会围绕该元素显示,形成类似"文字围绕图片"的效果。
  • 该元素将变为块级元素,相当于给该元素设置了display: block;。

浮动效果

下面我们通过几个例子来看看float会带来什么效果。

我们先来展示三个平铺的<div>:

<style>
.box1 {
  width: 100px;
  height: 100px;
  background: blue;
}
.box2 {
  width: 100px;
  height: 100px;
  background: green;
}
.box3 {
  width: 100px;
  height: 100px;
  background: red;
}
.parent {
  padding: 10px;
  border:1px solid green;
  text-align:center;
}
</style>
<div class="parent">
  <div class="box1"></div>
  <div class="box2"></div>
  <div class="box3"></div>
</div>




可以看到蓝色、绿色和红色方块从上往下排列,典型的块元素排列方式。

现在让我们把蓝色方块设置为float:right,效果如下:





如果将蓝色方块设置为float:left,则蓝色方块会遮挡绿色方块,效果如下:





如果三个方块都向左浮动,设置float:left,效果如下:





注意此时三个方块的父<div>元素是没有高度的,因为三个脱离了普通文档流,父<div>元素此时并没有包含这三个方块。

如果父<div>的宽度不够容纳三个方块,出出现什么情况呢? 我们将parent的width改为250:


<style>
.box1 {
  width: 100px;
  height: 100px;
  background: blue;
  float:left;
}
.box2 {
  width: 100px;
  height: 100px;
  background: green;
  float:left;
}
.box3 {
  width: 100px;
  height: 100px;
  background: red;
  float:left;
}
.parent {
  padding: 10px;
  border:1px solid green;
  text-align:center;
  width: 250px; /*这里设置宽度为250px,无法容下3个100px宽度的方块*/
}
</style>
<div class="parent">
  <div class="box1"></div>
  <div class="box2"></div>
  <div class="box3"></div>
</div>




如果将蓝色方块的高度改为150px,则蓝色方块会挡住红色方块向最左侧浮动,效果如下:





文字环绕效果

如果该元素的下一个兄弟元素中有内联元素(通常是文字),则会围绕该元素显示,形成类似"文字围绕图片"的效果。即虽然浮动会让元素脱离文档流,但是文本内容会受到浮动元素的影响。


<style>
.box1 {
  width: 100px;
  height: 100px;
  background: blue;
  float:left;
}
.box2 {
  width: 200px;
  height: 200px;
  background: green;
}

.parent {
  padding: 10px;
  border:1px solid green;
  text-align:center;
  width: 250px;
}
</style>
<div class="parent">
  <div class="box1"></div>
  <div class="box2">天码营秉承让技术学习更加高效和便捷的使命,致力于打造新一代的技术学习服务平台,提供创新并且专业的内容、工具与服务,帮助学习者与从业者实现个人价值。</div>
</div>




虽然蓝色方块浮动起来覆盖了绿色方块,在绿色方块中的文字并不会被覆盖。

清除浮动

clear属性用以清除浮动带来的影响。比如上一个示例中,为了让绿色方块不被蓝色方块遮挡,可以给绿色方块设置clear: left,即清除向左浮动带来的影响。你还可以用right或both来清除向右浮动或同时清除向左向右浮动,表示元素的哪些边不挨着浮动元素。


<style>
.box1 {
  width: 100px;
  height: 100px;
  background: blue;
  float:left;
}
.box2 {
  width: 200px;
  height: 200px;
  background: green;
  clear: left;
}

.parent {
  padding: 10px;
  border:1px solid green;
  text-align:center;
  width: 250px;
}
</style>
<div class="parent">
  <div class="box1"></div>
  <div class="box2">天码营秉承让技术学习更加高效和便捷的使命,致力于打造新一代的技术学习服务平台,提供创新并且专业的内容、工具与服务,帮助学习者与从业者实现个人价值。</div>
</div>


天码营秉承让技术学习更加高效和便捷的使命,致力于打造新一代的技术学习服务平台,提供创新并且专业的内容、工具与服务,帮助学习者与从业者实现个人价值。

对元素清理实际上为前面的浮动元素留出了垂直空间,这可以解决我们之前的一个问题。三个float:left的<div>因为不会占据空间,因此它们的父<div>高度为0。为了让父<div>包裹住三个方块,可以增加一个空的<div>并设置clear: both;。

<style>
.box1 {
  width: 100px;
  height: 100px;
  background: blue;
  float:left;
}
.box2 {
  width: 100px;
  height: 100px;
  background: green;
  float:left;
}
.box3 {
  width: 100px;
  height: 100px;
  background: red;
  float:left;
}
.parent {
  padding: 10px;
  border:1px solid green;
  text-align:center;
}
</style>
<div class="parent">
  <div class="box1"></div>
  <div class="box2"></div>
  <div class="box3"></div>
  <div style="clear:both;"></div>
</div>





从效果中可以看到,三个色块都包含在父<div>中了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值