CSS中的流与定位

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_44196299/article/details/99655645

什么是流

页面中的元素默认是如何排列呢?为何有的元素我们没有设置宽度却自动填满一行?种种这些疑问都让我们要去探索页面布局的核心:流。
什么是流?在W3C的文档中将CSS的基本定位机制和布局方式称为标准流(或称标准文档流),不过张鑫旭老师在《CSS世界》中将之称为流,这种说法更能凸显出这种布局方式像水流一样自然自动,因此本篇博客也采用了流这个说法,因此“流”就是是html元素默认的布局机制,是html元素没有添加任何CSS属性时的布局方式。

块级元素与内联元素

HTML按照功能将标签一般分为容器级标签与文本级标签,常见的标签列举如下:

  • 文本级标签:p、span、a、b、i、u、em
  • 容器级标签:div、h1~h5、li、dt、dd

其中,除了p以外的所有文本级标签都是内联元素,所有的容器级标签都是块级元素。从表现来说,内联元素的典型特征就是可以和文字在一行显示。实际上文字也是内联元素,图片、按钮、输入框、下拉框等元素也是内联元素。实际开发中,我们经常把display计算值为inline inline-block inline-table table-cell的元素叫做内联元素,而把display计算值为block、table的元素叫做块级元素。注意li元素的display属性为list-item,它也是块级元素。

块级元素和内联元素的主要区别为:

  • 对于块级元素,流体布局之下width: auto自适应撑满父元素宽度。这里的撑满并不同于width: 100%的固定宽度,而是像水一样能够根据margin不同而自适应父元素的宽度。如果给块级元素指定的宽度过小则会由margin自动填充,过大则页面会自动添加scroll。
  • 对于内联元素,width: auto则呈现出包裹性,内联元素不能设置宽高,宽度由子元素的宽度决定。
  • 无论内联元素还是块级元素,height: auto都是呈现包裹性,即高度由子级元素撑开。
  • 注意父元素height: auto会导致子元素height: 100%百分比失效。

注:正常流下,如果块级元素的width是个固定值,margin是auto,则margin会撑满剩下的空间;如果margin是固定值,width是auto,则width会撑满剩下的空间。这就是流体布局的根本所在。

元素的定位

在实际页面开发中我们往往要对页面进行各种布局,因此我们可能需要使某个元素脱离流布局的限制,目前为止CSS中有两种手段使一个元素脱离标准文档流,一种是浮动,另一种就是绝对定位,下面我们介绍元素的定位。
CSS3中position属性可选的值如下:

  • static:默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index声明)。
  • relative:生成相对定位的元素,相对于其正常位置进行定位,遵循标准文档流,但将依据top,right,bottom,left等属性在正常文档流中偏移位置,而其层叠通过z-index属性定义。
  • absolute:生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位,脱离标准文档流,元素的位置通过 left, top,right 以及bottom属性进行规定,其层叠通过z-index属性定义。
  • fixed:生成绝对对定位的元素,相对于浏览器窗口进行定位,脱离标准文档流,元素的位置通过 left, top, right以及bottom 属性进行规定,当出现滚动条时,对象不会随着滚动,其层叠通过z-index属性定义。
  • inherit:规定应该从父元素继承 position 属性的值。

1、position: static
默认值,无特殊定位,遵循正常的流特性,在静态定位模式下top、right、left、bottom及z-index属性都是无效的。

2、position: absolute
absolute绝对定位脱离了标准文档流,元素可以通过left、top、right和bottom属性进行定位,定位参考元素为第一个非static定位的祖先元素,这儿需要注意如果该祖先元素是纯inline元素,则规则略复杂:

  • 假设给内联盒子的前后各生成一个宽度为零的内联盒子,则这两个内联盒子的padding box外面的包围盒就是内联元素的定位和计算的参考元素;
  • 如果该内联元素被跨行分割了,那么包含块是未定义的,也就是 CSS 2.1规范并没有明确定义,浏览器自行发挥。

否则,进行定位和计算的参考元素由该祖先的padding box边界形成。如果向上一直没有找到符合条件的祖先元素则以根元素(大多数情景下可以直接视为html元素,其尺寸等同于浏览器可视窗口的大小)作为参考,absolute绝对定位也支持通过z-index属性来设置层级。
position: absolute的特性可以概括为“块状化”,“包裹性”和“破坏性”。
首先是“块状化”,position: absolute的特性“块状化”和float属性类似,当一个元素的position属性值为absolute或fixed,那么该元素的display属性的计算值就是block或table。示例:

var span = document.createElement('span');
document.body.appendChild(span);
console.log(window.getCompoutedStyle(span).display); // inline
span.style.position = 'absolute';
console.log(windiw.getComputedStyle(span).display); // block

然后是“破坏性”,这一点也和float属性类似,它们都破坏了正常的流特性,但是虽然absolute破坏正常的流来实现自己的特性表现,但是本身还是受到普通的流体元素布局、位置乃至一些内联相关的CSS属性影响的,关于这种影响最典型的应用就是“无依赖的absolute绝对定位”。
很多人错误地认为凡是使用absolute绝对定位的地方,一定要将父容器的position属性设为relative,同时通过left/top等属性进行定位,甚至必须同时使用z-index属性设置层级,但需要注意,**absolute是非常独立的CSS属性值,其样式和行为表现不依赖其他的任何CSS属性就可以完成。**而当不添加left、top等属性时元素仍出现在当前位置,(一般把这种没有设置left/top/right/bottom属性值的绝对定位称为“无依赖绝对定位”)示例:

<style type="text/css">
	#container {
		width: 200px;
		height: 200px;
		border: 2px solid gray;
	}
	#box {
		position: absolute;
	}
</style>
<body>
	<div id="container">
		<div id="box">absolute绝对定位</div>
	</div>
</body>

页面效果:
在这里插入图片描述
这种“无依赖的absolute绝对定位”在大多数场景下要比使用left/top之类的属性定位要实用和强大得多,因为其除了其代码更加简洁外还有一个很棒的特性,就是“相对定位特性”,实际上“无依赖绝对定位”实质上就是相对定位,但是相较于相对于相对定位,它多了一条特性:不占据标准文档流的内存空间,我们通过下面示例展现“无依赖绝对定位”的强大之处:
HTML代码:

<div class="nav">
    <h4 class="nav-list">
        <a href class="nav-a">普通导航</a>
    </h4>
    <h4 class="nav-list">
        <a href class="nav-a">
            热门导航<i class="icon-hot"></i>
        </a>
    </h4>
    <h4 class="nav-list">
        <a href class="nav-a">
            新导航<i class="icon-new"></i>
        </a>
    </h4>
</div>

CSS代码:

.nav {
    display: table;
    table-layout: fixed;
    width: 100%;
    max-width: 600px;
    margin: 1em auto; 
    background-color: #333;
    text-align: center;
}
.nav-list { 
    display: table-cell;
    font-weight: 400;
}
.nav-a { 
    display: block; 
    line-height: 20px; 
    padding: 20px; 
    color: #bbb; 
    text-decoration: none; 
}
.nav-a:hover { 
    color: #fff; 
}
.icon-hot { 
    position: absolute; 
    width: 28px; height: 11px; 
    margin: -6px 0 0 2px; 
    background: url(hot.gif);
}
.icon-new { 
    position: absolute; 
    width: 12px; 
    height: 13px; 
    margin: -6px 0 0 2px; 
    background: url(new.png) no-repeat center;
}

页面效果:
在这里插入图片描述
关于absolute定位的“包裹性”:absolute天然具有“包裹性”(即尺寸收缩包裹,同时具有自适应性),但是,和float或其他的“包裹性”带来的“自适应性”相比,absolute有一个平时不太被人注意的差异,那就是absolute的自适应性的最大宽度往往不是由父元素决定的,这是由于absolute定位和计算的参考元素的不同,示例:

<style>
	#container {
		width: 200px;
		border: 1px solid gray;
		position: relactive;
	}
	#box {
		position: absolute;
	}
</style>
<body>
	<div id="container">
		<div id="box">absolute绝对定位天然具有“包裹性”(即尺寸收缩包裹,同
		时具有自适应性),但是,和float或其他的“包裹性”带来的“自适应性”相比,
		absolute有一个平时不太被人注意的差异,那就是absolute的自适应性的最
		大宽度往往不是由父元素决定的,这是由于absolute定位和计算的参考元素的
		不同</div>
	</div>
</body>

页面效果:
在这里插入图片描述
从上图我们可以看出,当绝对定位元素没有设置宽度相关属性的时候,其宽度由里面的元素和外面的进行定位和计算的参考元素共同决定,container元素出现高度坍塌的原因是absolute绝对定位破坏了标准文档流,这也正是absolute绝对定位的破坏性。

