positon 定位

01. 定位中的偏移

CSS有三种基本的布局机制:普通流、浮动和绝对定位。利用定位,可以准确地定义元素框相对于其正常位置应该出现的位置,或者相对于父元素、另一个元素甚至浏览器窗口本身的位置。但元素究竟如何定位,定位到什么位置,主要依靠top/right/bottom/left这四个偏移属性。

position定位

值: static | relative | absolute | fixed | inherit

初始值: static

应用于: 所有元素

继承性: 无

static:元素框正常生成。块级元素生成一个矩形框,作为文档流的一部分,行内元素则会创建一个或多个行框,置于其父元素中

relative:元素框偏移某个距离。元素仍保持其未定位前的形状,它原本所占的空间仍保留

absolute:元素框从文档流完全删除,并相对于其包含块定位,包含块可能是文档中的另一个元素或者是初始包含块。元素原先在正常文档流中所占的空间会关闭,就好像该元素原来不存在一样。元素定位后生成一个块级框,而不论原来它在正常流中生成何种类型的框

fixed:元素框的表现类似于将position设置为absolute,不过其包含块是视窗本身

[注意] 相对定位实际上被看作普通流定位模型的一部分,因为元素的位置相对于它在普通流中的位置。

包含块

【1】根元素

根元素HTML的包含块(也称为初始包含块)是一个视窗大小的矩形,即HTML的父级document

【2】非根元素

如果position值是relative或static,包含块由最近的块级框、表单元格或行内祖先框的内容边界构成

如果position值是absolute,包含块设置为最近的position值不是static的祖先元素(可以是任何类型),过程如下:

[1]如果这个祖先是块级元素,包含块则设置为该元素的内边距边界。换句话说,就是由边框界定的区域

[2]如果这个祖先是行内元素,包含块则设置为该祖先元素的内容边界

[3]如果没有祖先,元素的包含块定义为初始包含块,即document

[注意]由于元素可以定位到其包含块的外面。这与浮动元素使用负外边距浮动到其父元素内容区外面很类似。所以这里包含块实际上应该是定位上下文,或者定位父级

偏移属性

三种定位机制使用了4个属性来描述定位元素各边相对于其包含块的偏移。这4个属性被称为偏移属性。

top/right/bottom/left

值: <length> | <percentage> | auto | inherit

初始值: auto

应用于: 定位元素(也就是position值不是static的元素)

继承性: 无

百分数: 对于top和bottom,相对于包含块的clientHeight;对于right和left,相对于包含块的clientWidth

这些属性描述了距离包含块最近边的偏移。top描述了定位元素上外边界离其包含块的顶端有多远。如果top为正值,会把定位元素的上外边距边界下移,若为负值,则会把定位元素的上外边距移到其包含块的顶端之上。类似地,left描述了定位元素的左外边距边界在其包含块左边界右边(正值)或左边(负值)有多远。如果是正值,会把定位元素的外边距边界移到包含块左边界右边,而负值则将其移到包含块左边界左边。所以,正值会导致向内偏移,使边界朝着包含块的中心移动,而负值会导致向外偏移。

偏移定位元素的外边距边界时,带来的影响是元素的所有一切(包含外边距、边框、内边距和内容)都会在定位的过程中移动。

[注意]定位元素的边界是指定位元素margin外侧的边界;包含块的包含区域是指包含块的border内侧的padding+content区域。

绝对定位

元素绝对定位时,会从文档流中完全删除。然后相对于其包含块定位,其边界根据偏移属性(top、left等)放置。定位元素不会流入其他元素的内容,反之亦然。元素绝对定位时,会为其后代元素建立一个包含块

[注意]如果文档可滚动,绝对定位元素会随着它滚动,因为元素最终会相对于正常流的某一部分定位

当元素绝对定位时,偏移属性表现如下:

    left:0 元素的左边界(margin-left外侧)位于包含块的左边界内侧(border-left内侧)
    top:0 元素的上边界(margin-rop外侧)位于包含块的上边界内侧(border-top内侧)
    right:0 元素的右边界(margin-right外侧)位于包含块的右边界内侧(border-right内侧)
    bottom:0 元素的下边界(margin-bottom外侧)位于包含块的下边界内侧(border-bottom内侧)
    当top、right、bottom、left四个值都为auto时(即都处于默认状态时),
    left:auto 元素的左边界位于元素处于静态位置时的左边界
    top:auto 元素的上边界位于元素处于静态位置时的上边界
    right:auto 元素的右边界位于正好能包裹住元素的横向区域的右边界(margin-right外侧)
    bottom:auto 元素的下边界位于正好能包裹住元素的纵向区域的下边界(margin-bottom外侧)

