基础布局


行内级元素布局

水平排版

行内级元素的水平排版使用 text-align 属性,它有以下值:

描述
left文本靠左侧对齐
center文本居中对齐
right文本靠右侧对齐
justify文本会在一行内两端对齐,最后一行靠左

【逐项演示】

垂直排版

垂直排版有两个属性:

  • line-height:用来设置元素的行高。
  • vertical-align:用来设置行内级元素垂直方向上的位置。

line-height 属性设置的行高并不属于盒模型的组成部分,它设置的是元素内部文本渲染的高度。

line-height 属性有以下值:

描述
normal默认值,这个值是相对于 font-size 属性和字体样式计算得来的一个合适的行高。这个高度并不等于 font-size 的大小。
长度
百分比100% 等于 font-size 值的大小。

比如:

p {
  line-height: 50px;
}

上面的代码会给 p 元素内的文本行高设置为 50pxline-height 只是设置了元素内部字体所占的行高,IFC 内一行的高度还是可能因为一张巨大的图片撑开。

vertical-align 属性用来设置一个行内级元素在其所在行的垂直位置。它有以下值:

描述
baseline默认值,让元素的基线和父级元素的基线对齐。
middle让元素的中部与父级元素的基线加上父级 x-height 的一半对齐。
top让元素的顶部与所在行的顶部对齐。
bottom让元素的底部与所在行的底部对齐。
text-top让元素的顶部与父级元素字体的顶部对齐。
text-bottom让元素的顶部与父级元素字体的顶部对齐。
super让元素基线提升到父级元素的上标位置。
sub让元素基线降低到父级元素的下标位置。
长度设置元素基线与父级元素基线的长度偏移值,设置为 0 相当于 baseline,10px 则会向上偏移 10px 高度,也可以为负值
百分比设置元素基线与父级元素基线的百分比偏移值,百分比基于当前元素的 line-height 属性计算,也可以设置为负值。

【逐项演示】

  • 关于基线: 基线取决于使用的字体,也就是 font-family 属性,不同字体的相关基线并不一定在相同的位置。 如果把字母写在四线三格中,那么大部分字体的基线应该是从上往下数第三条线。也就是 ‘abcdx’ 等字符的底部。

  • 关于 x-height: x-height 表示字符 ‘x’ 的高度,这是个相对值,会随着 font-size 的值改变而改变。

  • 关于上标和下标: 在 W3C 中,是这样介绍上下标位置的:

    • sub

      降低盒子的基线到父级盒子下标的合适位置(此属性并不会改变元素字体大小)

    • super

      提升盒子的基线到父级盒子上标的合适位置(此属性并不会改变元素字体大小)

    ---W3C

    HTML 中有两个元素 subsup,它们会使文本的排列位置向上或向下进行偏移,比如: H<sub>2</sub>O 会被渲染成:H2O; y = x<sup>2</sup> 会被渲染成:y = x2sub 元素和 sup 元素的 vertical-align 默认值就是 subsuper

缩进

中文段落常常会在首行缩进两个汉字,可以使用 text-indent 属性来实现:

p {
  text-indent: 2em;
}

其中,em 是字体的相对单位,1em 的大小等同于当前元素 font-size 的大小。所以 2em 就是两倍 font-size 的大小。

留白

设置 white-space 属性,可以页面改变渲染时对留白的处理,留白由缩进、空格、换行符等空白符号组成。

学习 white-space 之前,我们需要先整理页面当中可能够发生换行的情况:

  1. 换行符 \n,即回车键输入的符号,记作 ①;默认情况下,这种换行只会在 pre 元素中发生。
  2. IFC 内水平排列超出一行自动产生截断换行,记作 ②;
  3. 插入 <br /> 元素主动截断换行,记作 ③。

现在来了解 white-space 的值:

描述有效的换行
normal默认值,连续的留白会压缩成一个空格。②、③
nowrap类似于 normal,但是文本不会因为水平排列产生截断换行,除非主动插入 br 元素。
pre原样渲染,保留所有留白(水平排列不会自动产生换行,pre 元素的默认样式)。①、③
pre-wrap类似于 pre 元素,但是水平排列会自动产生换行。①、②、③
pre-line每行内连续留白会压缩成一个空格,保留所有换行。①、②、③

