网页开发入门|11 定位

Word中的图片会随着文本内容的变化跟着移动,而PowerPoint中的图片则不会,这就是图片的“定位”。

网页开发入门|11 定位

在上节课的最后,我们遗留下来了三个问题,其一便是下图中的这个小红点。

动态右上角的小红点
动态右上角的小红点

把未读消息标记为小红点已经成为设计中的惯例,我们会在大量的网页或者APP上看到类似的设计。

微信读书的底部Tab
微信读书的底部Tab

有些时候还会显示出具体的数字。

iOS中的未读消息
iOS中的未读消息

还有的时候还会显示出文字,甚至形状也不再是圆的。

天猫首页
天猫首页

这些小红点学名称作徽章Badge,是一种常见的装饰,通常用来提醒用户,图标或者按钮这里有一些特别的东西可以关注。

徽章有时还会出现在另外三个角落上,以应对更丰富的场景。

比如提醒用户换头像:

即刻APP
即刻APP

展示用户的尊贵身份:

微博热搜
微博热搜

游戏中标记人物等级或者状态:

魔兽世界
魔兽世界

但不论徽章是什么样子,用于什么目的,它都需要重叠在它要装饰的元素上。

我们知道可以用块级元素block实现垂直排列元素,也知道了使用行内块级元素 inline-block进行水平排列,但是如何把元素叠在一起呢?

本节课就让我们来解决这个重叠的问题。

文档流Normal Flow

两个元素叠在一起,说明这两个元素所在的位置发生了重合,所以我们需要重新思考一下,网页上的各个元素为什么会在现在的位置上。

网页中各元素的位置在默认的情况下,都是按照HTML代码里的书写顺序,在不发生遮盖的情况下,尽可能的靠上(块级元素)、靠左(行内元素)显示。

也就是说每个元素的位置取决于上一个元素的位置,而不是自己决定自己的位置。

我们可以通过分别在WordPowerPoint中插入图片来感受一下两者区别。

Word中的图片会随着文本内容的变化跟着移动。

word文档中的图片会随着文字内容移动
word文档中的图片会随着文字内容移动

PowerPoint中的图片则不会随着别的内容修改而改变自己的位置。

ppt文档中的图片不会随着文字内容移动
ppt文档中的图片不会随着文字内容移动

网页中元素的位置更接近在Word文档中的这种,当前面的内容删除了之后,后面的内容会自动补充过去,就好像是流水一样,哪里低就流向哪里。所以,称作文档流Normal Flow

水会自动的往低处流动
水会自动的往低处流动

绝对定位

元素的样式属性「定位」position,可以告诉浏览器是否将元素从文档流中拿出来单独处理。

设置position: absolute绝对定位,就是一种让元素从文档流中脱离出来的方法。绝对定位的元素将保持在页面某个位置上,出现类似PowerPoint中的效果。

让我们创建一个新文件position.html,然后体验一下。

<div class="absolute">
    <img src="assets/icon.png">
</div>
<div class="greeting">欢迎关注弦五说!!</div>
.absolute {
    position: absolute;
}
绝对定位的图片挡住了背后的文字
绝对定位的图片挡住了背后的文字

因为图片变成了绝对定位的元素,所以它脱离了文档流。原本应在图片下一排显示的文字,不再被图片影响,从而显示在了图片原本的位置,两个元素的位置相同,从而引发了重叠。

绝对定位的元素默认会呆在它原本在文档流中的位置,如何调整它的位置呢?

这需要使用leftrighttopbottom4个样式属性,用来指明元素的位置距离文档的4个边缘多远。

上下左右「外边距」边沿距离页面边缘的距离
上下左右「外边距」边沿距离页面边缘的距离
.absolute {
    position: absolute;
    left: 25px;
    top: 40px;
}
使用left和top调整绝对定位元素位置
使用left和top调整绝对定位元素位置

通常,我们只需在leftright这一对中选取一个进行设定,没有必要同时设定两个。topbottom也是类似的情况。

即使我们同时设定了两个,其实也只会有一个生效,具体是哪个生效取决于文档流的方向,在一般情况下 lefttop具有更高的优先级。

绝对定位适合用于排版准确度要求比较高,且内容相对明确的页面,比如产品的官网、邀请函等。

iPhone的官网
iPhone的官网

