无依赖绝对定位的应用
参考张鑫旭慕课网绝对定位课程:https://www.imooc.com/learn/192
含义、特点:
- 无依赖的绝对定位:当绝对定位元素不使用top/right/bottom/left中任何一个属性时,或者上述四个偏移量都使用auto取值时,该绝对定位元素不受其参照物的限制,又可以称为无依赖的绝对定位元素。
- 特点1:是一个无宽、高的浮动元素,因此会尽可能向上浮动。
- 特点2:位置跟随性,即原来是block水平元素的换行显示行为,在绝对定位以后仍是换行显示,即原来在某个块级元素(普通文档流)之上或者之下,绝对定位以后依然在该元素的上方或者下方;原来是inline或者inline-block水平元素的同行显示行为在绝对定位以后仍是同行显示,也就是如果原来是跟在某个行内元素(普通文档流)后面或者前面,在无依赖绝对定位以后依然在该元素后面或者前面。
- 特点3:对于含有无依赖absolute元素的父级元素DOM结构的布局行为:首先确定当前的普通文档流DOM结构:将普通文档流中的元素按照在DOM结构中的先后顺序进行摆放,确定当前的布局。接着判断无依赖absolute元素,按照DOM结构以此判断,如果多个绝对定位元素相互遮挡,那么按照七层层叠顺序+后来居上+大者居上的准则判断。
应用:
应用主要是与margin结合、与text-align结合。注意:绝对定位元素无论是否设置偏移量,都可以使用margin。具体包括:
- 图片的图标定位:左上角定位和右上角定位,可延伸到非图片的左上角、右上角定位
- 下拉框:最佳实践
- 星号和文字的对齐
- 小图标和文字的对齐:这个图片可以是img,也可以是只含背景图片的空标签
- 文字溢出的处理
- 对齐或者居中:与text-align结合(待整理)
1.图片的小图标定位,左上角定位和右上角定位
1.1 图片的小图标定位
效果:“推荐”和“VIP”分别在图片的左上角和右上角,这里我们没有使用图标,而是用文字代替的。
DOM结构:
- 左上角的图标要放在图片DOM结构的上方,右上角图标要放在图片DOM结构的下方。
- 由于三个元素都是inline或者inline-block元素,因此三者之间会有间隙,需要处理一下。(一定要处理,否则有问题,下面会分析。)
方法:
- 三个元素的包含块div设置diplay为inline-block,包裹性。
- span.left和span.right进行无依赖的绝对定位(block化),并设置宽度、行高(单行文本垂直居中)、文字水平对齐、背景色。
- 绝对定位以后脱离文档流,此时div中只包含图片,因此div尺寸变为图片的尺寸,图片占满整个div。
- 三个元素原本都是inline水平元素,因此当绝对定位以后,水平方向会有跟随性,span.left会跟在图片的左边,span.right会跟在图片的右边,且二者尽可能向上浮动。
- 由于图片已经在包含块的最左侧了,而span.left要跟随在图片的左侧,因此只能与图片发生重叠。
- 对span.left使用margin-left:-width;将其移动到右上角。
<div>
<span class="left">推荐</span><!--
--><img src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2096432854,4113309096&fm=26&gp=0.jpg"
width="150" height="150" alt="Some of a team"><!--
--><span class="right">VIP</span>
</div>
div {
display: inline-block;
color:white;
}
img {
vertical-align: middle;/*消除图片下方的空隙*/
}
span.left,span.right {
position: absolute;
width:35px;
line-height: 30px;/*单行文本垂直居中*/
text-align: center;/*绝对定位以后span变成block元素,可以用text-align*/
}
span.left {
background-color: deeppink;
}
span.right {
background-color: deepskyblue;
margin-left: -35px;
}
详细分析(HTML结构不变):
(1)初始代码
div {
color:white;/*文本颜色,可继承*/
background-color: blueviolet;
}
(2)为div进行inline-block化
div {
display:inline-block;
}
(3)span.left和span.right进行无依赖的绝对定位,并添加背景色
span.command,span.vip {
position: absolute;
}
span.command {
background-color: deeppink;
}
span.vip {
background-color: deepskyblue;
}
(4)消除图片下方的空隙,对img设置vertical-align:middle;
img {
vertical-align: middle;
}
(5)span.left的位置已经符合要求了,现在要把span.right移动到右上角,用margin-left等于自身宽度的负值,因此需要知道它的宽度,所以这里为它们设置宽度35px,并对span.right设置margin-left:-35px;
span.left,span.right{
width:35px;
}
span.right{
margin-left:-35px;
}
(6)基本实现了效果,下面微调span.left和span.right的样式,设置垂直对齐和水平对齐
span.left,span.right{
line-height: 30px;/*单行文本垂直居中*/
text-align: center;/*绝对定位以后span变成block元素,可以用text-align*/
}
1.2 图片的小图标定位——间隙问题
对于上述代码,如果我们将span.left、span.right与img之间的间隙处理去掉,也就是带有回车换行符,其他不变我们来看看效果
很奇怪,我们进一步把span.right的margin-left去掉,并且给父元素div添加背景色,来看看无依赖绝对定位初始效果,可以看出,此时虽然父元素只包含img,即span.left和span.right成功脱离了文档流,而且span.left的定位也没问题,但是span.right却换行了,看起来没有实现位置跟随,原因肯定是因为span.right和img之间存在间隙。
进一步我们把父元素div的display:inline-block去掉,也就是让其恢复本身的block,此时可以看出,span.right放在了应该放的位置
进一步我们给span.right设置margin-left:-35px,效果也是可以的,只不过这种方式下,父元素标签只能是block了
接着我们想尝试一下,如果将父元素也变成绝对定位,会是什么效果,可以看出,这回到了最初的那个问题,也就是与display:inline-block时的问题一样,那么就不禁让人想到是否因为display:inline-block、display:absolute之间某个共同的特性导致无法跟随的呢?(position:relative;时不会影响效果,与position:static;时的效果一样),所以大胆猜测,可能是与BFC有关。不知道对不对。
- 总之,对于多个inline-block水平的元素,最好将它们之间的空隙处理一下,那么就不会出现无法成功跟随的问题了,这样它们的 父元素可以按照需求设置,一般设置为display:inline-block实现包裹性。
- 接下来的例子中,我们都去除了多个inline或者inline-block元素之间的空隙。本文的例子出自张鑫旭的慕课网课程,他给的代码中也都对inline-block间隙进行了处理。
- 去除inline-block元素之间空隙的方法见张鑫旭的博文:https://www.zhangxinxu.com/wordpress/2012/04/inline-block-space-remove-%E5%8E%BB%E9%99%A4%E9%97%B4%E8%B7%9D/
1.3 非图片的小图标定位
想让图标在文字的右上角,那么在DOM结构中,图标就应该在文字的下方。此外,由于对图标绝对定位以后,图标会脱离文档流,因此最好让父标签具有“包裹性”,只包含住核心内容,本例中的父标签<a>有类似的效果,但是为其设置inline-block更好,因为能够设置尺寸,增大点击区域等好处。
然后图标可以用background-image来设置,这里为了简单起见,用的都是文字。
<a>
精选课程<span>HOT</span>
</a>
a {
display:inline-block;
}
a span {
color:red;
position: absolute;
margin-top: -10px;
}
2.下拉框最佳实践
2.1 下拉框在可视元素DOM结构上方
DOM结构:下拉框在可视元素(这里为a标签)的上方。
思路:
- 父标签div进行inline-block化,包裹性。由于下拉框绝对定位,因此父标签div只包含a标签。
- 下拉框元素绝对定位,并且设置很大的margin-top负值进行隐藏。
- 当对父元素div进行hover或者focus时,将margin-top设置为合理值,这里为a标签高度值。
- margin-top的选取:根据无依赖绝对定位的跟随性。本例子中绝对定位元素ul本来在a标签(inline-block)DOM结构的上方,当绝对定位以后,具有包裹性的div只包含a标签,而ul为了跟随a标签,应该在a标签的上方,但是a标签已经在最上方了,所以ul覆盖了a标签。所以应该设置margin-top,从而让ul标签下移至将a标签显示出来。
- 本例中背景颜色、边框、显示与隐藏之类的操作主要是为了增强交互替换和视觉效果,可以自行定义。
div未hover div进行hover时
<div>
<ul>
<li>橘子</li>
<li>苹果</li>
<li>圣女果</li>
</ul>
<a>水果</a>
</div>
div {
display: inline-block;/*父元素包裹性*/
color:white;
text-align: center;/*让后代元素a和li都继承*/
}
a {
display: inline-block;/*可对a设置width*/
width: 70px;
line-height: 35px;/*垂直居中,且等于a的height*/
background-color: orange;
}
div:hover ul,div:focus ul {
margin-top: 35px;/*下拉框显示*/
}
ul {
list-style-type: none;
position: absolute;
width:70px;
margin-top:1000px;/*下拉框隐藏*/
}
ul li {
border-top:1px solid;
background-color: orangered;
}
2.2 下拉框在可视元素DOM结构下方
效果同2.1
该方法与2.1的区别只有2点:
- DOM结构不同,此时下拉框在a标签的下方,因此在无依赖绝对定位跟随时,会跟在a标签的下方
- 控制下拉框显示与隐藏的方法不一样,本例没有使用margin-top,而是使用top
- 下拉框显示时,top值为auto,也就是无依赖绝对定位
- 下拉框隐藏时,top设置为一个很大的值,这个其实不是无依赖绝对定位了,是相对于参照物(初始包含块)设置的。
- 当然,虽然这个例子中的下拉框没使用margin-top进行显示与隐藏,但是也可以设置margin-top来微调下拉框的位置的,因为绝对定位元素本身是可以使用margin的。
- 此外,这里的top也可以换成left、bottom,都可以,因为此时无依赖绝对定位的位置已经符合要求了。
问题:绝对定位元素可以使用哪些属性?绝对定位元素的包含块元素设置的哪些属性能够影响绝对定位元素?绝对定位元素的父元素设置的哪些属性能够影响或者不能影响绝对定位元素?
<div>
<a>水果</a>
<ul>
<li>橘子</li>
<li>苹果</li>
<li>圣女果</li>
</ul>
</div>
div {
display: inline-block;/*父元素包裹性*/
color:white;
text-align: center;/*让后代元素a和li都继承*/
}
a {
display: inline-block;/*可对a设置width*/
width: 70px;
line-height: 35px;/*垂直居中,且等于a的height*/
background-color: orange;
}
div:hover ul,div:focus ul {
top:auto;/*下拉框显示*/
}
ul {
list-style-type: none;
position: absolute;
width:70px;
top:1000px;/*下拉框隐藏*/
}
ul li {
border-top:1px solid;
background-color: orangered;
}
3.星号与文字的对齐
效果
选中label时的效果
- 选中label元素时,可以看出,此时label元素已经不包含这个星号(*)了,因此星号脱离了普通文档流。这里的margin-left为-1em即可,用字号的倍数做单位在此处较为合适。
- 这个与第1节图片图标对齐中的左上角图标定位思路类似,只不过此时是尺寸相当的文字之间的定位。
- 这里其实也可以为label设置padding-left:1em,以此将星号放置在label的左内边距中。
<label class="regist-label">
<span class="regist-star">*</span>登录邮箱
</label>
label.regist-label {
width:70px;
float: left;
padding-top:10px;
}
.regist-label .regist-star {
color:red;
position: absolute;
margin-left: -1em;
}
4.小图标与文字的对齐
效果
选中span时的效果
1. 本例子就是将小图标放在父元素的padding中
2. 里面的i标签需要首先设置其尺寸,但是i标签为inline,所以我们将其设置inline-block,并设置width和height
3. i的尺寸设置好以后,为i添加合适的背景图像、重复方式、背景图像定位方式,此时小图标与文字没有对齐,这是因为小图标与文字此时都是默认基线对齐的,我们添加背景颜色方便分析。
4(个人理解).为了实现小图标与文字的对齐,我们将i设置为absolute,会发现i水平位置确实实现了位置跟随,但是垂直方向向上移动了,这是因为无依赖绝对定位的垂直方向会尽可能上浮,直到包含块的顶部,而这个包含块其实是将无依赖绝对定位看做是static时的包含块,也就是离它最近的block、inline-block、table-cell元素的content box。而此时span元素是inline,所以会寻找span上方的其他包含块。
5.为了解决上述span元素无法限制住绝对定位的i标签的垂直方向的问题,我们可以对span元素inline-block化,或者是也absolute(绝对定位元素此时可以看做block,可以限制i的垂直方向),我们选择inline-block化,效果为
6.步骤5已经成功限制了i的垂直位置,下面就对小图标的水平位置进行处理,为span添加padding-left:小图标宽度,此处为20px,同时给i进行margin-left:自身宽度的负值,-20px,效果为
7.至此完成,我们去掉背景色即可,最终效果为
<span class="regist-mark regist-warn">
<i class="icon-warn"></i>邮箱格式不正确
</span>
.regist-mark {
position: absolute;/*为无依赖绝对定位元素提供包含块*/
padding-top:9px;
}
.regist-warn {
padding-left:20px;/*为小图标提供位置*/
}
.icon-warn {
display: inline-block;/*在有绝对定位以后,此设置可以省略*/
width:20px;
height:21px;
background: url(http://img.mukewang.com/5453084a00016ae300120012.gif) no-repeat center;
position: absolute;/*无依赖绝对定位*/
margin-left:-20px;/*整个i标签左移自身宽度20px*/
}
5.文字溢出的处理
绝对定位元素可以认为无尺寸的浮动元素,因此即使溢出,也不会换行。效果为
<div class="regist-cell">
<input type="password" class="regist-input"><span class="regist-mark">
请输入6-16位密码,区分大小写,不能使用空格</span>
</div>
.regist-cell {
display: inline-block;
}
.regist-cell .regist-input {
width:260px;
height:16px;
padding:10px 5px;
margin-right:10px;
border: 1px solid #d0d6d9;
}
.regist-cell .regist-mark {
position: absolute;
padding-top:9px;
}
这里再提一下inline-block元素之间的空隙问题。如果我们将上述代码中input和span之间进行换行,即有空隙
<div class="regist-cell">
<input type="password" class="regist-input">
<span class="regist-mark">请输入6-16位密码,区分大小写,不能使用空格</span>
</div>
CSS代码不变,那么span元素会换行
接着,我们如果把父元素div的display:inline-block改为block,那么效果又正常了,但是这修改了父元素的display样式,有改变父元素兄弟元素布局的风险。
注意:这里只是一个演示,正确的做法最好还是在写HTML代码的时候就去掉inline-block元素之间的因为换行而带来的空隙。
6.完整实例:注册页面
6.1 效果图
6.2 登录邮箱、登录密码
- 登录邮箱和登录密码后面的span.regist-mark、span.regist-warn整体是一个无依赖absolute元素,因此脱离文档流,且跟随在相应input元素右面。
- 而登录邮箱中的<i>标签(小图标)又是一个无依赖absolute元素,虽然它脱离文档流,但是其还是被绝对定位的span.regist-mark包含了,所以其向上“浮动”时会受到包含块的限制。如果父元素是inline-block元素,也是被包含。
- 疑问:不知道这种现象是将无依赖absolute元素看作是static,然后确定其包含块(离它最近的block、inline-block、table-cell元素),还是inline-block父元素、absolute父元素的BFC所引起的?
6.3 验证码部分
效果
需要注意的是:
- input与图片二者之间的垂直对齐,这里对input设置vertical-align:top,由于图片与基线对齐,最高点就是图片的顶部,所以input与图片顶部对齐。
- 这也提醒了一点,替换行内元素一般都会有垂直对齐方面的细节调整,可以将本例子中所有的input都设置为vertical-align:top。
<div class="regist-group">
<label class="regist-label">
<span class="regist-star">*</span>验证码
</label>
<div class="regist-cell">
<input type="text" class=" regist-input regist-code-input"><img src="http://img.mukewang.com/545308540001678401500040.jpg">
</div>
</div>
.regist-code-input {
width:130px;
vertical-align:top;
}
6.4 协议与注册部分
效果
- 效果图中把验证码的部分也截图了是为了显示出,协议与注册部分是和上方input部分左对齐的。这里把复选框、复选框的label,以及立即注册按钮都放在了regist-cell中,最外面的label用一个 进行占位。
- 选中label的效果
3.选中regist-cell的效果
<div class="regist-group">
<label class="regist-label">
</label>
<div class="regist-cell">
<input type="checkbox"><label>
我已阅读并同意<a href="##">慕课协议</a>。</label>
<p>
<a href="javascript:" class="regist-btn">立即注册</a>
</p>
</div>
</div>
.regist-btn {
text-decoration: none;
display: inline-block;
color:white;
background-color: deeppink;
width:160px;
line-height: 40px;
text-align: center;
}
p {
padding:10px 0;
}
6.5 regist-head部分
<div class="regist-head">注册</div>
.regist-head {
line-height: 60px;
background-color: deeppink;
color:white;
padding-left: 30px;
font-size: 18px;
}
6.6 body背景颜色、字体、行高、regist-body背景颜色
body {
font: 14px/1.4 "Microsoft YaHei";
background-color: #EDEFF0;
}
.regist-body {
background-color: white;
}
6.7 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
<style type="text/css">
* {margin:0;padding:0;}
body {
font: 14px/1.4 "Microsoft YaHei";
background-color: #EDEFF0;
}
.regist-body {
background-color: white;
}
div.constr {
width:1200px;
margin:0 auto;
}
.regist-body{
padding:100px 0;
}
.regist-body .regist-main {
width:600px;
margin:0 auto;
}
.regist-group {
margin:20px 0;
overflow:hidden;
}
label.regist-label {
width:70px;
float: left;
padding-top:10px;
}
.regist-label .regist-star {
color:red;
position: absolute;
margin-left: -1em;
}
.regist-cell {
display: inline-block;
}
.regist-input {
width:260px;
height:16px;
padding:10px 5px;
margin-right:10px;
border: 1px solid #d0d6d9;
}
.regist-cell .regist-mark {
position: absolute;
padding-top:9px;
}
.regist-warn {
padding-left:20px;
}
.icon-warn {
display: inline-block;
width:20px;
height:21px;
background: url(http://img.mukewang.com/5453084a00016ae300120012.gif) no-repeat center;
position: absolute;
margin-left:-20px;
}
.regist-code-input {
width:130px;
vertical-align:top;
}
.regist-btn {
text-decoration: none;
display: inline-block;
color:white;
background-color: deeppink;
width:160px;
line-height: 40px;
text-align: center;
}
p {
padding:10px 0;
}
.regist-head {
line-height: 60px;
background-color: deeppink;
color:white;
padding-left: 30px;
font-size: 18px;
}
</style>
</head>
<body>
<div class="constr">
<div class="regist-head">注册</div>
<div class="regist-body">
<div class="regist-main">
<div class="regist-group">
<label class="regist-label">
<span class="regist-star">*</span>登录邮箱
</label>
<div class="regist-cell">
<input type="email" class="regist-input"><span class="regist-mark regist-warn">
<i class="icon-warn"></i>邮箱格式不正确
</span>
</div>
</div>
<div class="regist-group">
<label class="regist-label">
<span class="regist-star">*</span>登录密码
</label>
<div class="regist-cell">
<input type="password" class="regist-input"><span class="regist-mark">
请输入6-16位密码,区分大小写,不能使用空格</span>
</div>
</div>
<div class="regist-group">
<label class="regist-label">
<span class="regist-star">*</span>用户昵称
</label>
<div class="regist-cell">
<input type="text" class="regist-input">
</div>
</div>
<div class="regist-group">
<label class="regist-label">
手机号码
</label>
<div class="regist-cell">
<input type="tel" class="regist-input">
</div>
</div>
<div class="regist-group">
<label class="regist-label">
<span class="regist-star">*</span>验证码
</label>
<div class="regist-cell">
<input type="text" class=" regist-input regist-code-input"><img src="http://img.mukewang.com/545308540001678401500040.jpg">
</div>
</div>
<div class="regist-group">
<label class="regist-label">
</label>
<div class="regist-cell">
<input type="checkbox"><label>
我已阅读并同意<a href="##">慕课协议</a>。</label>
<p>
<a href="javascript:" class="regist-btn">立即注册</a>
</p>
</div>
</div>
</div>
</div>
</div>
</body>
</html>