[注意]元素的静态位置是指元素在正常流中原本的位置,更确切的讲,顶端的静态位置是从包含块的上边界到假想框的上外边距边界之间的距离。假想框是假设元素position属性为static时元素的第一个框。如果这个假想框在包含块的上面,则这个值为负

//DEMO中,包含块的width和height都是180px,padding为10px,所以包含块的clientWidth和clientHeight都是200px

格式化

对于普通流的元素来说,水平格式化的7大属性是margin-left、border-left、padding-left、width、padding-right、border-right、margin-right7个属性的值加在一起必须是元素包含块的宽度,这往往是块元素的父元素的width值(因为块级元素的父级元素几乎都是块级元素)。垂直方向也类似。

但是对于绝对定位元素则不相同。它的水平格式化等式为:

left + margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right + right = 包含块的clientWidth

类似的,垂直格式化等式为:

top + margin-top + border-top-width + padding-top + height + padding-bottom + border-bottom-width + margin-bottom + bottom = 包含块的clientHeight

auto

auto值是用来弥补实际值与所需总和的差距。

水平方向上,可以为auto的属性有left、margin-left、width、margin-right、right。类似地,垂直方向上,可以为auto的属性有top、margin-top、height、margin-bottom、bottom

【0个auto】

当水平方向上9个值的和不等于包含块的clientWidth时,属于过度受限的情况,right值会被重置为auto;类似地,当垂直方向上9个值的和不等于包含块的clientHeight时,属于过度受限的情况,bottom值会被重置为auto

【1个auto】

根据水平和垂直格式化等式,auto为计算值

【2个auto】

当margin-left和margin-right同时为auto时,margin-left和margin-right都为等式计算值且相等

[注意]在margin-left和margin-right同时为auto的情况下,只有当left和right值相等时,元素才能水平居中显示;否则,虽然margin-left和margin-right依然相等,但由于left和right并不相等,元素也不能水平居中

当margin-left或margin-right不同时为auto时,值为auto的margin-left或margin-right被置为0

当width与left或right同时为auto时,width被置为宽度最小值(内容宽度)

当left和right同时为auto时,则left为置为0

类似地,

当margin-top和margin-bottom同时为auto时,margin-top和margin-bottom都为等式计算值且相等

[注意]在margin-top和margin-bottom同时为auto的情况下,只有当top和bottom值相等时,元素才能垂直居中显示;否则,虽然margin-top和margin-bottom依然相等,但由于top和bottom并不相等,元素也不能垂直居中

当margin-top或margin-bottom不同时为auto时,值为auto的margin-top或margin-bottom被置为0

当height与top或bottom同时为auto时,height被置为高度最小值(行高)

当top和bottom同时为auto时,则top为置为0

【3个auto】

当margin-left和margin-right同时为auto时,margin-left和margin-right都被置为0

当margin-left和margin-right不同时为auto时,值为auto的margin-left或margin-right被置为0

除了width、margin-left和margin-right同时为auto时,margin-left和margin-right都置为0,width为等式计算值;其他情况下,width都被置为宽度最小值(内容宽度)

当left和right同时为auto时,则left为置为0

类似地,

当margin-top和margin-bottom同时为auto时,margin-top和margin-bottom都被置为0

当margin-top和margin-bottom不同时为auto时,值为auto的margin-top或margin-bottom被置为0

除了height、margin-top和margin-bottom同时为auto时,margin-top和margin-bottom都置为0,height为等式计算值;其他情况下,height都被置为高度最小值(行高)

当top和bottom同时为auto时,则top为置为0

【4个auto】

当width不为auto时,margin-left和margin-right被置为0,left被置为0,right为计算值

当left不为auto时,margin-left和margin-right被置为0,width被置为宽度最小值(内容宽度),right为计算值

当right不为auto时,margin-left和margin-right被置为0,width被置为宽度最小值(内容宽度),left为计算值

当margin-left不为auto时,left和margin-right被置为0,width被置为宽度最小值(内容宽度),right为计算值

