头图

这篇文章,我们学习一个新的布局方法——定位。

定位在网站布局中随处可见,像地图的标记点,电商网站的各种标识和按钮,浮动快捷入口,吸附导航等等效果。

position 属性指定了一个元素定位方式,它有五个不同的类型值:static 静态定位,relative 相对定位,fixed 固定定位,absolute 绝对定位,sticky粘性定位。给元素设置了 position 属性后,再使用 top、bottom、left 和 right 属性对元素进行定位。

我们先来学习相对定位。

position 属性值 relative,可以设置元素为相对定位,相对定位有什么特点呢?我们通过例子来看。

创建 position.html 文件和 position-style.css 文件。打开 html 文件,构建基础代码,引入外部样式。在body里输入 emmet 命令:div.container>(div[class=box$]{盒子$})*3,回车。在一个大的容器里创建了三个小盒子。

HTML
<body>
  <div class="container">
    <div class="box1">
      盒子1
    </div>
    <div class="box2">
      盒子2
    </div>
    <div class="box3">
      盒子3
    </div>
  </div>
</body>

打开 css 文件,定义通用选择器,声明样式 box-sizing: border-box。定义分组选择器 html, body,声明样式 height: 100%,让 html 和 body 撑满整个页面。定义选择器 body,声明样式 margin: 0,去除 body 的外边界。

给外部容器里的三个盒子(.container > div)定义样式: float: left,width: 150px,height: 150px,border: 1px solid black,line-height: 150px,text-align: center,固定的宽高,1 像素的边框,文本水平垂直居中,水平横向排列。

为了消除浮动对其他容器的影响,给 container 定义伪元素(.container::after ),声明样式为:content: "",clear: both,display: block。

再分别给 box1 添加背景颜色 orange,给 box2 添加背景颜色 skyblue,给 box3 添加背景颜色 hotpink。

CSS
* {
  box-sizing: border-box;
}

html, body {
  height: 100%;
}

body {
  margin: 0;
}

.container > div {
  float: left;
  width: 150px;
  height: 150px;
  border: 1px solid black;
  line-height: 150px;
  text-align: center;
}

.container::after {
  content: "";
  clear: both;
  display: block;
}

.box1 {
  background-color: orange;
}

.box2 {
  background-color: skyblue;
}

.box3 {
  background-color: hotpink;
}

到浏览器里看一下效果,三个用来实验的盒子就做好了。

图片

回到 css,我们给 box2 添加样式 position: relative,让它相对定位。

此时,我们发现盒子2没有任何变化。

再回到 css,给 box2 添加样式 left: 50px,top: 50px。

CSS
.box2 {
  position: relative;
  left: 50px;
  top: 50px;
}

再来看效果,盒子2向右和向下各偏移了 50px,并盖在了盒子3的上面。
图片

通过这个实验,我们总结相对定位的几个特点:第一,position: relative ruai 定位样式需要配合 left、top、right、bottom 这些定位属性才能生效。第二,relative 相对的是容器自身的屏幕坐标 0,0 点。第三,容器位置发生位移后,原来占据的空间依然保留。第四,默认会覆盖没有定位的容器。

接下来学习绝对定位。

注释掉相对定位的样式代码。给 box2 添加样式 position: absolute,让它绝对定位。

CSS
.box2 {
  position: absolute;
}

在浏览器里观察效果,盒子1 怎么消失了?原来,当一个容器为绝对定位时,它会脱离文档流,盒子2 盖在了盒子1 的上面。

图片

给 box2 添加样式 left: 50px,top: 50px。

CSS
.box2 {
  position: absolute;
  left: 50px;
  top: 50px;
}

再看看效果,盒子 1 显露出来了,盒子2 向右和向下各偏移了 50px,盖在了两个盒子的上面。
图片

这里有个问题,盒子 2 已经脱离了文档流,它位移坐标的参照点是哪里呢?目前看,它是相对于窗口的屏幕坐标 0,0 点。再做一个实验。

回到 css,给外部容器 container 声明样式 display: inline-block,margin-top: 100px,margin-left: 100px,让它向下向右偏移 100px 的距离。显示属性设置为 inline-block,是为了防止margin 塌陷。

再仔细观察一下效果,盒子2 的确是相对于窗口左上角发生了位移,窗口对应的元素就是body 了。这说明,默认情况下,绝对定位的参照点是 body 元素的坐标起始点。

图片

可以修改绝对定位元素的参照点吗?我们再做一个实验。

回到 css,给 container 添加样式 position: relative,也就是给盒子2 的父元素添加了一个相对定位。

再看一下效果,盒子2 相对于它的父容器定位了。

图片

如果把 container 的定位样式值改为 absolute,效果如何呢?

我们看,盒子2 的位置没有发生变化。这说明,盒子2 定位的参照元素只要设置了定位属性,无论是哪一种定位方式都可以。但 static 静态定位例外,其实,static 表示元素为静态定位,也就是和不给元素添加 position 属性是等价的。

比如,注释掉 container 容器的定位属性。

此时,盒子2 又相对于 body 来定位了。

如果再添加样式 position: static。

效果是一样的。