【逐项演示】

文本溢出

可以使用 text-overflow 属性来设置文本的溢出样式,这个属性有以下值:

描述
cilp默认值,溢出部分被剪裁
ellipsis溢出显示为省略号

但是需要强调的是,只有横向溢出,并且是 white-space 属性设置为 nowrap 时产生的溢出,text-overflow 属性才会生效。

所以下面三行代码需要同时设置,才能设置横向溢出样式:

.text {
  /* 设置盒模型溢出隐藏 */
  overflow: hidden;
  /* 设置文本不换行排列 */
  white-space: nowrap;
  /* 设置文本水平溢出时显示为省略号 */
  text-overflow: ellipsis;
}

上述代码在业界常被称作 文本三件套

定位布局

通过设置元素的 position 属性,可以改变其在文档中的定位方式,例如把一个块级元素定位到页面的左侧形成导航栏,或者把一段文字定位到父级元素的边框区域等,这些布局方式都可以使用 position 属性定位实现。

position 的有以下值可供使用:

定位方式描述
static静态定位默认值,元素会随着文档流排列,无法进行偏移
relative相对定位元素会 相对于在文档流中原本的位置 进行偏移
fixed固定定位元素会 相对于视口 区域(窗口,也可能是一个 iframe 区域)进行偏移
absolute绝对定位元素会 相对于最近的非静态定位父级元素的内容边界 进行偏移
sticky粘性定位元素 根据 最近的滚动祖先和包含块(最近的块级元素祖先)进行偏移,这是一个 CSS3 的属性

相对定位与偏移

偏移值:

给一个元素设置相对定位后,可以通过设置 topbottomleftright 四个属性设置元素相对与定位参考位置的偏移量。

例如:

.foo {
  position: relative;
  top: 10px;
  right: 10px;
}

上述代码中,类名含有 foo 的元素会进行相对定位,元素会相对默认情况下的原始位置进行定位,声明 top: 10px; 会让元素距离原始位置顶部偏移 10 像素,声明 right: 10px; 会让元素距离原始位置的右侧偏移 10 像素。

关于偏移量

偏移量的设置对静态定位元素无效,对其他定位方式都有效。

负值偏移量:

偏移量可以设置为负值,会采取相反方向的偏移。比如:

<style>
  .foo {
    position: relative;
    left: -100px;
  }
</style>
<div class="foo">相对原本位置从左侧偏移 -100px</div>

固定定位

固定定位的元素参考视口进行定位,固定定位的元素不会跟随页面滚动,被钉死在了视口上。

固定定位和绝对定位的元素都有以下特性:

  • 元素会脱离当前文档流;
  • 元素会形成新的 BFC 布局区域, 也就是产生新的纵向布局环境;
  • 元素的盒子会改变为块级元素, 比如给 span 或者 input 这样的默认行内级元素进行固定定位或者绝对定位,它们的盒子会转化为 block
  • 固定定位或绝对定位的元素虽然是块级元素,但是它们脱离了文档流,并不会表现为独占一行。

示例:

<style>
  .foo {
    position: fixed;
    bottom: 100px;
    right: 20px;
    width: 100px;
    height: 100px;
    background-color: silver;
  }
</style>
<div class="foo">元素被放到距离视口底部 100px 右侧 20px 的位置</div>

固定定位元素的宽高显示方式很多:

  • 默认情况下,固定定位的元素宽高由内容撑起;
  • 如果设置了偏移值,那么会根据偏移值拉伸元素的宽高;
  • 也可以直接设置 widthheight 属性,确定元素的宽高。

上列情况并不完全适用于表单相关元素,例如输入框,按钮等,表单元素固定定位后也会拥有初始样式,比如初始宽度,所以并不一定会随着偏移值进行变化。

示例:

<style>
  .foo,
  .bar,
  .baz {
    position: fixed;
  }
  .foo {
    top: 0;
    left: 0;
    background-color: silver;
  }
  .bar {
    left: 100px;
    right: 100px;
    top: 20%;
    bottom: 70%;
    background-color: tomato;
  }
  .baz {
    bottom: 0;
    right: 0;
    height: 100px;
    width: 100px;
    background-color: skyblue;
  }