当margin-right不为auto时,left和margin-left被置为0,width被置为宽度最小值(内容宽度),right为计算值

类似地,

当height不为auto时,margin-top和margin-bottom被置为0,top被置为0,bottom为计算值

当top不为auto时,margin-top和margin-bottom被置为0,height被置为高度最小值(行高),bottom为计算值

当bottom不为auto时,margin-top和margin-bottom被置为0,height被置为高度最小值(行高),top为计算值

当margin-top不为auto时,top和margin-bottom被置为0,height被置为高度最小值(行高),bottom为计算值

当margin-bottom不为auto时,top和margin-top被置为0,height被置为高度最小值(行高),bottom为计算值

【5个auto】

left、margin-left和margin-right被置为0,width被置为宽度最小值(内容宽度),right为计算值

类似地,top、margin-top和margin-bottom被置为0,height被置为高度最小值(行高),bottom为计算值

总结

auto值的赋值顺序为:margin先置0或其他值,然后宽高置为最小值,然后left/top置为0,最后right/bottom为等式计算值

[注意1]IE7-浏览器不支持绝对定位元素通过将上下外边距设置为auto来实现垂直居中的行为

[注意2]IE6-浏览器不支持绝对定位元素不设置宽度,而通过设置top/left/right/bottom来撑开宽高的行为

//DEMO中,定位元素的padding、border都为0。而父级元素也就是包含块的width和height都设为200px,边框为2px

02. 定位中的堆叠 z-index

对于所有定位,最后都不免遇到两个元素试图放在同一位置上的情况。显然,其中一个必须盖住另一个。但,如何控制哪个元素放在上层,这就引入了属性z-index。

定义

利用z-index,可以改变元素相互覆盖的顺序。这个属性的名字由坐标系统得来,其中从左向右是x轴,从上到下是y轴。从屏幕到用户是z轴。在这个坐标系中,较高z-index值的元素比较低z-index值的元素离用户更近,这会导致较高z-index值的元素覆盖其他元素,这也称为堆叠或叠放

z-index

值: <integer> | auto | inherit

初始值: auto

应用于: 定位元素

继承性: 无

[注意]z-index应用于定位元素是CSS2的规范,到了CSS3标准,z-index的应用范围扩大了不少

[注意]所有整数都可以作为z-index的值,包括负数。如果为元素指定一个负z-index值,会将其移到离读者更远的位置,会移到叠放栈的更低层

堆叠规则

对于CSS2.1来说,页面元素的堆叠规则如下图所示:

定位元素的堆叠规则

[1]对于定位元素(position不是static的元素)来说,不设置z-index或z-index相同时,后面元素覆盖前面元素

[2]对于处于同一堆叠上下文中的同一层次的元素来说,默认z-index较大值覆盖z-index较小值

堆叠上下文

一旦为一个元素指定了z-index值(不是auto),该元素会建立自己的局部堆叠上下文。这意味着,元素的所有后代相对于该祖先元素都有其自己的叠放顺序

[注意]auto值指当前堆叠上下文中生成的栈层次与其父框的层次相同,这个框不会建立新的局部叠放上下文。z-index:auto与z-index:0的值相等,但z-index:0会建立新的局部堆叠上下文

默认样式

<div class="box1">
    <ul class="list1">
        <li id="one">1</li>
        <li id="two">2</li>
        <li id="three">3</li>
        <li id="four">4</li>
    </ul>
    <ul class="list2">
        <li id="five">5</li>
        <li id="six">6</li>
    </ul>    
</div>
<div class="box2">
    <div id="seven">7</div>
    <div id="eight">8</div>
</div>
.box1{z-index: 1;}
.box2{z-index: auto;}
.list1{z-index: 2;}
.list2{z-index: 1;}
#one{z-index: -1;}
#two{z-index: 1;}
#three{z-index: 0;}
#four{z-index: auto;}
#five{z-index: 2;}
#six{z-index: 1;}
#seven{z-index: 2;}
#eight{z-index: -1;}
// 堆叠顺序
.box1                  1
.box1 .list1           1,2
.box1 .list1 #one      1,2,-1
.box1 .list1 #two      1,2,1
.box1 .list1 #three    1,2,0
.box1 .list1 #four     1,2,auto
.box1 .list2           1,1
.box1 .list2 #five     1,1,2
.box1 .list2 #six      1,1,1
.box2                  auto
.box2 #seven           auto,2
.box2 #eight           auto,-1

