CSS系列——CSS深入理解之absolute定位

1,579 阅读12分钟

1. 写在前面

本篇将要介绍的绝对定位absolute属性和此前介绍的CSS系列——CSS深入理解之float浮动有着几分的相似性,可以认为两者是兄弟关系,都具有“包裹性”、“高度塌陷”、“块状化”的特性,它们在很多场合都可以互相替代。很多人可能有这样的疑问:一个属性名是“position”,一个属性名是“float”,从名字看起来,它们八竿子都打不着啊,怎么还是兄弟关系呢?要说position: absoluteposition: relative是兄弟关系还能理解,要说和float是兄弟关系我就纳闷!!!呵呵~~~~,别急,这就是写作本文的目的。

2. absolute的特性

在介绍absolute之前,有以下公共CSS代码:

/* CSS代码 */
.father{
    border: 2px solid deeppink;
    width: 200px;
}
.son {
    position: absolute;
    font-size: 0;
    border: 2px solid blue;
    padding: 5px;
}
.father img {
    width: 128px;
}

2.1 包裹性

然后有以下html代码:

<div class="father">
    <!--son1与son的唯一区别是son1的position设置为static-->
    <div class="son1">
        <img src="../../lib/img/mm1.png">
    </div>
</div>
<br/>
<br/>

<div class="father">
    <div class="son">
        <img src="../../lib/img/mm1.png">
    </div>
</div>

最终显示的效果如下图所示:

在本例中,son1与son的唯一区别是son1的position设置为static.father元素的宽度设置为200pximg元素是一个128px宽度的图片,则此时绝对定位元素宽度表现为"包裹性",其宽度也就是里面图片的宽度128px。

由于绝对定位元素宽度表现为"包裹性",因此,下面的CSS写法就是多余的:

.wrap{
    display: inline-block;// 没有必要
    position: absolute;
}

2.2 高度塌陷

基于上图,父元素div的高度并没有被子元素撑开(粉色区域),这种效果可以称为"高度塌陷"。导致高度塌陷的原因是因为浮动元素脱离了正常的文档流,则div.father认为其没有子元素,所以产生了高度塌陷。

如果在.father元素增加子元素,如下:

<!--HTML代码-->
<div class="father">
    <div class="son">
        <img src="../../lib/img/mm1.png">
    </div>
    美女1,美女2,美女3,美女4,美女5
</div>

则在浏览器中的效果如下:

从图中明显看出文字被图片遮盖了,这一点和float不同。因为,float元素本身仍处于文档流中,文字会环绕着float元素,不会被遮蔽,而设置了absolute的图片元素出现了层级关系,已经脱离了正常的文档流了,从父元素的视点看,图片已经完全消失不见了,因此从最左边开始显示文字,而absolute的层级高,所以图片遮盖了文字。

2.3 块状化

块状化的意思是,一旦元素position的属性为absolute或者fixed,则其display计算值就是block或者table。可以复制以下代码到浏览器控制台中:

var span = document.createElement('span')
document.body.appendChild(span)
console.log('1.' + window.getComputedStyle(span).display)
// 设置元素绝对定位
span.style.position = 'absolute'
console.log('2.' + window.getComputedStyle(span).display)
document.getElementById("aa").style.display = "block"

则在浏览器控制台中的结果如下:

1.inline
2.block

2.4 小结

对于上面对absolute的介绍,对比float属性,是不是应该理解他们是兄弟关系呢?如果你非得不这样认为可以,只要你明白absolute的特性即可。绝大多数前端开发人员应该都懂,但是如果本文只是介绍上面的知识点,就太对不起大家的期待了!下面将要介绍absolute的流体与相对特性才是本文的重点。

3. absolute流体与相对特性

3.1 absolute的相对特性

在介绍absolute的相对特性之前,先抛出以下问题: 如果一个元素的定位属性设置成了:position: absolute后,没有设置left/top/right/bottom,并且其祖先元素全部都是非定位元素,请问它将在哪里显示?

包括我自己,在深入了解absolute的特性之前,认为该元素是在浏览器窗口的左上方显示,其实这是对absolute绝对定位属性错误的认识。因此,很多人在使用absolute定位属性的时候,必定先要设置父元素position: relative,同时设置绝对定位元素的left/top/right/bottom,甚至还要设置绝对定位元素层级z-index实际上,该元素还是在当前的位置。我们拿下面的这个例子验证:

 <!--HTML代码-->
<div class="father">
    <div class="pa box"></div>
</div>
/* CSS代码 */
.father{
    border: 2px solid deeppink;
    width: 100px;
    height: 100px;
}
.pa{
    position: absolute;
}
.box{
    background-color: #cdcdcd;
    width: 50px;
    height: 50px;
}