</style>
<div class="foo">foo 默认大小,由内容撑起</div>
<div class="bar">bar 通过偏移值确定大小,大小会随着页面进行拉伸</div>
<div class="baz">baz 直接限制大小</div>

固定定位有一个很特殊的居中方式,就是当水平方向上的偏移量设置为 0,并且水平方向上的外边距为 auto 的时候,元素会产生水平居中效果,垂直方向同理。如果同时设置了水平和垂直居中,那么元素就会在视口的中央。

比如:

<style>
  div {
    line-height: 100px;
    height: 100px;
    width: 100px;
    text-align: center;
    background-color: silver;
  }
  /* 水平居中 */
  .foo {
    position: fixed;
    top: 0;
    bottom: 0;
    margin: auto 0;
  }
  /* 上下居中 */
  .bar {
    position: fixed;
    right: 0;
    left: 0;
    margin: 0 auto;
  }
  /* 正中间居中 */
  .baz {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;
  }
</style>
<div class="foo">foo</div>
<div class="bar">bar</div>
<div class="baz">baz</div>

视口是什么?

视口(viewport)可以简单的理解为浏览器的窗口区域,又或者一个 <iframe> 元素的内容边界,相关内容被我分到 CSS3 的讲义中,你可以点击以下链接提前了解:

绝对定位

绝对定位和固定定位的特性和规则完全一样,只是参考的位置不同。

诸如固定定位的宽高设置,居中效果,对于绝对定位也完全适用,只是需要改变定位参考的位置。

绝对定位的元素会参考最近的 position 不是 static 的祖先定位(即最近的非静态定位祖先元素),如果没有,则参考的是页面第一页来定位,不管如何定位,都会跟随页面或元素滚动。

<style>
  .foo {
    position: relative;
    left: -100px;
    width: 500px;
    height: 500px;
  }
  .bar {
    position: absolute;
    bottom: 0;
    right: 0;
  }
</style>
<div class="foo">
  <div class="bar">相对最近的非静态定位祖先元素定位,跟随页面或元素滚动</div>
</div>
<div class="bar">相对最近的非静态定位祖先元素定位,跟随页面或元素滚动</div>

大部分情况下,绝对定位都会配合一个相对定位一起使用,比如:

<style>
  #fieldset {
    position: relative;
    padding: 10px 20px;
    border: 1px solid silver;
  }
  #legend {
    position: absolute;
    top: -10px;
    left: 20px;
    height: 20px;
    background: white;
    padding: 0 10px;
  }
</style>
<div id="fieldset">
  <span id="legend">说明</span>
  <input type="text" />
</div>

因为 #fieldset 元素为相对定位,可以其作为 #legend 元素的定位参考,从而实现相对父级进行定位,上述代码就简单模拟了 fieldsetlegend 的默认样式。

这种方式不仅限于父子级,还可以应用到祖孙级等更复杂的嵌套关系当中。

粘性定位

粘性定位的元素会在其包含块范围内,相对于它最近的滚动祖先进行偏移。

粘性定位元素的包含块是那个区域?

粘性定位元素的包含块就是最近的块级元素祖先的内容边界。

什么是滚动祖先?

滚动祖先被视作拥有滚动机制的祖先元素,即元素的 overflowhiddenscrollauto 等值时,算作一个滚动祖先。

粘性定位的元素定位方式非常特殊,它并不一定会在一开始就相对于最近的滚动祖先进行定位,在完全阐述它的定位之前,我们需要准备一些区域和规则:

  • 把粘性定位的包含块记作 A;
  • 把粘性定位元素最近的滚动祖先的可视滚动区域减去四个方向上的偏移量得到区域记作 B(偏移值如果出现冲突依旧是 left 或者 top 优先,某个方向上没有设置偏移值的话则使用滚动祖先的内容边界充当该方向上的边界,比如所有偏移值都不设置时,区域 B 相当于滚动祖先的整个内容区);

那么粘性定位元素的位置是:

  • 当元素处在区域 B 和 A 里面时,元素会进行静态定位;
  • 当滚动祖先发生滚动让元素处在区域 B 或者 A 的边缘时,元素会粘在区域 B 或 A 的边缘,并优先停靠在区域 A 的边缘。

示例:

