网页开发入门|09 盒模型

W3C标准中把每个元素都看作是一个小盒子,从而处理元素间的边距问题。

网页开发入门|09 盒模型

在上节课,我们了解了如何在网页中设定颜色。通过准确的设定颜色,文章页面的配色看起来和谐多了。

校正颜色过后的成稿
校正颜色过后的成稿

本节课来解决边距和间距的问题。

原本的设计稿
原本的设计稿

对比设计稿,我们目前的成稿中有三处明显距离问题:

  1. 标题与段落,以及段落之间的间距;
  2. 作者名和朝代的间距;
  3. 标签中字与背景框的边距。

盒模型Box model

CSS中是使用盒模型box model来处理边距问题的。

什么是盒模型呢?

W3C标准中把每个元素都看作是一个小盒子,就下面这样:

两个相邻的首饰盒
两个相邻的首饰盒

盒子与盒子之间的距离称作外边距margin,盒子里装的东西与盒子边之间的距离称作内边距padding,盒子里装的东西称作内容content,盒子本身的外壳称作边框border

与上面图中的首饰盒不同的是,在页面中的元素都是二维的,把盒子拍扁之后就是这样:

盒模型
盒模型

如图,内边距padding、边框border、外边距margin,围绕内容content在上下左右四个方向存在,且都可以有一定的尺寸(可以理解为厚度)。

随着技术的发展,对盒模型的理解有两个版本,一个是早期的IE版的盒模型,一个是如今的标准盒模型,主要的区别是对元素宽度的理解不同。

在IE浏览器的年代,元素的宽度width指的是包含了边框的元素的宽度,而在现代浏览器中,元素的宽度width指元素中内容的宽度。

其实这两种盒模型之间是可以相互换算的,但后者逐渐成为了今天的主流,可能是因为今天的开发者更关心的是盒子里面装的内容的尺寸,而不是盒子本身的尺寸吧。

本教程中强烈推荐大家使用Edge或Chrome浏览器,所以我们会使用标准盒模型,即把元素宽度理解为内容的宽度。

盒模型的代码实现

让我们新建一个box.html来看看盒模型的效果,代码如下:

<head>
    <style>
        div {
            margin: 20px;
            border: 2px solid red;
            padding: 20px;
            width: 100px;
            background-color: lightgray;
        }
    </style>
</head>
<body>
    <div>hello, world!</div>
</body>

CSS代码中,我们设置了margin,border,padding,width,background-color五个属性,可以在图中看到他们的效果:

  • margin是这个元素与周围其他元素之间的距离,因为左侧和上侧是浏览器的边框,右侧和下方并没有其他的元素,所以左侧和右侧看起来窄一些,实际的距离就是代码中设定的20px;
  • border我们设定为了2px宽的红色实线(solid),这是我们第一次遇到需要多个值的样式属性,多个属性之间需要使用空格隔开;
  • padding使得边框在上下左右所有方向上都距离内容有20px,但因为content中文字的实际宽度不到100px,所以看起来文字距离左右两侧边框的距离并不一致;
  • width只能对块元素设定,行内元素的width会永远和里面内容的保持一致;
  • background-color的有效范围是包含padding部分的。

如果我们只需设置上下左右其中一个方向的margin,border,padding,有两种方法设定。

以值设定左padding为例:

方法一,直接使用更准确的样式属性padding-left

div {
  padding-left: 20px 
}
只剩下左边距
只剩下左边距

方法二,以上、右、下、左的顺序,分别写出四个方向具体的值,以空格隔开:

div {
  padding: 0 0 0 20px;
}

如果我们想只区分上下和左右的话,还可以写两个值:

div {
  padding: 0 20px;
}
左右边距
左右边距

如果在配合上单方向边框,还会有些特别的效果。

div {
  padding: 0 20px;
  border-bottom: 2px solid red;
}
看起来像下划线或强调
看起来像下划线或强调
div {
  padding: 0 20px;
  border-left: 2px solid red;
}
只设置左边框,会有字幕或者标题的感觉
只设置左边框,会有字幕或者标题的感觉

块元素的调整

让我们先来解决目前成稿中块级元素之间的边界问题。

为了不影响之前已经生效的代码,建议再复制一下上节课peom4.htmlpoem5.html,在新文件中改造它。

为了方便使用CSS选择器,咱们先给页面中的一些主要部分添加一下id属性,必要的地方还会套一层div标签:

<body style="font-family: STKaiti, KaiTi">
  <h1 id="title">登鹳雀楼</h1>
  <div id="author" style="font-size: 0.9em;">
    <!-- 此处省略部分代码 -->
  </div>
  <hr>
  <div id="content">
    <p>白日依山尽,黄河入海流。</p>
    <p>欲穷千里目,更上一层楼。</p>
  </div>
  <div id="tag" style="font-size: 0.9em; font-family: STSong, SimSun">
    <!-- 此处省略部分代码 -->
  </div>
  <p id="photo">
    <img src="assets/王之涣.jpg" alt="王之涣" />
  </p>
</body>
标题、作者朝代、正文段落都是块级元素
标题、作者朝代、正文段落都是块级元素

块级元素都是独占一行的,所以对边距的调整更多是来调整元素间在垂直方向上的距离。

目前设计稿中的这些块级元素,都没有画出边框,也没有背景色,所以从代码实现的角度来说,无论使用padding或者margin都可以调整元素间的距离,完全看不出来区别。

