阅读 363

CSS进阶(12)—— position:absolute如此高深,我当真不懂(上)

之前在探讨float属性的时候就已经提到了position:absolute的概念,绝对定位和浮动在很多方面都具有相似性,包括“块状化”,“包裹性”,“破坏性”等等,在理论层面上两者是一对兄弟关系。然而在实际场景中,由于绝对定位的“破坏性”通常比float的要强,因此会有人觉得绝对定位的元素似乎跟普通的流体元素完全玩不到一块去,事实上,除了众所周知的需要依托最近的定位祖先节点进行定位,绝对定位元素还有很多“不脱离文档流的特性”,这在本章的“非依赖性绝对定位”中会深入探索。了解了绝对定位的一些基本信息后,下面就来深入探索一下高深莫测的绝对定位吧!

1.absolute的包含块

在CSS世界里,元素的大小和定位计算一直都要受包含块的影响,如果没有包含块,那么元素的信息就会像txt文本一样,全都显示在一行,这显然是不符合我们的阅读标准的,通常情况下我们希望文本信息能在某些符合常理的情况下自动换行,既然能换行,就必须要有包含块的概念,有经验的人一般都知道,普通元素的包含块一般是他的父容器,也就是你设置某个元素的宽度为100%,那么指的是相对于父容器的宽度进行计算后得到的宽度,而绝对定位元素的包含块是相对于第一个position不为static的祖先元素进行计算的,由于包含块在CSS世界的重要性,CSS规范中有明确的计算规则如下:

(1)根元素(通常情况下就是html)被称为初始包含块,其尺寸等同于浏览器可是窗口的大小。

(2)对于position:relative/static(默认)的元素,其包含块由其最近的块容器祖先盒的content-box边界形成。

(3)对于position:fixed的元素,其包含块指的是初始包含块。

(4)对于position:absolute的元素,其包含块由最近的position不为static的祖先元素的padding-box建立(如果祖先元素为块元素)。如果没有符合条件的包含块,则包含块是初始包含块。

上面四句话看着普通,实则暗藏玄机。对于纯内联元素,position:relative和static是直接无视的,因此position:relative和static的元素的包含块不一定是其父容器,这句话有个前提条件是父容器必须为块元素,为了证明这个观点,我们可以来看一个例子加深一下印象。

<!-- 普通元素包含块 -->
<div>
    <span>你好呀</span>
    <span style="max-width: 200px;">我很好,我有一个子元素
        <div style="width: 50%">我是子元素,我想看看包含块是谁</div>
    </span>
</div>
复制代码

理论和实践再一次统一了,上述例子中,子元素div是以最外层的div作为自己包含块,直接无视了自己的父级span内联标签。

与常规元素比,absolute元素有两个比较明显的特征:

(1)包含块所在的元素不是父级块元素,而是最近的position不为static的祖先元素或根元素。

(2)边界是padding-box而不是content-box。

事实上除了以上两个明显的特征外,absolute元素和普通元素还有一个更大的差异,就是纯内联元素也可以作为absolute元素的包含块,只是规则要相对复杂,且不同的浏览器有不同的规则,因此这儿就避开不谈了。好在我们在使用绝对定位的时候大部分是用块来进行布局,跟展示图文为主的内联元素本身就玩不到一块去,因此我们就可以理直气壮的不去探索这个特性了。

利用绝对定位元素计算的容器是第一个position不为static的祖先元素,我们可以衍生出一个非常好用的小tips,就是对于绝对定位元素height:100%和height:inherit是有区别的,前者可能基于祖先元素定位,后者单纯的继承了父元素的高度,在某些场景下非常好用。

现在我们已经“完全”了解了绝对定位元素的“包含块”是如何产生的了,因此我们需要通过一个小测试来验证其实用性。

<!-- 鼠标悬浮展示文字效果 -->
 <div class="icon"></div>
 <style>
.icon{
     position: relative;
     width: 16px;
     height: 16px;
     background: url('../pic_title_left.png') center;
}
/*为了展示更清除不使用鼠标移入事件*/
.icon::after{
     content: '图标';
     position: absolute;
     top: 100%;
     background: rgba(0,0,0,0.8);
     color: white;
}
 </style>