如下图所示,.box元素还是在当前的位置显示,而不是在浏览器窗口的左上方显示:

在京东商城首页,有这样的一个效果:

image-20180502200432543

然后我们打开调试窗口,查看html和css代码如下:

image-20180502200712645

这里css代码中的top:0;left:0完全是多余的代码,可以省略不写。因为,不设置left/top/right/bottom的绝对定位元素还是在当前的位置,只是脱离了正常的文档流了。

实际上,absolute是一个相对比较独立的CSS属性,它的样式和行为表现不依赖其他的CSS属性就可以完成。因此,如果元素设置了定位属性为absolute绝对定位,并且没有设置left/top/right/bottom,那么可以将这种定位属性称为“无依赖绝对定位”,其本质就是"相对定位",特点仅仅是脱离文档流,不占据任何CSS流的尺寸空间了。

无依赖绝对定位在实际开发中非常有用,下面举几个比较常用的例子。

1)各类图标定位

我们以慕课网首页上的课程列表举例:

WX20180502-205632@2x

<div>
    <div class="box"></div>
    <i>Hot</i>
</div>

核心CSS代码如下所示:

WX20180502-205758@2x

完全不需要借助top/right/bottom/leftposition: relative的帮助就可以搞定小图标的布局啦。相比使用position:relativeright/top的布局方式,这种布局方式的优点是:

  • 维护成本低。如果后面想删除这个图片,只需要将图标对应的html和css代码删除掉就可以了,不会影响其他的元素
  • 健壮性高。如果图片变大或者文字变长,我们不需要修改小图标的css代码,仍然定位效果良好。

再举一个在实际开发中用的比较多的一个例子,如下图所示,在一段文字的前面有一个图标:

这种布局方式同样可以借助无依赖定位的实现,并且代码简单高效,代码如下所示:

<div class="email-wrapper">
    <i class="icon-email"></i>
    <span class="icon-msg">请输入您的邮箱:</span>
</div>
.email-wrapper{
    display: inline-block;
    height: 20px;
    padding-left: 20px;
    /*font-size: 0;*/
}
.icon-email{
    position: absolute;
    margin-left: -20px;
    width: 20px;
    height: 20px;
    background: url("../../lib/img/email.png") center center no-repeat;
    background-size: contain;
}
.icon-msg{
    display: inline-block;
    line-height: 20px;
    vertical-align: top;
}

2)校验提示错误

在实际开发中,我们有很多表单校验,当校验不通过的时候,会有一些错误提示给用户,如下图所示:

通常,错误提示可以放到input框的下面,但是当出现错误提示的时候,下面的内容会整体下移,当错误提示消失的时候,下面的内容又会整体上移,用户体验不好。还有一种做法是放到input框的右侧显示,但是在默认状态下部容器设置了水平居中, 宽度不大,如果再出现错误提示信息,就会出现容器的宽度不够的问题。此时,我们同样可以借助:"无依赖定位",直接给错误提示信息增加一个CSS类,如下所示:

.msg-error{
	position: absolute;
	margin-left: 10px;
}

无论将input框的宽度变大或者变小,提示信息都会跟着input框。相比使用position:relativeright/top的布局方式,这种方法代码量更少、容错性更高、维护成本更低。

关于无依赖绝对定位的应用还有很多,这里就不一一介绍了,有兴趣的同学可以参看张鑫旭老师的《CSS世界》。

3.2 absolute的流体特性

只有absolute遇到left/top/right/bottom属性的时候,absolute元素才真正变成绝对定位元素。如果用户给absolute至少指定了left/right中的一个,则水平方向的相对特性丢失,垂直方向上继续保持相对特性;如果用户给absolute至少指定了top/bottom中的一个,则保持水平方向上的相对特性,垂直方向上的相对特性丢失。例如:

<div class='box'></div>
.box{
    position: absolute;
    right: 0;
}

此时,元素水平方向相对特性丢失,具有了绝对定位特性,而垂直方向的定位依然保持了相对特性。

以上面的这个例子举例,当只有left或者right属性的时候,由于包裹性,此时div的宽度是0。但是,如果同时设置left:0;right:0的时候,宽度表现为"格式化宽度",宽度自适应于.box包含快的content-box,换句话说,如果包含快的conent-box宽度发生变化,则.box的宽度也会跟着一起变。举个例子:

<div class='box'></div>
.box{
    position: absolute;
    right: 0;
    left: 0;
    top: 0;
    bottom: 0;
}

