CSS

CSS基础-盒模型

This entry is part 7 of the seriesenjoy-css

盒模型概念

在 CSS 中,所有的元素都被一个个的“盒子”包围着,理解这些“盒子”的基本原理,是我们使用 CSS 实现准确布局、处理元素排列的关。

CSS 盒模型是 CSS 中最基本的布局模型,它描述了一个元素在文档中的表现方式。盒模型由内容(content)、内边距(padding)、边框(border)和外边距(margin)四个部分组成。理解盒模型对于前端开发者来说是非常重要的,因为它决定了元素在页面上的布局和空间占用

下面是一个简单的 CSS 盒模型示例:

Code Playground
<style>
.box {
 width: 200px; /* 内容宽度 */
 height: 100px; /* 内容高度 */
 padding: 10px; /* 内边距 */
 border: 5px solid black; /* 边框 */
 margin: 20px; /* 外边距 */
}
</style>
<div class="box"></div>

一个简单的类比

盒装模型理解起来比较复杂,因此用下面类比的方式总结一下所学的内容。

在此图中,有三幅艺术作品安装在墙上,每幅作品都用黑色边框框起来,彼此相邻。

  • 内容区域就是艺术作品。
  • 内边距是指位于框架和艺术作品之间的白色安装板。
  • 边框是一个框架,为图片提供字面边框。
  • 外边距是各个艺术品之间的间距。

开发者工具调试

浏览器开发者工具可以直观呈现选定元素的盒模型,这有助于您了解盒模型的工作原理


接下来,在您自己的浏览器中尝试此操作:

  1. 打开浏览器开发者工具
  2. 选择元素

Box Sizing

box-sizing是CSS中的一个属性,它决定了元素的宽度和高度计算。这个属性有两个主要的值: content-boxborder-box

  • content-box: 默认值,标准盒子模型。width 与 height 只包括内容的宽和高,不包括边框(border),内边距(padding),外边距(margin)。注意:内边距、边框和外边距都在这个盒子的外部。比如说,.box {width: 350px; border: 10px solid black;} 在浏览器中的渲染的实际宽度将是 370px。

    尺寸计算公式:
    width = 内容的宽度
    height = 内容的高度
    宽度和高度的计算值都不包含内容的边框(border)和内边距(padding)。
  • border-box: width 和 height 属性包括内容,内边距和边框,但不包括外边距。这是当文档处于 Quirks 模式 时 Internet Explorer 使用的盒模型。注意,填充和边框将在盒子内 , 例如, .box {width: 350px; border: 10px solid black;} 导致在浏览器中呈现的宽度为 350px 的盒子。内容框不能为负,并且被分配到 0,使得不可能使用 border-box 使元素消失。

    尺寸计算公式:
    width = border + padding + 内容的宽度
    height = border + padding + 内容的高度

可以通过下面一个案例来理解content-boxborder-box👇, 注意观察padding变化造成的影响

padding: 0px
content-box
border-box
.box {
padding: 0px;
width: 500px;
border: 5px solid red;
}

box-sizing 属性的主要用途是改变元素的宽度和高度的计算方式,使得布局更加灵活和容易管理。border-box 通常被认为是更好的选择,因为它使得元素的宽度和高度包括了内容、内边距和边框,这样可以避免布局中的意外偏移。

全局设置border-box

实际开发中,我们可以使用下面代码来强制所有元素使用border-box

css
*,
*::before,
*::after {
box-sizing: border-box;
}

Padding

padding用于设置元素内容区域与边框之间的空间。这意味着,当你为一个元素设置padding时,元素的内容区域会向内缩小。共有四个方向可以设置,分别为 上、下、左、右

48px
48px
48px
48px
content

语法


padding属性可以接受以下几种值:

  • 单个值:设置所有四个方向的内边距
    css
    .box {
    /* 将在元素的上、右、下、左四个方向上都设置10像素的内边距。 */
    padding: 10px;
    }
  • 两个值:第一个值设置上下的内边距,第二个值设置左右的内边距
    css
    .box {
    /* 将上下设置为10像素,左右设置为20像素的内边距。 */
    padding: 10px 20px;
    }
  • 三个值:第一个值设置上的内边距,第二个值设置左右的内边距,第三个值设置下的内边距
    css
    .box {
    /* 将上设置为10像素,左右设置为20像素,下设置为30像素的内边距。 */
    padding: 10px 20px 30px;
    }
  • 四个值:分别设置上、右、下、左四个方向的内边距
    css
    .box {
    /* 将上设置为10像素,右设置为20像素,下设置为30像素,左设置为40像素的内边距。 */
    padding: 10px 20px 30px 40px;
    }
    记住这个顺序的最简单方式是用时钟做类比:

Border

border属性用于设置元素的边框样式、宽度和颜色。边框是元素的一个重要视觉组成部分,它可以帮助用户识别和区分页面上的不同元素。


有三个属性可以设置边框样式,分别是

  • border-width: (eg: 3px, 1em)
  • border-style: (eg: solid, dashed)
  • border-color: (eg: hotpink, black) 它们可以合在一起共用一个属性:
css
.box {
border: 3px solid hotpink;
}

Border radius

CSSWG曾经发布过 Incomplete List of Mistakes in the Design of CSS, 上面记录了CSS设计中的错误不完整列表。其中有一条是关于border-radius的。

border-radius should have been corner-radius

不难理解, border-radius是给元素设置拐角半径的,俗称圆角。这个属性可以让你的元素看起来更加圆润和现代化,特别是在设计带有圆角边框的按钮、卡片或其他用户界面元素时非常有用。

padding一样,border-radius也可以设置四个方位的圆角

Code Playground
<style>
  .box {
    width: 100px;
    height: 100px;
    border: 4px solid hotpink;
    border-radius: 25px;
  }
</style>
<div class="box"></div>
Code Playground
<style>
  .box {
    width: 100px;
    height: 100px;
    border: 4px solid hotpink;
    border-radius: 20px 10px 40px 40px;
  }
</style>
<div class="box"></div>

你也可以使用百分比单位,比如 50% 会将拐角设为圆角。

Code Playground
<style>
  .box {
    width: 100px;
    height: 100px;
    border: 4px solid hotpink;
    border-radius: 50%;
  }
</style>
<div class="box"></div>

Border Style

border-style有很多类型,下面通过一个案例一次性直观的了解这些类型:

solid
dotted
dashed
double
groove
ridge
inset
outset
dashed solid

Border vs Outline

CSS outline 属性用于在元素周围绘制一个轮廓线,这个轮廓线不占用布局空间,也就是说,它不会影响元素的大小或位置。outline 属性是一个简写属性,它可以同时设置 outline-styleoutline-widthoutline-color 这三个属性

Code Playground
<style>
  .box {
    width: 100px;
    height: 100px;
    outline: 4px solid hotpink;
  }
</style>
<div class="box"></div>

其使用场景有以下几种:

  • 聚焦指示:当用户通过键盘导航时,使用 outline 属性来提供视觉反馈,指示哪个元素当前被选中或聚焚。
  • 错误提示:在表单验证时,使用 outline 来突出显示输入错误的字段。
  • 辅助功能:对于视觉障碍用户,使用 outline 可以帮助他们更容易地识别和导航网页。

Margin

margin属性用于设置元素周围的外边距。外边距是元素与其周围元素之间的空间,它可以帮助元素在页面上更好地布局和分隔。

语法

其语法形式和padding如出一辙:

css
.margin {
margin: 20px;
}
.margin {
margin: 20px 30px;
}
.margin {
margin: 20px 30px 40px;
}
.margin {
margin: 20px 30px 40px 50px;
}
.margin {
margin-top: 20px;
margin-right: 30px;
margin-bottom: 40px;
margin-left: 50px;
}

Margin Auto

通常情况下,我们使用px, remem%作为margin的值, 但你知道 margin 属性也接受名为auto的关键字作为值吗?


当在 margin 属性中使用auto关键字时,浏览器会根据元素周围的空间自动计算元素的合适边距。auto 本质上告诉浏览器让元素占用可用空间。

占用可用空间又是什么意思呢?


假设我么有一个div标签(边框为粉色),其内部有一个section标签(背景为橙色, 宽度为100px),就像下面这样👇

Box

如果我将margin-left: auto分配给section,你认为会发生什么呢?

margin: 0 auto
<style>
  .container{
    width: 100%;
    height: 100px;
    border: 1px solid hotpink;
  }
  .box {
    width: 200px;
    padding: 16px;
    text-align: center;
    background: orange;
    margin-left: auto; // 👈
  }