<body>
  <style>
    .foo {
      position: sticky;
      top: 50px;
      width: 100px;
      height: 100px;
      background-color: tomato;
    }
    .bar {
      width: 200px;
      height: 500px;
      background-color: teal;
    }
  </style>
  <div class="bar">
    <div class="foo">此元素的包含块是父级元素的内容边界</div>
  </div>
  <div class="foo" style="margin: 20px 0">此元素的包含块是 body 元素的内容边界</div>
  <div style="height: 2000px"></div>
</body>

粘性定位是一个 CSS3 的属性,适配所有移动设备上的浏览器,但是并不是兼容老旧浏览器,比如 IE。

层叠

定位元素之间有可能会因为偏移重叠在一起,默认情况下,定位元素都会覆盖原始文档流中的元素。

可以通过 z-index 属性可以设置定位元素之间的覆盖优先级,z-index 属性又称 层级,层级对静态定位的元素无效

z-index 属性不是定位元素独有的,比如 opacity 属性不为 1 时也可以使用层级。

z-index 属性有以下值:

描述
auto默认值
整数值值最大的定位元素显示到最前,按 z-index 大小堆叠

例如:

<style>
  .foo {
    position: fixed;
    top: 0;
    left: 0;
    width: 200px;
    height: 200px;
    background: red;
  }
  .bar {
    position: absolute;
    top: 0;
    left: 0;
    width: 100px;
    height: 100px;
    background: silver;
  }
</style>
<div>普通文本</div>
<div class="foo"></div>
<div class="bar"></div>

默认情况下,定位元素都会覆盖当前文档流中的元素,给上面选择器添加以下两个声明:

.foo {
  z-index: -100;
}
.bar {
  z-index: -50;
}

此时它们将不再继续覆盖文档流中的元素,不同层级的元素会依次进行覆盖,千万记住,层级对静态定位元素无效

层叠上下文

元素因为样式产生相互覆盖时,元素会产生层叠上下文,层叠上下文的层级大的元素会优先显示。

层叠上下文的产生条件如下:

层叠上下文的特性:

元素会相对最近的产生层叠上下文祖先进行层级设置

示例:

<style>
  #foo,
  #bar,
  #baz {
    position: fixed;
    top: 0;
    right: 0;
    width: 200px;
    height: 200px;
  }
  #foo {
    z-index: 1;
    background-color: tomato;
  }
  #bar {
    z-index: 99999;
    background-color: skyblue;
  }
  #baz {
    z-index: 2;
    background-color: silver;
  }
</style>

<div id="foo">
  <div id="bar"></div>
</div>
<div id="baz"></div>

上诉代码中,屏幕上最终会显示一个黑块,#baz 排到了最前。#bar 元素的层级虽然是 1000,但是依旧无法突破到最前。这是因为其父级的层级小于 #baz的层级,而 #bar 被限制在 #foo 的层叠上下文中,无法越级。

如果把层叠上下文的嵌套关系分出等级,那么上面三个元素的所处的层叠上下文和层级如下:

元素一级层叠上下文层级二级层叠上下文层级
#foo1
#bar199999
#baz2

虽然 #bar 元素的在二级层叠上下文中的层级是 99999,但是它所处的一级层叠上下文层级是 1,所以无法对 #baz 元素进行覆盖。

浮动布局

浮动布局可以让文本图片(行内级元素)环绕另一个元素布局,通过给元素设置 float 属性来让元素浮动。

float 属性有以下值:

描述
none不浮动,默认值
left使元素浮动在左侧
right使元素浮动在右侧

【逐项演示】

浮动元素的特性

浮动元素有以下特性:

  • 浮动元素会靠左或者靠右排列,视 float 属性的值而定。

  • 浮动元素会自动转化为块级元素,比如让一个 span 元素浮动,那么它的盒子会改变为 block

  • 浮动元素周围的文本会环绕浮动元素排列;(不论文本与浮动元素是相邻或是间隔)

  • 浮动元素会浮动在在块元素之上,在布局上块级元素会无视浮动元素,在渲染上块级元素会被浮动元素覆盖;

  • 浮动元素不能撑起父级的高度。

  • 浮动元素会漂浮在文档流之上,不会遵循 BFC 和 IFC 的规则,所有没有独占一行,外边距重叠等特性,甚至没有行的概念。

  • 浮动元素带来的影响并不会干扰到其他的 BFC 区域。

