前言
CSS position属性用于指定一个元素在文档中的定位方式。top、right、bottom、left 属性(值可为CSS数值单位,正负决定其方向)则决定了该元素的最终位置。
1. static定位
position属性的默认值,指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top、right、bottom、left 属性无效。与普通元素一样,其包含块为父元素的content-box
2. relative相对定位
基于元素原本的位置进行定位移动。此时 top、right、bottom、left 属性均基于原本的位置进行移动尺寸的计算。
特点:
- relative定位时未设置top/bottom/left/right时,位置无变化
- relative定位的包含块为父元素的的content-box
- relative定位后,原位置依然占用布局空间,所以不脱离标准文档流
- relative定位后的元素位置不影响周围其他元素的布局
- relative定位top和bottom属性同时存在时,只有top生效;left和right属性同时存在时,只有left生效
3. absolute绝对定位
通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。
特点:
- absolute定位未设置top/bottom/left/right时,位置无变化
- absolute定位的包含块为最近的position不为static的祖先元素的padding-box,若没有符合条件的祖先元素,则为根元素html标签。
- absolute定位后,原位置不占用布局空间,所以脱离标准文档流
- absolute定位的元素可以设置外边距(margin),且不会与其他边距合并。
- absolute定位元素的宽度由自身内容决定,且不会超过其包含块的宽度
- absolute定位与float同时使用时,float无效
3.1 “无依赖”的绝对定位
如果一个绝对定位元素,其没有设置任何top/bottom/left/right属性,且其祖先元素全都没有设置定位(其实有定位也无妨),那么它的位置依然还是定位前的位置。
概括起来就是:“无依赖”的绝对定位本质就是脱离文档流的相对定位
absolute是独立的CSS属性值,必须改掉“ 只要有absolute定位,其必有祖先元素relative定位,top,left必有属性值或者必须有z-index ”的错误观点!!
举例:将icon图标显示到内容content的左上角
<div class="content">
<div class="icon"></div>
</div>
通常来说,很多人是这么实现的:
.content{
position: relative;
}
.icon{
position: absolute;
left:0;
top:0
}
而实际只需要一行代码即可:
.icon{
position: absolute;
}
无依赖绝对定位的其他应用场景举例:
(1)input表单输入框尾部添加提示信息(用无依赖绝对定位好处是提示信息不占用空间):
<input type="text" name="name"> <span class="message">请输入姓名</span>
.message{
position: absolute;
color:red;
margin-left: 10px;
}
(2)模拟input输入框的placeholder效果(兼容ie9以下不支持placeholder属性的情况):
<label class="placeholder" for="name">请输入姓名</label>
<input type="text" id="name">
.placeholder{
position: absolute;
color:#cccccc;
/*margin来调整位置*/
margin-left: 5px;
}
(3)下拉列表定位:
<input placeholder="搜索" type="search" id="name">
<ul class="datalist show">
<li>张三</li>
<li>李四</li>
<li>王五</li>
</ul>
ul.datalist{
position: absolute;
/*下拉列表其他样式*/
color: #bbbbbb;
list-style: none;
margin: 0;
padding: 0;
width: 200px;
border-style: solid ;
border-color: #cccccc;
border-width: 0 1px 1px 1px;
}
/*下拉列表显隐切换*/
.datalist.show{
display: block;
}
.datalist.hide{
display: none;
}
input{
width: 200px;
}
建议:在只需满足布局效果的情况下,只用absolute的无依赖定位能解决的问题就能尽量不要同时再用relative定位,这样避免了relative和absloute元素的耦合度,降低了代码维护成本
3.2 absulute与overflow
当设置了overflow属性的元素其包含absolute定位的后代元素时,只有当absolute元素的包含块(即postiton为非static的祖先元素)也是overflow元素的后代元素或就是overflow元素本身时,overflow属性才会有效,否则不会生效。
.relative{
position: relative;
}
.absolute{
position: absolute;
}
.overflow{
overflow: hidden;
width: 100px;
height: 50px;
}
<div class="relative">
<div class="overflow">
<!-- absolute元素溢出不会被隐藏-->
<div class="absolute">豆腐干豆腐干豆腐干地方微软微软为</div>
</div>
</div>
<div class="overflow">
<div class="relative">
<!-- absolute元素溢出会被隐藏-->
<div class="absolute">豆腐干豆腐干豆腐干地方微软微软为</div>
</div>
</div>
<div class="overflow absolute">
<!-- absolute元素溢出会被裁剪-->
<div class="absolute">豆腐干豆腐干豆腐干地方微软微软为</div>
</div>
注意事项:
overflow元素自身同时设置过transform属性时,overflow属性是否生效在各种浏览器中可能存在一定差异
3.3 absoulte的流体特性
当absolute定位的元素同时定义了对立方向的定位尺寸时(如同时设置了left和right,同时设置了bottom和top),那么该元素的宽度或者高度自适应于该元素的包含块的padding-box的宽度和高度,具体宽度和高度由具体的left/top/bottom/right值来确定
示例:
<div class="relative">
<div class="absolute"></div>
</div>
.relative{
position: relative;
width:200px;
height:200px;
background-color: red;
}
.absolute{
position: absolute;
left:10px;
right:10px;
top:20px;
bottom: 20px;
background-color: blue;
}
此例子中,relative父元素变大变小,absulute子元素也会自适应变化,并且各边界距离relative父元素的各边界距离为其设置的四种属性值尺寸。当四种尺寸都为0时,则完全覆盖其包含块的padding-box范围。
absolutel流体特性非常经典的应用就是和margin:auto属性搭配使用实现元素相对于包含块的垂直水平居中效果
:
.relative{
position: relative;
width:100px;
height:100px;
background-color: red;
}
.absolute{
position: absolute;
background-color: blue;
width: 20px;
height: 20px;
left:0;
right:0;
top:0;
bottom: 0;
margin:auto
}
绝对定位注意事项:
如果绝对定位的祖先元素 存在使用了transform属性的元素,则其会优先成为该绝对定位元素的包含块
4. fixed固定定位
基于页面根元素html标签的位置进行定位移动。此时 top、right、bottom、left 属性均基于HTML文档(即页面窗体)进行移动尺寸的计算。
特点:
- fixed定位时未设置top/bottom/left/right时,位置无变化
- fixed定位的包含块为根元素html标签
- fixed定位后,原位置不占用布局空间,所以脱离标准文档流
- 与absolute的“无依赖”定位效果原理类似,fixed定位同样有此特性,只不过包含块改变了
fixed定位相对简单粗暴,一些经典应用场景为页面右下角的回到顶部按钮,页面的各种固定位置的图标按钮或广告,页面上居中的蒙层弹窗等
经典应用——蒙层弹窗:
蒙层弹窗是网页中常见的交互,其中黑色半透明全屏覆盖的蒙层基本上都是使用 position: fixed 定位实现的。如下图所示:
实现这种效果并不难,但是这种蒙层弹窗一般存在一个细节体验问题:
如果原始页面存在滚动条,蒙层弹出后,鼠标滚动的时候蒙层后面的原始页面内容依然可以被滚动(即滚动穿透),且滚动时现蒙层无法覆盖浏览器右侧的原始页面滚动条
解决方法:
如果是移动端项目,阻止 touchmove 事件的默认行为可以防止滚动;
如果是桌面端项目,可以让根元素直接 overflow:hidden。但是,Windows 操作系统下的浏览器的滚动条都是占据一定宽度的,滚动条的消失必然会导致页面的可用宽度变化,页面会产生体验更糟糕的晃动。此时可以通过使用同等宽度的透明边框border来代替消失的滚动条。以下为代码示例:
蒙层显示的同时执行下面的 JavaScript 代码:
let widthBar = 17;
const root = document.documentElement;
if (typeof window.innerWidth == 'number') {
//获取滚动条的宽度
widthBar = window.innerWidth - root.clientWidth;
}
//禁止原始页面滚动
root.style.overflow = 'hidden';
//html根元素右边框代替消失的滚动条
root.style.borderRight = widthBar + 'px solid transparent';
蒙层隐藏的时候执行下面的 JavaScript 代码:
const root = document.documentElement;
root.style.overflow = '';
root.style.borderRight = '';
fixed定位注意事项:
由于设置了transfom属性的元素的特有渲染特性,会导致设置了fixed定位的子元素其fixed定位失效,而变成了基于transfom元素的绝对定位现象。此时的现象可视为transform元素拥有了position:relative属性,而原fixed定位的元素设置了position:absolute属性
5. sticky粘性定位
粘性定位的元素是依赖于用户的滚动
元素先根据正常文档流进行定位(即原本应该在正常文档流的位置),然后相对它的最近滚动祖先(nearest scrolling ancestor)和 containing block (最近块级祖先 nearest block-level ancestor),包括table-related元素,基于top, right, bottom, 和 left的值进行偏移。偏移值不会影响任何其他元素的位置。
该值总是创建一个新的层叠上下文(stacking context)。注意,一个sticky元素会“固定”在离它最近的一个拥有“滚动机制”的祖先上(当该祖先的overflow 是 hidden, scroll, auto, 或 overlay时),即便这个祖先不是最近的真实可滚动祖先。
文章参考资料:张鑫旭《CSS世界》