</style>
<div class="container">
  <section class="box">Box</section>
</div>

我们发现,section移动到了最右侧。当使用了margin-left: auto之后,section会将每一点可用空间用于其左边距。


如果我把margin-left: automargin-right: auto同时分配给section, 又会怎样呢?

margin: 0 auto
<style>
  .container{
    width: 100%;
    height: 100px;
    border: 1px solid hotpink;
  }
  .box {
    width: 200px;
    padding: 16px;
    text-align: center;
    background: orange;
    margin: 0 auto; // 👈
  }
</style>
<div class="container">
  <section class="box">Box</section>
</div>

我们发现,section又移动到了水平中间位置。当元素左右两侧margin都设置为auto时,水平方向上的可用空间会被平局分配给左右margin

有两点需要特别注意:

  1. 仅在水平方向,也就是margin-leftmargin-right上使用auto时才会生效。
  2. auto生效的前提是:元素要指定width

负 Margin

Negative margins 是指元素的外边距(margin)设置为负值。这意味着元素的边界会向外扩展。这种技术可以用来实现各种布局效果,如元素重叠、拉伸背景等

margin: 0 auto
<style>
.box {
  position: relative;
  z-index: 1;
  border: 2px solid black;
  width: 100px;
  height: 100px;
  transform: skewY(18deg);
}
.box-2 {
  z-index: 2;
  margin-top: -24px;

  transition: all 300ms ease-in-out;
}
.box-2:hover {
  transform: translateX(-25%) skewY(18deg);
}
</style>
<div>
  <div class="box"></div>
  <div class="box box-2">
    <div style="background: #ffb156a6; height: 24px"></div>
    <div>Hover me!</div>
  </div>
</div>

Margin 合并

元素的上下外边距有时会合并(折叠)为单个边距,其大小为两个边距中的最大值(或如果它们相等,则仅为其中一个),这种行为称为外边距折叠。


只有垂直方向会发生Margin 合并

下面是一个例子

html
<style>
p {
margin-top: 25px;
margin-bottom: 25px;
}
</style>
<p>Paragraph One</p>
<p>Paragraph Two</p>

每个段落都有上下25px的外边距,但是两个段落的间距并不是24px+24px=48px, 而是24px,因为发生了外边距合并。

Paragraph One
Paragraph Two
水平方向Margin不会合并
First
Second

下面是一个在线案例,打开开发者工具,检查margin,你会发现两个段落左右间距为24px + 24px = 48px,证明水平方向上Margin不会合并

margin: 0 auto
<style>
p {
  display: inline-block;
  border: 2px solid black;
  margin: 0px 24px;
}

</style>
<div>
  <p>Paragraph One</p>
  <p>Paragraph Two</p>
</div>

只有相邻元素才会发生Margin合并

如果使用<br />将段落分隔开,则不会发生Margin合并

html
<style>
p {
margin-top: 24px;
margin-bottom: 24px;
}
</style>
<p>Paragraph One</p>
<br />
<p>Paragraph Two</p>
Paragraph One
Paragraph Two

较大值获胜

当段落1的margin-bottom72px而段落2的margin-top24px时,合并后的margin为多少呢?你会发现较大值会获胜

Paragraph One
Paragraph Two

嵌套不会阻断Margin合并

请思考下面代码,

html
<style>
p {
margin-top: 24px;
margin-bottom: 24px;
}
</style>
<div>
<p>Paragraph One</p>
</div>
<p>Paragraph Two</p>

注意高亮部分,我把段落1放到了div内,但这并不会影响两个段落垂直方向上的Margin合并

Paragraph One
<div>
Paragraph Two

padding/border会阻断Margin合并

你可以把paddingborder想象成一堵墙,这堵墙会阻断Margin的合并

Paragraph One
<div>
Paragraph Two
margin: 0 auto
<style>
p {
  margin: 24px 0px;
}

</style>
<div>
  <div style="border: 1px solid black">
    <p>Paragraph One</p>
  </div>
  <p>Paragraph Two</p>
</div>

资源

Questions? Let's chat

discord logoOPEN DISCORD
6423
members online
previous article
CSS基础-字体
next article
CSS布局-文档流

A TypeScript Full Stack Blog

Share articles about Typescript, React, Next.js, Node.js and Css from time to time.
No spam, unsubscribe at any time.