示例:

<style>
  .main {
    width: 600px;
    margin: auto;
  }
  .foo {
    float: left;
  }
</style>
<div class="main">
  <h1>荷塘月色</h1>

  <div>
    <img src="./img.png" class="foo" alt="" />
  </div>
  <p>
    这几天心里颇不宁静。今晚在院子里坐着乘凉,忽然想起日日走过的荷塘,
    在这满月的光里,总该另有一番样子吧。月亮渐渐地升高了,墙外马路上孩子们的欢笑,已经听不见了;妻在屋里拍着闰儿,迷迷糊糊地哼着眠歌。我悄悄地披了大衫,带上门出去。
  </p>
</div>

上面代码中,img 元素设置了浮动,它没有撑起父级 div 的高度;p 的布局并没有受到浮动影响,但是其内部的文字会环绕浮动元素布局。

浮动元素之间的影响

  • 浮动方向相同的元素会按照浮动方向依次排列;
  • 因为浮动元素是漂浮在文档流之上的,并不遵循 BFC 的布局规则,所以:
    • 浮动元素没有换行的概念,横向溢出的浮动元素会最少限度的向下排列,并不一定是换行;
    • 浮动元素之间不会产生外边距重叠;

比如:

<style>
  .main {
    width: 300px;
  }
  .foo {
    float: left;
    border: 1px solid black;
    background-color: silver;
  }
  .foo50 {
    width: 50px;
    height: 50px;
  }
  .foo70 {
    width: 70px;
    height: 70px;
  }
  .foo100 {
    width: 100px;
    height: 100px;
  }
</style>

<div class="main">
  <div class="foo foo100">1</div>
  <div class="foo foo50">2</div>
  <div class="foo foo50">3</div>
  <div class="foo foo70">4</div>
  <div class="foo foo70">5</div>
  <div class="foo foo100">6</div>
  <div class="foo foo100">7</div>
</div>

如果多个浮动连续排列它会尽可能的朝同一个方向排列,一般情况下并不会让不同大小的元素浮动到一起,虽然浮动被用来让文字环绕布局,但是也通过上述排列方法来渲染横向列表,比如:

<style>
  .foo {
    padding: 0;
    list-style: none;
  }

  .foo li {
    float: left;
    line-height: 50px;
    width: 120px;
    text-align: center;
    margin: 10px;
    background-color: silver;
  }
</style>
<ul class="foo">
  <li>content 1</li>
  <li>content 2</li>
  <li>content 3</li>
  <li>content 4</li>
  <li>content 5</li>
</ul>
<p>这里的文字会环绕这个列表布局</p>

清除浮动

如果浮动元素对周围的块级元素(非父级或祖先的块级元素)产生了覆盖,可以使用 clear 属性让该块级元素向下移动到浮动元素的下方。

clear 属性它有以下值:

描述
none不清除浮动,默认值
left将元素向下移动,直至清除左侧浮动
right将元素向下移动,直至清除右侧浮动
both将元素向下移动,直至清除两侧浮动

当应用于非浮动块时,它将非浮动块的边框边界移动到所有相关浮动元素外边界的下方。这个非浮动块的垂直外边距会折叠。

另一方面,两个浮动元素的垂直外边距将不会折叠。当应用于浮动元素时,它将元素的外边界移动到所有相关的浮动元素外边框边界的下方。这会影响后面浮动元素的布局,后面的浮动元素的位置无法高于它之前的元素。

---MDN clear

关于外边界和边框边界和折叠:

  • 外边界:即 margin 的边缘;
  • 边框边界: 即 border 的边缘。

上述所讲的折叠并不是 BFC 环境中的外边距重叠,两者并没有关系。

清除浮动的方式有两种。

  • 从兄弟元素上清除

  • 从父元素上清除,使用伪元素

    .float-root::after {
      content: "";
      display: block;
      clear: left;
    }
    

小结

大部分布局都和文档流、BFC 和 IFC 环境相关,可以回顾盒模型与文档流章节后再理解本节内容,如果你有新的发现或者疑惑,那么你有了更多的收获,下一节将讲述常规流和各种布局之间的关系。