但用绝对定位来实现徽章却不太方便:徽章只是用来装饰,我们不能要求被装饰的对象也一起成为绝对定位的元素。如果原本要被装饰的对象依然是在文档流中的,一旦被装饰的对象随着文档流发生变化,徽章就很难跟着同步移动了。

固定定位

还有的时候,我们不是要将元素的位置固定在在页面中的某处,而是要相对于浏览器窗口来定位。

比如,给用户弹出的对话框,无论用户目前阅读到了页面的哪里,都需要在整个浏览器窗口里居中。

花瓣网的登录弹窗,在浏览器窗口居中
花瓣网的登录弹窗,在浏览器窗口居中

这种定位方法叫做固定定位,对应的position: fixed

​固定定位的元素同样会脱离文档流,也使用leftrighttopbottom4个样式属性,用来标记元素的位置应该距离浏览器窗口的4个边缘多远。

看一下效果。

<div class="fixed">
    <img src="assets/icon.png">
</div>
.fixed {
    position: fixed;
    right: 25px;
    top:40px
}
图片固定在浏览器右下角,位置随着浏览器窗口调整而改变
图片固定在浏览器右下角,位置随着浏览器窗口调整而改变

固定定位因为会跟着浏览器窗口移动,没有办法准确的停在某个元素附近,就更不适合实现徽章了。

相对定位

除了绝对定位和固定定位还有一种相对定位的方法,对应的position: relative

将元素设定为相对定位时,元素将依然存在于文档流中,这时leftrighttopbottom4个样式属性,让元素偏离原本所在的位置。

<div class="greeting">欢迎关注弦五说!!</div>
<div class="greeting">欢迎关注弦五说!!</div>
<div class="greeting">欢迎关注弦五说!!</div>
<div class="relative">
    <img src="assets/icon.png">
</div>
<div class="greeting">欢迎关注弦五说!!</div>
<div class="greeting">欢迎关注弦五说!!</div>
<div class="greeting">欢迎关注弦五说!!</div>
.relative {
    position: relative;
    left: 25px;
    top: 40px;
}
相对定位元素以它原本在文档流的位置为基准,发生位移
相对定位元素以它原本在文档流的位置为基准,发生位移

相对定位能实现元素的重叠的同时,还能跟着文档流流动,比较适合实现徽章。

但相对定位也有一个不尽如人意的地方:因为相对定位的元素并没有脱离文档流,尽管它显示的位置发生了偏移,但它依然占据着文档流中原本的位置,这导致原本的位置会显示出一个空白区域。

图片原本的位置仍然被占用,显示为空白
图片原本的位置仍然被占用,显示为空白

复合定位

我们可以综合使用绝对定位和相对定位,可以让元素既能在局部发生位移,又能让元素脱离文档流,避免空白区域。

这需要用到绝对定位的一个特性。

当绝对定位的父元素不是默认定位方式,而是绝对定位、固定定位、相对定位中的任何一种时,这个绝对定位的元素仍然会脱离文档流,但位置不再以整个文档的边缘为基准偏移,而是以这个父元素的(外边距)边缘为基准偏移。

<div class="greeting">欢迎关注弦五说!!</div>
<div class="greeting">欢迎关注弦五说!!</div>
<div class="greeting">欢迎关注弦五说!!</div>
<div class="relative">
    <div class="absolute"><img src="assets/icon.png"></div> 
</div>
<div class="greeting">欢迎关注弦五说!!</div>
<div class="greeting">欢迎关注弦五说!!</div>
<div class="greeting">欢迎关注弦五说!!</div>
.absolute {
    position: absolute;
    left: 25px;
    top: 40px;
}

.relative {
    position: relative;
}
图片脱离了文档流,所以父元素的高变成了0,空白区域消失
图片脱离了文档流,所以父元素的高变成了0,空白区域消失

这种复合定位的方式,很适合实现徽章的效果。

我们可以把要被装饰的元素和小红点装到同一个父元素里,并把这个父元素设置为相对定位,然后把小红点设置为绝对定位,这时再调整小红点的位置即可。

<div class="badge-father">
    <img src="assets/icon.png">
    <div class="badge"></div>
</div>
.badge-father {
    position: relative;
    width: fit-content;
}
.badge {
    position: absolute;
    top: 0px;
    right: 0px;
    background-color: red;
    width: 12px;
    height: 12px;
    border-radius: 50%;
}
小红点的实现
小红点的实现

这样小红点以及它所装饰的icon就可以随着父元素一起,随着原本的文档流移动了,从而实现了徽章的效果。

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