如果.box的包含块是根元素,则上面的代码可以让.box元素正好完全覆盖浏览器的可视窗口,同时,如果改变浏览器窗口的大小,.box的大小会随着浏览器的大小自动变化。因此,对于设置了对立定位属性的绝对定位属性,无论设置padding还是margin,其占据的空间一直不变,变化的就是content-box,这就是典型的流体表现特性。流体特性的具体用法在后面会介绍到。

4. absolute与其他属性

CSS中的很多属性需要和其他的属性一起使用的时候会发生意向不到的效果。下面将介绍absolute与其他CSS一起使用产生的效果。

4.1 absolute与text-align

利用text-align可以控制绝对定位元素的位置,实现主窗口右侧的"返回顶部"以及"反馈"等布局的效果。效果图如下:

WX20180502-210045@2x

核心代码如下:

<!--HTML代码-->
<div class="alignright">
    <span class="follow">
        <img src="../../lib/img/message.png">
        <img src="../../lib/img/top.png">
    </span>
</div>
/* CSS代码 */
.alignright{
    overflow: hidden;
    text-align: right;
}
.alignright:before{
    content: "\2002"
}
.follow{
    position: fixed;
    bottom: 100px;
    z-index: 1;
}
.follow img{
    display: block;
    margin: 10px;
    width: 20px;
    height: 20px;
    background-size: contain;
}

在本例中,利用:before伪元素,在其前面插入一个空格(\2002),然后设置text-aligin: right,则空格对齐主结构的右侧边缘,后面的固定定位元素(同绝对定位元素)由于"无依赖定位"特性,左边缘正好就是主结构的右边缘,自然就跑到主结构的外面显示了。这种布局在实际开发中用处非常大,比如说下图中某宝的楼层导航效果都可以使用这种方式实现。

4.2 absolute与clip

在实际开发过程中,很多时候我们为了更好的SEO和无障碍识别,都会将页面中的一些元素隐藏,例如隐藏下面代码中的本网站名字这几个字:

/* CSS代码 */
<a href="#" class="logo">
	<h1>本网站名字</h1>
</a>

为了隐藏上面的文字,有以下几种方案可以供我们选择:

  • 使用display:none或者visibility:hidden。缺点:屏幕阅读设备会忽略这些文字;
  • 使用text-align缩进。缺点:如果缩进过大到屏幕之外,屏幕阅读设备也是不会读取的;
  • 使用color: transparent。原生IE8浏览器器并不支持,并且还是能够选中文本。

借助absolute和clip(关于clip用法不熟悉的同学可以自己百度下,很简单)这两个属性,能够同时满足视觉上隐藏和屏幕阅读设备能够读取的要求,核心代码如下:

/* CSS代码 */
h1{
    position: absolute;
    clip: rect(0 0 0 0);
}

4.3 absolute之margin:auto居中

在实际工作开发中,可能我们用的最多的是下面的方式来实现元素的水平垂直居中效果,核心代码如下:

/* CSS代码 */
.box{
    width: 20px;
    height: 20px;
    position: absolute;
    left: 50%;
    right: 50%;
    margin-left: -10px;
    margin-right: -10px;
}

此方法有一个不足之处就是需要提前知道元素的尺寸,否则无法控制margin负值的大小。

如果不知道元素的尺寸,可以使用transform: translate(-50%, -50%)代替margin负值,然而这种方法存在一定的兼容性问题,IE9(-ms-), IE10+以及其他现代浏览器才支持,在一定的场景下会导致微信闪退的问题。

在介绍下另外一种方法前,我们首先熟悉下margin: auto的填充规则:

  • 如果一侧定值,一侧auto,则auto为剩余空间大小;
  • 如果两侧都是auto,则平分剩余空间。

因此,利用绝对定位absolute元素的流体特性和margin: auto的自动分配特性能够实现水平垂直居中的效果,核心代码如下:

/* CSS代码 */
.box{
    width: 20px;
    height: 20px;
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    margin: auto;
}

显示效果如下:

WX20180502-212501@2x

这种方法兼用性好,并且需要提前知道元素的尺寸,减少了依赖,后期维护改动的地方少,何乐而不为呢?

5. 结语

关于absolute的介绍就到这里了,平时我们应该多思考,多总结,才会有新的体会。计划下一篇文章介绍relative定位,最新文章都会第一时间更新在我的公众号<前端Talkking>里面,欢迎关注。

以上就是本文的全部内容,感谢阅读,如果有表述不正确的地方,欢迎留言指正!

6.参考

  • 张鑫旭 《CSS世界》

 **遇见了,不妨关注下我的微信公众号「前端Talkking」**