3、position: relative
relative的定位有两大特性:一是相对自身,二是无侵入。
“相对自身”是指relative定位中偏移位置以元素在原本标准文档流中应该出现的位置为参考;“无侵入”是指当relative进行定位偏移的时候,一般情况下不会影响周围元素的布局。
示例:

<html>
<head>
	<style type="text/css">
 		#first{
 			width: 200px; 
 			height: 200px; 
 			border: 2px solid red
 		}
 		#second{
 			width: 200px; 
 			height: 200px;
 			border: 2px solid green;
 			position: relative;
 			top :50;
			left : 50
		}
	</style>
</head>
<body>
	 <div id="first">静态定位</div>
	 <div id="second">相对定位</div>
</body>
</html>

页面结果:
在这里插入图片描述
relative的定位还有另外两点值得一提,相对定位元素的left/top/right/bottom的百分比值是相对包含块计算的,而不是自身。注意,虽然定位位移是相对自身,但是百分比值的计算值不是。
top和bottom这两个垂直方向的百分比值计算跟height的百分比值计算是一样的,都是相对高度计算的。同时,如果包含块的高度为auto,那么计算值是0,偏移无效,也就是说如果父元素没有设定高度或者不是“格式化高度”,那么relative类似top: 20%的代码等同于top: 0。
当相对定位元素同时应用对立方向定位值的时候,也就是top/bottom和left/right同时使用的时候,其表现和绝对定位差异很大,绝对定位是尺寸拉伸,保持流体特性,但是相对定位却是“你死我活”的表现,也就是说,只有一个方向的定位属性会起作用,而孰强孰弱则是与文档流的顺序有关,默认的文档流是从上而下,从左往右,因此top/bottom同时使用的时候,bottom被干掉,left/right同时使用的时候,right毙命。
示例:

.examole {
	position: relative;
	top: 10px;
	left: 10px;
	right: 10px; /*无效*/
	bottom: 10px; /*无效*/
}

4、position: fixed
position: fixed固定定位元素的“包含块”是根元素,我们可以将其近似看成<html>元素。换句话说,唯一可以限制固定定位元素的就是<html>根元素。所以如果是想把某个元素固定定位在某个模块的右上角,下面这种做法就是没有用的:

<div class="father">
	<div class="son"></div>
</div>
.father {
	width: 300px;
	height: 200px;
	position: relative;
}
.son {
	width: 40px;
	height: 40px;
	position: fixed;
	top: 0;
	right: 0
}

但是,并不是说我们无法把.son元素精确定位到.father元素的右上角,事实上是可以实现的,如何实现呢?和“无依赖绝对定位”类似,就是无依赖的固定定位,利用absolute/fixed元素没有设置left/top/right/bottom的相对定位特性,可以将目标元素定位到我们想要的位置,例如:

<div class="father">
	<div class="right">
		&nbsp;<div class="son"></div>
	</div>
</div>
.father {
	width: 300px;
	height: 200px;
	position: relative
}
.right {
	height: 0;
	text-align: right;
	overflow: hidden;
}
.son {
	display: inline;
	width: 40px;
	height: 40px;
	position: fixed;
	margin-left: -40px;
}

注:position: fixed的absolute模拟
有时候我们希望元素既有不跟随滚动的固定定位效果,又能被定位元素限制和精准定位,那我们该怎么办呢?
我们可以使用position: absolute进行模拟,原理其实很简单,页面的滚动使用普通元素代替,此时滚动元素自然就有了”固定定位“的效果了。常规的html结构和css代码是下面这样的:

<html>
	<body>
		<div class="fixed"></div>
	</body>
</html>
.fixed {
	position: fixed;
}

使用position: absolute进行模拟则需要一个滚动容器,假设类名是.page,则有:

<html>
	<body>
		<div class="page">固定定位元素</div>
		<div class="fixed"></div>
	</body>
</html>
html,body {
	height: 100%;
	overflow: hidden;
}
.page {
	height: 100%;
	overflow: auto;
}
.fixed {
	position: absolute;
}

整个网页的滚动条由.page元素产生,而非根元素,此时虽然.fixed元素是绝对定位,但是并不在滚动元素内部,自然滚动时不会跟随,如同固定定位效果,同时本身绝对定位,因此,可以使用relative进行限制或者overflow进行裁剪等。然而,将网页的窗体滚动变成内部滚动,很多窗体滚动相关的小JavaScript组件需要跟着进行调整,并且可能会丢失其他一些浏览器内置行为,需要谨慎使用。

猜你喜欢

转载自blog.csdn.net/weixin_44196299/article/details/99655645