[注意]auto,2和auto,-1相当于2和-1,因为auto代表未产生堆叠上下文。则#seven和#eight相当于和它们的父级.box2以及.box1处于同一层次。

元素不会叠放在其堆叠上下文(即定位父级z-index为数字值)的背景之下,但可以叠放在其内容之下;当元素没有处于堆叠上下文中,元素不会叠放在<body>元素的背景之下,但可以叠放在其内容之下。

兼容

【1】IE7-浏览器z-index的默认值是0

一般地,定位元素的z-index的默认值是auto,而IE7-浏览器定位元素的z-index的默认值是0,二者的区别于IE7-浏览器的定位元素会自动生成堆叠上下文。

div{
    position: absolute;
    border: 1px solid black;
}    
.div1{
    width: 300px;
    height: 100px;
    background-color: pink;
    z-index: 1;
}
.div2{
    background-color: lightgreen;
    top: 50px;
    left: 50px;
    width: 200px;
    height: 200px;
}
.in2{
    width: 100px;
    height: 150px;
    background-color: lightblue;
    z-index: 2;
    border: none;
}
<div class="div1"></div>
<div class="div2">
    <div class="in2"></div>
</div>

一般地,div1的堆叠顺序为1;div2的堆叠顺序为auto;in2的堆叠顺序为auto,2相当于2。所以覆盖层次为in2 覆盖 div1 覆盖 div2。但在IE7-浏览器中,div1的堆叠顺序为1;div2的堆叠顺序为0;in2的堆叠顺序为0,2。所以覆盖层次为div1 覆盖 in2 覆盖 div2。

【2】IE6-浏览器关于z-index的一个怪异bug

当元素本身浮动且不是定位元素(position不是static),元素父级是relative,则在IE6-浏览器在无论该元素的父级的z-index如何设置都不起作用。

.div1{
    position: absolute;
    z-index: 1;
    width: 100px;
    height: 100px;
    background-color: pink;
}
.box{
    position: relative;
    z-index:2;
}
.div2{
    float: left;
    width: 150px;
    height: 50px;
    background-color: lightgreen;
}
<div class="div1"></div>
<div class="box">
    <div class="div2"></div>    
</div>

解决方法

[1]元素去除浮动

[2]父级元素的相对定位改成绝对定位

[3]元素添加position属性(static除外)

以上三个方法任一方法都可以,其实就是在破坏bug成立的条件

【3】IE6-浏览器下select的z-index无效而遮挡div

IE6-浏览器下select设置z-index无效,且默认会堆叠在div上

.box{
    left: 30px;
    z-index:2;
    position: absolute;
    width: 100px;
    height: 100px;
    background-color: pink;
}
select{
    width: 100px;
    position: absolute;
    z-index:1;
}
<div class="box"></div>
<select name="select" id="slt1">
    <option value="1">第一项</option>
    <option value="2">第二项</option>
</select>

解决方法

在IE6-浏览器中,虽然div无法覆盖select,但是iframe可以select。所以可以设置一个与div宽高相同的iframe。让div覆盖iframe,iframe覆盖select,最终达到select被div覆盖的效果。

iframe{
    left: 30px;
    position: absolute;
    width: 100px;
    height: 100px;
    z-index: 2;
}
<iframe src="#" frameborder="0"></iframe>
<div class="box"></div>
<select name="select" id="slt1">
    <option value="1">第一项</option>
    <option value="2">第二项</option>
</select>

CSS3

CSS3的出现对过去的很多规则发出了挑战。对层叠上下文z-index的影响更加显著,主要包括以下8个属性

1、z-index值不为auto的flex项(父元素display:flex | inline-flex)

2、元素的透明度opacity值不等于1

3、元素的变形transform不是none

4、元素的mix-blend-mode值不是normal

5、元素的filter值不是none

6、元素的isolation值是isolate

7、will-change指定的属性值为上面的任意一个

8、元素的-webkit-overflow-scrolling设置为touch

设置以上8个属性的任意一个,都和设置absolute类似,层叠上下文z-index会生效。

03. 绝对定位

相较于相对定位和固定定位,绝对定位在实际中应用频率更高、应用场景更广泛。

定义