复制代码

此例中,我们希望实现一个鼠标移入图标,显示提示信息的效果,可以看到绝对定位元素的宽度被限制在父容器的16px,此时文字的主动换行变成了一种不怎么好看的“一柱擎天”效果,这就是绝对定位的元素的“包裹性”,因此绝对定位元素的“包裹性”依赖于“包含块”。要修复问题其实很简单,只要改变默认的宽度类型就可以了,添加white-space:nowrap,让宽度表现从“包裹性”变成“最大可用宽度”,就可以实现想要的效果了。

下面我们再来看一下,position:absolute为什么要以padding-box作为边界,这其实和overflow隐藏也是padding-box作为边界类似,是由实际开发场景决定的。举个例子,如我们在开发某个文字栏目的时候,需要两侧有一定的留白,这个留白我们通常会用padding撑开,而不是margin,因为margin是全透明的,在背景颜色设置上会遇到一些麻烦,当然我们也不会考虑用border撑开,因为我们打心底认为border是用来做边框的。这时候我们需要在右上角固定一个图标,如“博客专家”的图标,你希望这个图标放在什么位置?或者说,右上角的概念是什么?CSS帮我们做了取舍,CSS认为,应该放到padding-box的外边缘,而不是content-box,事实上这样看起来确实比较美观,如下所示

<!-- 图标固定在右上角的效果 -->
<div class="content">
    <span>假设我个是图标</span>
     我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标
     我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标
     我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标
     我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标
     我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标
     我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标
     我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标
     我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标
     我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标
</div>
<style>
 .content{
    position: relative;
    width: 400px;
    padding: 20px;
    border:2px solid #ccc;
    border-radius: 4px;
 }
.content span{
    position: absolute;
    right: 0;
    top: 0;
    line-height: 20px;
    width: 70px;
    height: 40px;
    background: yellow;
}
</style>
复制代码

由于markdown编辑器支持标签语言,因此我们可以直接预览最终效果如下(小提示:你可以通过浏览器直接检查下面的元素看到CSS样式)

假设我个是图标 我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标 我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标 我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标 我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标 我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标 我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标 我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标 我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标 我这里有很多内容,但我需要有一个内边距,我还要在右上角放个图标

如果你需要右上角的定义是content,那么CSS也给你留有一丝余地,注意不要用right:padding-right,top:padding-top,那样就太蠢了,而且增加了右上角和padding的耦合性,你完全可以使用border留白来实现这个效果,这个时候就不要请padding帮忙了。

2.具有相对特性的无依赖absolute定位

很多人对于absolute的印象是“完全破坏文档流”,这可能是CSS历史上最大的冤假错案了,这甚至比clear清浮动还冤,毕竟clear清浮动好歹从表现上“清除了浮动”。而absolute则被认为默认定位在包含块的左上角。我们可以通过一个简单的例子来验证一下,一个绝对定位元素在没有left/r/t/b的情况下会在定位到哪里?

 <div style="position: relative;background:yellow">
     我是包含块
     <div style="position: absolute;">我是绝对定位元素</div>
 </div>
复制代码

很多人会觉得,绝对定位元素会和包含块内的文字重合在一起显示,事实上测试结果如下图所示,由于markdown编辑器支持标签语言,因此我们可以直接预览最终效果如下(小提示:你可以通过浏览器直接检查下面的元素看到CSS样式)

我是包含块
我是绝对定位元素

绝对定位元素并没有和包含块的文字发生重合,而是中规中矩的呆在后面,当然绝对定位的“破坏性”依旧存在,可以看到父容器div的高度不包含绝对定位元素的高度。作者把这种没有设置left/right/top/bottom属性值的绝对定位称为“无依赖绝对定位”,这种绝对定位属性拥有两个显著特性:1.破坏性,2.相对性。无依赖绝对定位本质上可以看作是relative相对定位,只是不占据CSS的尺寸流而已,也就是他在保持破坏性的基础上,保留了一定的“相对性”。听起来有一种,先按照相对定位进行计算位置,然后把自己抽离文档流的定位方式。这种不占位置的相对定位特性在实际开发的时候实则非常有用,为了加深大家对这个概念的印象,我们来举几个例子说明。

