📔前言
在Web开发中,掌握CSS布局对于提高页面开发效率至关重要。随着Web技术的不断演进,实现各种布局的方法层出不穷。
最近,我利用零散时间花费了半个月整理了一系列文章。本系列总结了CSS中各种布局以及实现方式及常用技巧,通过阅读这些文章,你将对CSS布局有全新的认识。
📔position 属性简介
position 属性是CSS布局中的一个关键属性,用于定义元素在文档中的定位方式。通过 top、right、bottom 和 left 属性,可以确定元素最终的位置。
该属性包含以下五个取值:
static: 默认值,表示正常布局行为,此时设置 top、right、bottom、left 和 z-index 属性均无效。
relative: 将元素设置为相对定位元素,不会脱离文档流。
absolute: 将元素设置为绝对定位元素,使其相对于最近的非 static 定位祖先元素进行定位。
fixed: 将元素设置为固定定位元素,相对于视窗进行定位。
sticky: 将元素设置为粘性定位元素,一开始不脱离文档流,当到达某个位置时,相对于视口进行定位。
🍚absolute 属性值
基本性质
与 float 属性类似,具有相似的包裹性和破坏性特征:
包裹性: 元素的宽度会自动调整为与内容一致。
破坏性: 导致父元素的高度塌陷。
🍚脱离文档流
当将 position 属性设置为 absolute 时,元素会脱离文档流。
文档流是将窗体从上至下分成行,并按从左至右的顺序排列元素的布局方式,也被称为文档流或普通流。
脱离文档流意味着元素不再占据文档流中的位置,而是处于浮动状态(可以理解为浮在文档流的上方)。脱离文档流的元素定位基于正常的文档流。一旦元素脱离文档流,其他在文档流中的元素将忽略该元素,并填充其原先的空间。
以下是示例代码:
不脱离文档流的效果如下图所示:
脱离文档流的效果如下图所示:
从中可以观察到 <div> 元素已经漂浮在图片的上方。
🍚与 margin 结合运用
当 absolute 属性值与 margin 结合使用时,可以实现一些出色的布局效果。例如,实现一个搜索框的下拉提示效果。以下是示例代码:
<html> <head> <meta charset="utf-8" /> <title>巧妙运用 absolute 和 margin 实现下拉框</title> <style> body { margin: 0; background-color: #edeff0; } /* 容器样式 */ .container { margin-top: 120px; margin-left: 240px; overflow: hidden; } /* 输入框样式 */ .input { width: 240px; line-height: 18px; padding: 10px; margin: 0; border: 0 none; } .input:focus { outline: 0 none; } .list { /* 默认不显示,通过js控制显示 */ /* display: none; */ position: absolute; width: 260px; /* 通过 margin 控制显示位置 */ margin: 39px 0 0 -1px; padding-left: 0; list-style-type: none; border: 1px solid #e6e8e9; background-color: #fff; box-shadow: 0px 1px 2px #d5d7d8; font-size: 12px; } /* 列表项样式及悬停样式 */ .list > li { line-height: 30px; padding-left: 12px; } .list > li:hover { background-color: #f9f9f9; } .list a { display: block; color: #5e5e5e; text-decoration: none; } .list a:hover { color: #000; } </style> </head> <body> <div class="container"> <ul class="list"> <li> <a>玩转CSS布局之 Grid 布局</a> </li> <li> <a>玩转CSS布局之 Flex 布局</a> </li> <li> <a>玩转CSS布局之深入理解 position 定位</a> </li> <li> <a>玩转CSS布局之深入理解 z-index 定位</a> </li> </ul> <input class="input" placeholder="请输入内容" /> </div> </body></html>
执行结果如下图所示:
此时,可以通过 JavaScript 控制提示内容的显示与隐藏。这种结合运用的方式使得页面布局更加灵活多样。
🍚left、right、top、bottom 的应用技巧
一旦开启定位,我们便能通过这四个属性来灵活控制元素的偏移,这些属性可以接受像素值、百分比(相对于元素包含块的宽度或高度)等参数。尽管基础的使用比较简单,这里分享一些在实际开发中的小技巧。
全屏自适应效果(无需宽度和高度声明)
示例代码如下:
<html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>全屏自适应效果</title> <style> .overlay { position: absolute; /* 拉满整个页面 */ left: 0; top: 0; right: 0; bottom: 0; background-color: #000; opacity: 0.5; } </style> </head> <body> <div class="overlay"></div> </body></html>
水平居中(使用 left、right 和 width)
示例代码如下:
<html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>水平居中</title> <style> img { position: absolute; right: 0; left: 0; width: 800px; /* 开启定位后,margin: auto 无法实现水平居中,需结合 left、right 和 width 使用 */ margin: auto; } </style> </head> <body> <img src="../image/img.jpg" /> </body></html>
实现效果如下:
值得注意的是,absolute 属性值不能与 float 共同使用,当二者共存时,float 将失效。
🍚定位与 z-index 的关联
对于绝对定位的元素,我们可以通过 z-index 属性来控制它们的层级显示关系。然而,在实际开发中,我们更注重代码结构的清晰性,因此并非必须在所有情况下都使用 z-index。以下是一些使用准则:
单个绝对定位元素: 如果只有一个绝对定位的元素,它自然会覆盖普通元素,此时无需通过 z-index 控制层级显示。
两个绝对定位元素: 当存在两个绝对定位的元素时,通过控制它们在 DOM 流中的前后顺序即可达到覆盖效果,无需额外使用 z-index 属性。
多个绝对定位元素: 在极少见的情况下,如果有多个绝对定位元素相互交错,可以通过 DOM 流的顺序和设置 z-index: 1 等较小的值来实现层级控制。
非弹框类元素: 对于非弹框类的绝对定位元素,如果需要设置 z-index,建议将值设为大于2的数值。然而,注意在许多情况下,使用 z-index 的冗余性可能会使代码变得复杂,可以考虑优化代码结构。
通过遵循这些准则,我们能够在确保页面效果的同时,保持代码的简洁和可维护性。
🍚relative 属性值
relative 对 absolute 的限制
🍉1. 使用 relative 定位的父元素对其子元素的 absolute 定位具有一些限制作用,主要体现在以下方面:
位置限制: 当父元素开启 relative 定位后,其子元素如果使用 absolute 定位,那么子元素的 left、right、top、bottom 属性值将受到限制,永远不会超出父元素的边界。示例代码如下:
<html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>relative 对 absolute 的限制</title> <style> .container { /* 父级元素开启 relative 定位 */ position: relative; height: 400px; width: 600px; margin: 0 auto; background-color: #9c27b0; } .item { /* 子元素开启 absolute 定位 */ position: absolute; background-color: #4caf50; height: 200px; width: 300px; /* 子元素的 top left right bottom 会被限制在父级容器中 */ right: 0; bottom: 0; } </style> </head> <body> <div class="container"> <div class="item"></div> </div> </body></html>
执行结果如下:
🍉2. z-index 层级限制: 当存在两个父元素都开启 relative 定位,并通过 z-index 限制层级时,z-index 较大的父元素的子元素将始终覆盖 z-index 较小的父元素的子元素。这是因为在同一层级中,z-index 更大的元素具有更高的堆叠顺序。示例代码如下:
在这种情况下,parent-1 下面的子元素无论其 z-index 的值多大,都不会覆盖 parent-2 下面的子元素。
🍉3. overflow:hidden 限制: 如果父元素未开启 relative 定位,其 overflow: hidden; 的限制对 absolute 定位的子元素并没有任何限制。只有父元素开启 relative 定位后,才会对 absolute 定位的子元素施加位置和溢出限制。示例代码如下:
当父元素未开启 relative 定位时:
当父元素开启 relative 定位后:
通过了解这些相对定位对绝对定位的限制,我们能更好地利用它们来实现页面布局。
🍚自定义偏移属性的使用
在元素开启 relative 定位后,我们可以使用 left、right、top、bottom 这些自定义偏移属性来实现相对于其原始位置的偏移,而不会对其他元素产生侵入性影响。简而言之,这些偏移属性是相对于元素自身进行调整,不会影响其他元素的布局。
以下是一个示例代码:
<html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>自定义偏移属性的使用</title> <style> .container { /* 父级元素开启 relative 定位 */ position: relative; height: 400px; width: 600px; background-color: #9c27b0; left: 100px; top: 100px; } </style> </head> <body> <div class="container"></div> </body></html>
执行结果如下:
通过调整 left 和 top 属性的值,我们可以使元素相对于其原始位置进行水平和垂直方向的偏移。这种方式非常灵活,可以用于微调元素的布局,而不会对其他元素的排列产生干扰。
🍚相对定位的最小化影响原则
相对定位的最小化影响原则旨在尽量减少 relative 属性对其他元素或布局的潜在影响,体现在两个方面的考虑:
🍉1. 优先使用 margin 实现 absolute 定位的偏移,而不是依赖 relative 属性值。
示例代码如下:
<html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>相对定位的最小化影响原则</title> <style> .container { height: 400px; width: 600px; background-color: #9c27b0; margin: 0 auto; } .item { height: 100px; width: 50px; background-color: #ff7043; line-height: 100px; font-size: 30px; text-align: center; } .absolute-item { position: absolute; right: 0; } </style> </head> <body> <div class="container"> <div class="item absolute-item">1</div> <div class="item">2</div> </div> </body></html>
这样的设计避免了相对定位对后续元素布局的干扰。
🍉2. 当必须使用相对定位时,为相对定位的子元素创建单独的父元素,并在该父元素上开启相对定位。
示例代码如下:
<html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>相对定位的最小化影响原则</title> <style> .container { height: 400px; width: 600px; background-color: #9c27b0; margin: 0 auto; } .item { height: 100px; width: 50px; background-color: #ff7043; line-height: 100px; font-size: 30px; text-align: center; } .relative-parent { position: relative; } .absolute-item { position: absolute; right: 0; } </style> </head> <body> <div class="container"> <!-- 单独创建一个 开启 relative 定位的 父元素--> <div class="relative-parent"> <!-- 这样不会影响后面元素的定位 --> <div class="item absolute-item">1</div> </div> <div class="item">2</div> </div> </body>
</html>
这种方式有效地隔离了相对定位,减少了其对其他元素的潜在影响。
通过以上设计原则,我们能够更好地利用相对定位,同时最小化其可能带来的布局影响。
🍚fixed 定位的特性
在CSS中,当 position 属性值设置为 fixed 时,元素会相对于浏览器窗口进行偏移,即定位的基准点是整个浏览器窗口。这使得该元素的位置不会随着页面的滚动而变化,它就像是固定在页面上一样。
fixed 属性值可以与 top、bottom、left、right 这四个属性一起使用,用于确定元素的初始位置,这些值是相对于视口计算的。如果不使用这四个属性,元素将出现在其默认位置。
以下是示例代码:
<html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>fixed 定位的特性</title> <style> body { margin: 0; height: 2000px; } .container { /* 使用 fixed 定位 */ position: fixed; height: 400px; background: #2c80c5; /* 实现居中 */ left: 0; right: 0; width: 500px; margin: auto; } </style> </head> <body> <div class="container"></div> </body></html>
无论页面如何滚动,该元素始终保持在浏览器窗口的顶部。
这种布局方式的效果如下图所示。
🍚sticky 定位的独特特性
在CSS中,sticky 定位值与其他属性不同,它呈现出一种动态效果,可用于实现吸顶效果。
这个值的行为就像是 relative 和 fixed 的结合。在某些情况下,它是相对定位(基准点是元素自身的默认位置),而在其他情况下,它会自动变成固定定位(基准点是视口)。
sticky 属性值必须与 top、bottom、left、right 这四个属性一起使用,不能省略,否则效果等同于 relative 定位,不会产生动态吸附的效果。
这个属性值的定位规则是:当页面滚动时,父元素开始脱离视口(即部分不可见),只要与 sticky 元素的距离达到生效门槛,relative 定位自动切换为 fixed 定位;等到父元素完全脱离视口时(即完全不可见),fixed 定位自动切换回 relative 定位。
以下是示例代码:
<html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>sticky 定位的独特特性</title> <style> .container { background: #eee; width: 600px; height: 1000px; margin: 0 auto; } .title { /* 兼容 Safari 浏览器 */ position: -webkit-sticky; position: sticky; height: 60px; background: #ff7300; top: 0px; font-size: 30px; text-align: center; color: #fff; line-height: 60px; } img { width: 100%; display: block; } </style> </head> <body> <div class="container"> <div> <div class="title">内容1</div> <img src="../image/img.jpg" /> </div> <div> <div class="title">内容2</div> <img src="../image/img.jpg" /> </div> <div> <div class="title">内容3</div> <img src="../image/img.jpg" /> </div> <div> <div class="title">内容4</div> <img src="../image/img.jpg" /> <img src="../image/img.jpg" /> </div> </div> </body></html>
当页面滚动时,只要视口的顶部与 .title 的距离 >= 0,.title 就会自动变为 fixed 定位,保持与视口顶部 0px 的距离。页面继续向下滚动,父元素彻底离开视口,.title 恢复成 relative 定位。这种效果如下图所示。
🍚position:sticky 的生效规则需要满足以下条件:
🍉1. 指定 top、right、bottom 或 left 阈值: 在使用 position:sticky 时,必须指定 top、right、bottom 或 left 四个阈值中的至少一个,以使粘性定位生效。如果没有指定这些阈值,其行为将与相对定位相同。
如果同时设置 top 和 bottom,top 的优先级较高。
如果同时设置 left 和 right,left 的优先级较高。
🍉2. 父节点的 overflow 属性设置为 visible: position:sticky 元素的任意父节点的 overflow 属性必须是 visible,否则 position:sticky 不会生效。这是因为:
如果 position:sticky 元素的任意父节点的 overflow 设置为 hidden,则父容器无法进行滚动,导致 position:sticky 元素无法在滚动时固定。
如果 position:sticky 元素的任意父节点的 overflow 设置为 position:relative、absolute 或 fixed,则元素会相对于父元素进行定位,而不是相对于视口。
🍉3. 达到设定的阈值: position:sticky 元素会在滚动时相对于其包含块(nearest block ancestor)进行定位,直到达到设定的 top、right、bottom 或 left 阈值。元素达到设定的阈值后,其表现为 fixed 定位,保持在视口的相应位置。
考虑以上规则,以下是一个示例代码:
<html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>position:sticky 生效规则</title> <style> .container { background: #eee; width: 600px; height: 1000px; margin: 0 auto; overflow: visible; /* 必须设置 overflow 为 visible */ } .sticky-element { position: -webkit-sticky; position: sticky; top: 20px; /* 达到设定的阈值 */ height: 60px; background: #ff7300; font-size: 18px; text-align: center; line-height: 60px; } img { width: 100%; display: block; } </style> </head> <body> <div class="container"> <div class="sticky-element">Sticky Element</div> <img src="../image/img.jpg" /> </div> </body></html>
这个示例满足了 position:sticky 的生效条件,包括指定了 top 阈值、父节点的 overflow 属性为 visible,以及达到设定的阈值。