当元素绝对定位时,会从文档流中完全删除。元素位置相对于最近的已定位祖先元素,如果元素没有已定位的祖先元素,那么它的位置相对于初始包含块document,其边界根据偏移属性放置。元素定位后生成一个块级框,而不论原来它在正常流中生成何种类型的框。定位元素不会流入其他元素的内容,反之亦然。

[注意]如果文档可滚动,绝对定位元素会随着它滚动,因为元素最终会相对于正常流的某一部分定位。

// 滚动滚动条时会发现,绝对定位元素会随着其滚动,但固定定位不会。

特性

absolute和float都可以触发元素的BFC属性,且都具有包裹性和破坏性,所以对于一些应用场景,这两个属性可以进行替换。

【1】包裹性

元素绝对定位后,会为其后代元素建立一个包含块。且若该绝对定位元素不设置宽度,宽度由内容撑开。

[注意]浮动的包含块会延伸,进而包含所有后代浮动元素,但绝对定位的包含块并不会包含后代的定位元素,只是作为后代定位元素的定位父级。

【2】破坏性

元素绝对定位后,会脱离文档流,若父级不设置高度,则父级高度塌陷;若父级为行内元素,无其他内容,则父级宽度也将塌陷

// 父级元素有10px的padding,且背景颜色为天蓝色。

【3】去浮动

元素绝对定位后,元素原来的浮动效果将失效。

【4】偏移特性

如果使用top、right、bottom、left这4个偏移特性来描述元素4个边的放置位置,那么元素的高度和宽度将由这些偏移隐含确定,元素将会拉伸

使用偏移属性拉伸的绝对定位元素,其内部元素支持百分比width/height值。通常情况下,元素高度百分比要想起作用,需要父级窗口的高度值不是auto;但是如果容器由绝对定位拉伸形成,百分比高度值也是支持的。

display

当元素绝对定位后,元素可以改变display属性,但各浏览器解析不一致

【1】IE8+浏览器解析正常

【2】firefox和safari浏览器只有切换为display:none时才会重新渲染,其他值相互切换时无效

【3】chrome浏览器切换到display:inline时渲染无效,其他值相互切换时渲染正常

【4】IE7-浏览器将绝对定位的元素全部渲染为inline-block元素,只有切换为display:none时才会重新渲染,其他值相互切换时无效

[注意]解决IE7-浏览器绝对定位元素渲染为inline-block元素的bug很简单,只需要在绝对定位的元素外面套一个空的<div>即可

<div>
    <div style="position:absolute"></div>
</div>

clip

绝对定位或固定定位元素才可以使用clip属性。绝对定位元素常配合clip属性达到元素隐藏的效果。

.hide{
    position:absolute;
    clip: rect(0,0,0,0);
}

静态位置

当元素绝对定位后,若该元素的格式化属性不发生变化,则该元素处于静态位置。元素的静态位置是指元素在正常流中原本的位置,更确切的讲,顶端的静态位置是从包含块的上边界到假想框的上外边距边界之间的距离。假想框是假设元素position属性为static时元素的第一个框。

但对于居中对齐的行内元素来说,将元素设置为absolute或fixed会发生静态位置跳动问题。而relative或static则不会有此问题。这是因为元素默认的居中对齐是元素的内容中线对应父级块级元素中线,而当元素绝对定位或固定定位之后,定位元素左边界将与其父级块级元素的中线对齐。

overflow

当overflow在绝对定位元素和其包含块之间时,绝对定位元素不会被父级overflow属性剪裁。

可以应用绝对定位元素的overflow属性失效实现按钮外置的效果。

.box{
    width: 100px;
    height: 100px;
    overflow: auto;
}    
.in{
    width: 100%;
    display: inline-block;
    height: 200px;
    background-color: pink;
}
.close{
    position:absolute;
    margin: 0 0 0 -20px;
    font-size: 20px;
    line-height: 20px;
    border: 2px solid;
    border-radius: 50%;
    cursor:pointer;
}
<div class="box">
    <div class="in">测试内容</div><!--             
     --><span class="close">&times;</span>
</div>

应用:

[1] 静态位置

当元素绝对定位后,若该元素的格式化属性不发生变化,则该元素处于静态位置。元素的静态位置是指元素在正常流中原本的位置,更确切的讲,顶端的静态位置是从包含块的上边界到假想框的上外边距边界之间的距离。假想框是假设元素position属性为static时元素的第一个框。

以下是基于绝对定位静态位置的应用:

跟随图标