但我们更加推荐使用margin来定义元素间的间距,padding更适合实现每个元素自己的样式,比如缩进等效果。这也是外边距和内边距原本的含义。

更好的办法还是以设计师给出的设计稿为准。

设计稿中应该明确的定义内外边距的数值
设计稿中应该明确的定义内外边距的数值
作为一个开发向的课程,我们不展开如何从设计稿中获取各元素的样式信息的办法,因为这与设计师所使用的设计软件有关。我们假设已经从设计师处了解到了具体的数值了。

废话不多说,直接上代码。

/* 省略无关代码 */
#title {
  margin: 13.4px 0;
  padding: 0 5px;
}

#author {
  margin: 10px 0;
}

#content {
  margin: 15px 0 5px 0;
  padding: 0 5px;
}

#content p {
  margin: 5px 0;
}

#tag {
  margin: 13px 5px;
}

行内元素的调整

目前页面里需要修改的行内元素是a,需要调整作者名后面的间距,以及标签部分的每个标签的样式。

与块级元素不同,行内元素会排列在同一行内,所以对行内元素的调整更多的是水平方向的调整。

与块级元素相似,元素间的间距调整应该使用margin,每个元素自己的效果,应该使用内边距。

同样,我们直接以设计师给出的参数,对这些a元素的效果进行调整:

/* 省略无关代码 */
#author a {
  margin-right: 30px;
}

#tag a {
  background-color: #f1f2f6;
  margin: 2px 5px;
  padding: 2px 5px;
}
调整了超链接的间距
调整了超链接的间距

行高

调整完了内外边距,我们发现在垂直方向显得更加的紧凑了,行与行之间的距离怎么比设计稿里又小了呢?是我们调整错了参数么?

当然不是啦!行间的间距变小了是因为影响垂直方向间距的,还有一个重要因素——行高line-height

让我们回到box.html中,将div的宽度设置为50px

div {
    margin: 20px;
    border: 2px solid red;
    /* padding: 0 20px; */
    width: 50px;
    background-color: lightgray;
}
将宽度设置为50px,自动换行了
将宽度设置为50px,自动换行了

因为50px不足以在一行内排列整个句子,所以发生了自动换行。可以清楚的看到,行与行之间并没有紧紧的挨在一起,而是出现了一个空隙。

行间的空隙
行间的空隙

同时请注意,我们在代码中明确的取消了padding效果,但是hello, world!距离上下边缘还都有一定的距离。

内容与边框间的空隙
内容与边框间的空隙

带来这两个地方空隙的就是行高。

如果行内的字比行高要大,实际的行高就是字的高度;如果行内的字比行高要小,多出来的行高将均匀的分布在字的上下方。

行高
行高

因为行高有这样的特性,所以通常有两个作用:

  1. 用于多行的元素,设定行间距,提升阅读体验;
  2. 用于单行的元素,使其内容在垂直方向上居中。

好了,了解了行高的作用,让我们回到poem.html,根据设计稿把行高属性也设定进去:

/* 省略无关代码 */
body {
  line-height: 1.5em;
}

#author {
  line-height: 19px;
}

#content p {
  line-height: 25px;
}

延伸阅读:用盒模型绘图

通过设定元素的盒模型属性,可以在页面中绘制一些图形。

矩形

绘制矩形比较容易,设定好元素的宽、高、背景色即可。

<style>
  .rectangle {
    width: 100px;
    height: 50px;
    background: red;
  }
</style>

<div class="rectangle"></div>

圆角矩形

边框还有设定圆角能力,可以将矩形设定为圆角矩形。

<style>
  .round-rectangle {
    width: 100px;
    height: 50px;
    background: red;
    border-radius: 20px;
  }
</style>

<div class="round-rectangle"></div>

椭圆/圆

当圆角矩形的圆角尺寸刚好是所在边的一半,就可以形成一个椭圆形。

<style>
  .oval {
    width: 100px;
    height: 50px;
    background: red;
    border-radius: 50%;
  }
</style>

<div class="oval"></div>

当然,如果原本是个正方形,那就可以得到一个圆形。

<style>
  .circle {
    width: 50px;
    height: 50px;
    background: red;
    border-radius: 50%;
  }
</style>

<div class="circle"></div>

三角形

借助边框的能力,还可以绘制出三角形。

对一个宽高都为0的元素,四个方向边框加上不同的颜色,可以得到这样的图形。

<style>
  .colorful-border {
    width: 0px;
    height: 0px;
    border-left: 50px solid red;
    border-right: 50px solid yellow;
    border-top: 50px solid green;
    border-bottom: 50px solid blue;
  }
</style>

<div class="colorful-border"></div>

如果我们只保留一遍的颜色,然后其余边框设为透明,即可得到三角形。

<style>
  .triangle {
    width: 0px;
    height: 0px;
    border-left: 50px solid red;
    border-right: 50px solid transparent;
    border-top: 50px solid transparent;
    border-bottom: 50px solid transparent;
  }
</style>

<div class="triangle"></div>

画出这些形状与什么用呢?

其实用的地方还蛮多的,很多页面中的小细节都是靠这些能力实现的。比如微信聊天的气泡,就是一个小三角和一个圆角矩形的结合。

我将本课程所有的代码托管在gitee上了,你可以点击这个链接,或到gitee.com上搜索弦五 网页开发入门,查看和获取本课程的全部代码。