你可能还会问,绝对定位只参照父元素和 body 来定位吗?我们再做一个实验。

回到 html,在 container 外部再添加一个父元素 div,定义属性。

HTML
<div class="outer">
    <div class="container">
      <div class="box1">
        盒子1
      </div>
      <div class="box2">
        盒子2
      </div>
      <div class="box3">
        盒子3
      </div>
    </div>
  </div>

回到 css,给 outer 添加样式:display: inline-block,width: 600px,height: 500px,background-color: aliceblue,margin-left: 100px,margin-top: 100px,定义最外部容器的宽高,背景颜色,并向右下方设置100px的位置偏移。

CSS
.outer {
  display: inline-block;
  width: 600px;
  height: 500px;
  background-color: aliceblue;
  margin-left: 100px;
  margin-top: 100px;
}

此时,盒子1 和 盒子3 随着整个盒子发生偏移,盒子2 还是相对 body 定位。

注释掉 container 的定位样式,重新设置它为绝对定位。再给 outer 声明一个 position: relative 样式。现在,box2 的父容器和祖先容器都设置了定位,它会参照谁来定位呢?

很显然,盒子2 相对于父容器来定位了

图片

如果注释掉父容器 container 的定位样式。盒子2 相对于祖先元素 outer,还是相对于 body 来定位呢?

答案显而易见,相对于 outer 定位了。

图片
再去掉 outer 的定位样式。盒子2 又相对于 body 定位了。
图片
通过绝对定位的这些实验,我们总结绝对定位的几个特点:第一,绝对定位的元素会脱离文档流。第二,绝对定位的参照点为,有定位设置的离他最近的祖先元素的 0,0 点坐标。第三,绝对定位的容器默认会覆盖没有定位的容器。  接下来学习固定定位。注释掉 box2 的定位相关样式。添加样式:position: fixed,right: 0,top: 100px,定义 box2 为固定定位,位置紧贴参照容器右侧

CSS
.box2 {
  position: fixed;
  right: 0;
  top: 100px;
}

我们发现,容器2 相对于 body 定位了。其实,它只相对于 body 定位。

即使祖先元素有定位,比如打开父容器 container 的定位样式注释。

我们看,容器2 的位置依然不变。你会说,这不是和绝对定位类似嘛,是的,固定定位其实就是绝对定位的特例。那它有什么特殊用途呢?

图片

回到 css,给 body 添加 2000px 的高度。

CSS
body {
  height: 2000px;
}

滚动页面,我们发现:盒子2 仍旧固定不动。

你在浏览器网站时,是不是见过这个效果呢?
通过实验,我们总结固定定位的特点:第一、固定定位的元素是相对于浏览器视口定位的,这意味着即使页面发生滚动,它也始终保持在同一个位置。第二、top、right、bottom和left属性被用来定位元素,但不是必须的。

最后来学习粘性定位。它会产生动态效果,很像 static 和 fixed 的结合:某些状态下是static 定位,某些状态下自动变成了 fixed 定位。

回到 css,注释掉 box2 里的定位样式,添加样式:position: sticky,top: 100px。

静态预览没有效果,滚动一下窗口,也没有啥特殊效果。

一般情况下,粘性定位没有效果,有几个原因:第一、父元素不能添加 overflow: hidden 或者 overflow: auto 属性。第二、元素自身必须声明 top、bottom、left、right 一个或多个属性,否则就相当于静态定位了。第三,父元素的高度不能低于 sticky si tei k定位元素的高度。第四,sticky 定位元素仅在其父元素内生效。

仔细检查一下,应该是第三个原因。父容器如果滚动起来,就能看到效果了。

回到 html,在 body 里添加一个新的 div 容器,定义 属性,填入一些文本。

CSS
<div class="box4">盒子4</div>

回到 css,注释掉 box2 的定位样式。定位选择器 .box4,声明样式:height: 30px,background-color: darkgrey,margin-top: 20px,text-align: center,line-height: 30px,定义容器的基本样式。position: sticky,top: 0,定义容器为粘性定位。

CSS
.box4 {
  height: 30px;
  background-color: darkgrey;
  margin-top: 20px;
  text-align: center;
  line-height: 30px;
  position: sticky;
  top: 0;
}

我们来看一下效果:当滚动页面时,开始一段时间盒子4表现的和普通容器一样,随着页面滚动而滚动,当它距离父容器顶部,到达我们在样式里设置的定位值的时候,这里是 top: 0,就表现为固定定位了。
图片

图片
需要注意,这里的 top: 0,指的是当容器为固定定位状态时,相对于父容器的顶部的距离,并不是容器初始定位。比如,把 top 的值改为 100px。我们看,盒子4 初始位置并没有什么变化。当滚动页面时,盒子4 到达了距离父容器顶部 100px的位置,就固定不动了。

图片
通过实验,我们总结粘性定位的几个特点:第一,粘性定位初始状态相当于 static定位。第二,相对于父容器的定位条件符合时,容器变现为固定定位。第三,top、right、bottom或left 至少声明一个,粘性定位才能生效。

本篇文章配套的教程链接:https://www.bilibili.com/vide...


陆荣涛
28 声望4 粉丝

千锋教育HTML5大前端教研总监