图标使用不依赖定位父级的absolute和margin属性进行定位,这样,当文本的字符个数改变时,图标的位置可以自适应。

div{
    height: 20px;
    width: 500px;
    line-height: 20px;
    margin-bottom: 30px;
}    
i{
    position: absolute;
    width: 28px;
    height: 11px;
    margin: -6px 0 0 2px;
    background: url('http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/hot.gif');
}
<div>长度可变文字<i></i></div>

视频提示

一般在视频图片上的边角上都会有"自制"、"最新"、"1080p"等诸如此类的提示。使用不依赖的绝对定位属性,可以让父级元素不设置relative,拓展性更强。

i{
    position: absolute;
    width:40px;
    text-align: center;
    height: 18px;
    line-height: 18px;
    font-style: normal;
    background-color: orange;
    color: white;
    padding: 2px;
}    
.box{
    height: 200px;
    width: 200px;
    border: 2px solid gray;
}
.in{
    width: 100%;
    height: 100%;
    line-height: 100px;
    background-color: pink;
    display:inline-block;
}
.rt{
    margin-left: -44px;
}
.lb{
    margin-top: -22px;
}
.rb{
    float: right;
    margin-top: -22px;
    margin-left: -44px;
}
<div class="box">
    <i class="lt">自制</i>
    <div class="in">测试内容</div><!--
    --><i class="rt">独家</i>
    <i class="lb">1080p</i>
    <span style="width: 100%;display:inline-block"></span><!--
    --><i class="rb">最新</i>
</div>

下拉菜单

一般地,下拉菜单作为一个组件需要使用在各种场景中,如果给组件添加relative属性,则降低了其利用率。

body{
    margin: 0;
}    
ul{
    margin: 0;
    padding: 0;
    list-style: none;
}
input{
    padding: 0;
    border: 0;
}
.box{
    width: 200px;
    height: 38px;
    border: 2px solid gray;
}
.con{
    overflow: hidden;
}
.input{
    float: left;
    width: 160px;
    height: 38px;
}
.search{
    width: 38px;
    height: 38px;
    float: right;
    background: url('http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/search.png') 0 -38px;
}
.list{
    display:none;
    position: absolute;
    width: 158px;
    border: 1px solid #e6e8e9; 
    overflow: hidden;
}
.in{
    line-height: 30px;
    border-bottom: 1px solid lightblue;
    cursor:pointer;
    text-indent: 1em;
}
.in:hover{
    background-color: #f9f9f9;
}
<div class="box">
    <div class="con">
        <input class="input" id="input">
        <a href="javascript:;" class="search"></a>
    </div>
    <ul class="list" id="list">
        <li class="in">选项一</li>
        <li class="in">选项二</li>
        <li class="in" style="margin-bottom: -1px">选项三</li>
    </ul>        
</div>
input.onfocus = function(){
    list.style.display = 'block';
}
input.onblur = function(){
    list.style.display = 'none';
}

边缘对齐

很多网站都使用了边缘对齐,但好多都是用页面宽度计算出来的,当宽度变化时需要重新计算。而无依赖的绝对定位利用静态位置,无需计算就可将其位置确定,且拓展性好。

body{
    margin: 0;
}
ul{
    margin: 0;
    padding: 0;
    list-style: none;
}
.box{
    width: 200px;
    height: 100px;
    border: 2px solid black;
    background-color: lightgreen;
}    
.out{
    text-align: right;
}
.list{
    position: absolute;
    margin: 10px 0 0 2px;
    display: inline-block;
}
.in{
    text-align: center;
    width: 20px;
    line-height: 20px;
    margin-top: 4px;
    background-color: pink;
    border-radius: 50%;
}
<div class="box">
    <div class="out">
        <!-- 对于safari浏览器需要添加空格&nbsp;来触发右对齐,其他浏览器则不需要-->
        &nbsp;
        <ul class="list">
            <li class="in">一</li>
            <li class="in">二</li>
            <li class="in">三</li>
        </ul>        
    </div>
</div>

星号

在很多注册或登录页面中,存在用*表示的必填项。**号对齐,文字和文字对齐。这种情况使用静态位置的绝对定位比较合适。