1)我们需要实现一张图的左上角有一个小图标。这时候我们仅需用一个样式就能搞定,而不需要多余的left,top申明。

<!-- 图片定位到左上角 -->
<img src="top1.png" style="position:absolute"><img src="1.jpg">
复制代码

2)我们需要实现一些带上标的文字,vertical-align中也有上标下标属性,但由于内联元素会占据位置,会影响元素的居中显示,通常情况下我们还是会借助到绝对定位不占位置的特性去实现下图的效果。

<!-- 文字定位到右上角 -->
<div class="container">
    <div class="li">
        <div class="word">普通导航</div>
    </div>
    <div class="li">
        <div class="word">热门导航
         	<span class="icon">hot</span>
        </div>
    </div>
    <div class="li">
        <div class="word">新导航
         	<span class="icon">new</span>
        </div>
    </div>
</div>
<style>
.container{
    margin: auto;
    background: #ccc;
}
.li{
    display: inline-block;
    width: 200px;
    text-align: center;
}
.word{
    padding: 20px;
}
.icon{
    position: absolute;
    color: red;
    margin: -6px 0 0 4px;
    font-size: 12px;
}
</style>
复制代码
普通导航
热门导航 hot
新导航 new

3)最后一个例子是一个比较常用的登陆注册提示功能。

<!-- 登录注册提示 -->
<div class="container">
    <div class="line">
        <label>用户名</label>
        <div>
            <input type="text" placeholder="请输入用户名">
            <i>*用户名不正常</i>
        </div>
    </div>
    <div class="line">
        <label>密码</label>
        <div>
            <input type="text" placeholder="请输入密码">
            <i>*密码不支持</i>
        </div>
    </div>
    <div class="line">
        <label>手机号</label>
        <div>
            <input type="text" placeholder="请输入手机号">
        </div>
    </div>
</div>
 <style type="text/css">
.container{
    width: 400px;
    margin: auto;
}
.line{
    margin:20px 0;
}
.line label{
    font-size: 18px;
    line-height: 40px;
    float: left;
}
.line div{
    margin-left: 4em;
}
.line input{
    width: 320px;
    font-size: 18px;
    padding: 9px 5px;
    border: 1px solid #d0d6d9;
    vertical-align: top;
}
.line i{
    position: absolute;
    line-height: 40px;
    margin-left: 20px;
    color:red;
}
</style>
复制代码

除了上述几种效果之外,无依赖绝对定位还可以帮助我们实现下拉框,模拟占位符等,在这里就不过多赘述了,举了三个例子也是为了帮助大家理解无依赖绝对定位的使用场景。

最后我们来重点关注一下无依赖绝对定位的“块状化”,通常意义上,块状化指的是display的计算值是块状的,也就是说声明了position:absolute,相当于同时申明了display:block,但该元素的位置却和元素本身的属性相关。听起来有点绕,我们来看一个例子对比一下就明白了。

<!-- 深入理解无依赖定位 -->
<div style="position: relative;background: yellow">
     我是包含块
     <span style="position: absolute;">我是绝对定位元素</span>
</div>

<div style="position: relative;background: yellow">
    我是包含块
    <div style="position: absolute;">我是绝对定位元素</div>
</div>
复制代码

由于markdown编辑器支持标签语言,因此我们可以直接预览最终效果如下(小提示:你可以通过浏览器直接检查下面的元素看到CSS样式)

我是包含块 我是绝对定位元素
我是包含块
我是绝对定位元素

上面这个例子中,绝对定位元素在未被声明position:absolute之前,一个是块级元素,一个是内联元素,因此一个是换行显示,另一个是同行显示,在声明了absolute后,虽然计算值都变成了block,但其位置仍然跟之前定位的相同。

本章我们已经深入了解了绝对定位的包含块以及“无依赖绝对定位”的特性,下一章我们来聊聊absolute的流体特性以及absolute和其他CSS相互之间的爱恨情仇。

不忘初心,方得始终

喜欢博主的童鞋可以扫描二维码加博主好友~ 也可以扫中间二维码入驻博主的粉丝群(708637831)~当然你也可以扫描二维码打赏并直接包养帅气的博主一枚。

关注下面的标签,发现更多相似文章
评论