body{
    margin: 0;
}
ul{
    margin: 0;
    padding: 0;
    list-style: none;
}
i{
    font-style: normal;
    color: red;
    position:absolute;
    margin-left: -10px;
}
.list{
    width: 100px;
    padding-left: 20px;
    border: 2px solid black;
    line-height: 2;
}
<ul class="list">
    <li class="in">
        <i>*</i><span>手机号</span>
    </li>
    <li class="in">
        <span>用户名</span>
    </li>
    <li class="in">
        <i>*</i><span>密码</span>
    </li>
</ul>

[2] 偏移属性

当使用偏移属性时,绝对定位元素将相对于包含块进行定位。一般地,我们仅仅使用偏移属性中的两个,且这两个属性不对立。但实际上,对立的偏移属性如left和right可以同时使用,甚至4个偏移属性都可以同时使用,并且可以达到一些意想不到的效果。以下基于绝对定位偏移属性的应用

应用

全屏自适应

实现一个距离屏幕右侧200px的全屏自适应的容器层

.box{
    position: absolute;
    top: 0;
    left: 0;
    right: 200px;
    bottom: 0;
    background-color: pink;
}
<div class="box"></div>

左右半区翻图

一些选项卡中存在左右半区的翻图效果,点击左覆盖区切换到上一张图片,点击右覆盖区切换到下一张图片。

ul{
    margin: 0;
    padding: 0;
    list-style: none;
}
.box{
    position: relative;
    width: 300px;
    height: 200px;
    border: 2px solid lightgray;
    text-align: center;
    font: 40px/200px '宋体';
    color: white;
    overflow: hidden;
}
.list{
    position: absolute;
    width: 400%;
    left: 0;
    top: 0;
    bottom: 0;
    transition: left 1s;
}
.in{
    float: left;
    width: 25%;
    background-color: lightgreen;
}
.l,.r{
    position: absolute;
    opacity: 0;
    top: 0;
    bottom: 0;
    background-color: rgba(0,0,0,0.1);
    cursor: pointer;
}
.l{
    left: 0;
    right: 50%;
}
.r{
    left: 50%;
    right: 0;
}
.l:hover,.r:hover{
    opacity: 1;
    transition: 1s;
}
<div class="box">
    <ul class="list" id="list">
        <li class="in">第1个</li>
        <li class="in">第2个</li>
        <li class="in">第3个</li>
        <li class="in">第4个</li>
    </ul>
    <div class="l" id="l">&lt;</div>
    <div class="r" id="r">&gt;</div>
</div>
var index = 0;
var children = list.children;
l.onclick = function(){
    if(index > 0){
        index --;
        move(index);
    }
}
r.onclick = function(){
    if(index < children.length -1){
        index++;
        move(index);
    }
}
function move(index){
    list.style.left = '-' + index*100 + '%';
}

九宫格

利用绝对定位的偏移属性可以制作宽高自适应的九宫格效果。

ul{
    margin: 0;
    padding: 0;
    list-style: none;
}    
.list{
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
}
.in{
    position: relative;
    float: left;
    height: 33.3%;
    width: 33.3%;
    background-color: pink;
}
.in:before{
    content: '';
    position: absolute;
    left: 10px;
    right: 10px;
    top: 10px;
    bottom: 10px;
    background-color: lightblue;
    border-radius: 10px;
}
.in:after{
    content: attr(data-value);
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    height: 30px;
    margin: auto;
    text-align: center;
    font:bold 24px/30px  '宋体';
}
<ul class="list">
    <li class="in" data-value='1'></li>
    <li class="in" data-value='2'></li>
    <li class="in" data-value='3'></li>
    <li class="in" data-value='4'></li>
    <li class="in" data-value='5'></li>
    <li class="in" data-value='6'></li>
    <li class="in" data-value='7'></li>
    <li class="in" data-value='8'></li>
    <li class="in" data-value='9'></li>
</ul>

等高布局

利用overflow清除浮动的BFC的包裹性,形成一个看似等高的布局,再利用绝对定位模拟出背景和间隔线。

.box{
    width: 80%;
    margin: auto;
    border: 1px solid gray;
    overflow: hidden;
    position: relative;
    background-color: lightgreen;
}
.l{
    box-sizing:border-box;
    float: left;
    width: 25%;
    position: relative;
}
.r{
    box-sizing:border-box;
    float: right;
    width: 75%;
    padding: 10px;
    height: 100%;
}
.con{
    position: absolute;
    background-color: lightblue;
    border-right: 1px solid #ccc;
    height: 9999px;
    width: 100%;
}
.show{
    padding: 10px;
    position: relative;
}
<div class="box">
    <div class="l">
        <div class="con"></div>
        <div class="show">测试文字<br>测试文字<br></div>
    </div>
    <div class="r">测试文字<br>测试文字<br>测试文字<br></div>
</div>

整体布局

整体布局的思路就是利用绝对定位元素的偏移属性来替代固定定位,首先让<page>元素满屏起到<body>元素的作用,然后各个模块各居其位。如果有其他的一些整体的页面遮罩,则与<page>元素平级。

html,body{
    height: 100%;
}
body{
    margin: 0;
}
.page{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}
header,footer{
    position: absolute;
    left: 0;
    right: 0;
    height: 50px;
}
header{
    top: 0;
    background-color: lightgreen;
}
footer{
    bottom: 0;
    background-color: lightcoral;
}
aside{
    position: absolute;
    left: 0;
    top: 50px;
    bottom: 50px;
    width: 250px;
    background-color: lightblue;
}
.content{
    position: absolute;
    top: 50px;
    bottom: 50px;
    left: 250px;
    right: 0;
    overflow: auto;
    background-color: pink;
}
<div class="page">
    <div class="content">
        <div style="height: 1000px">内容区</div>
    </div>
    <aside>侧边栏</aside>
    <header>头部</header>
    <footer>底部</footer>
</div>

04. 相对定位和固定定位

相对定位

定义

可能理解起来最简单的定位机制就是相对定位了。采用这种机制时,通过使用偏移属性移动定位元素。当元素相对定位时,它会从其正常位置移走,不过,原来所占的空间并不会因此消失。相对定位元素,会为其所有子元素建立一个新的包含块。这个包含块对应于该元素原本所在的位置

[注意]如果相对定位元素遇到过度受限的问题,一个值会重置为另一个值的相反数。bottom总是等于-top,right总是等于-left。

百分比

非常奇怪的是,虽然相对定位的数值型偏移属性是相对于自身的,但其百分比却是相对于包含块的。top和bottom百分比相对于包含块的高度(只是高度height,不包括纵向padding和border),left和right百分比相对于包含块的宽度(只是宽度width,不包括横向padding和border)

[注意]对于IE7-和firefox浏览器来说,若包含块的高度height为auto,则百分比的top和bottom设置有效果,而其他浏览器则都没有效果 。

特性

【1】限制范围

一般地,给绝对定位元素限制范围时,为其父级元素设置相对定位relative,因为相对定位元素不脱离文档流

[注意]相对定位元素可以限制绝对定位,但不能限制固定定位,因为固定定位是相对于视窗定位的

【2】提升层级

当想要提升元素层级,又不想脱离文档流时,使用相对定位是一个好主意

行内元素

不同于绝对定位元素可以使元素具有块级元素属性,相对定位应用于inline元素后,由于无法改变其行内元素的属性,不具备块级元素属性,无法设置宽高,其上下margin也依然存在问题。

IE兼容

在IE6浏览器下,haslayout下的元素负margin超出父元素的部分会被隐藏掉。这个问题可以通过设置margin负值元素的position属性值为relative来解决。

固定定位

固定定位与绝对定位很类似,元素会完全从文档流中去除,但固定元素的偏移是相对于视窗。

[注意]IE6-浏览器不支持

特性

固定定位与绝对定位的很多特性都类似,具有包裹性、破坏性及去浮动的特性,关于各浏览器中display属性的bug、clip属性的隐藏功能、静态位置跳动以及overflow失效的表现都相同,在此就不再赘述。

全屏遮罩

当页面内容超出页面容器大小出现滚动条时,此时使用absolute全屏遮罩会出现滚动条以外部分没有遮住的情况。因为根元素html的父级是document,document的高度和可视区域一致,也就是与视窗一致,是不包括滚动条以外部分的。

这时,只能使用fixed固定定位来实现全屏遮罩效果。

.page{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: pink;
    z-index: -1;
}    
.test{
    width: 2000px;
    height: 200px;
    background-color: lightblue;
}
<div class="page" id="page"></div>
<div class="test"></div>    
<button>absolute</button>
<button>fixed</button>
var btns = document.getElementsByTagName('button');
for(var i = 0; i < btns.length; i++){
    btns[i].onclick = function(){
        page.style.position = this.innerHTML;
    }
}