Pixiv - KiraraShss
1135 字
6 分钟
display:flex与绝对定位
欢迎来到我的博客!
使用 Markdown 格式编写。
今天学到了什么
- 炫彩工具箱案例
父盒子设置了 display: flex;对设置了绝对定位的子盒子还生效吗
这是一个非常经典且容易混淆的问题。
结论:
display: flex 对绝对定位(position: absolute)的子元素只有部分影响,大部分 Flex 布局特性会失效。
具体来说:
-
脱离文档流: 一旦子元素设置了
position: absolute,它就脱离了文档流。这意味着它不再参与 Flex 容器的自动空间分配(比如flex-grow,flex-shrink等属性对它无效)。 -
justify-content和align-items的影响:- 如果子元素没有设置偏移量(top/left/right/bottom):
Flex 容器的对齐属性(
justify-content和align-items)依然会影响这个绝对定位子元素的初始位置。- 在你的代码中,
.menu设置了justify-content: center; align-items: center;,且.btn没有设置top/left等。 - 结果:
.btn会乖乖地待在.menu的正中心。
- 在你的代码中,
- 如果子元素设置了偏移量(比如
top: 0; left: 0;): 偏移量的优先级高于 Flex 对齐。子元素会直接飞到top: 0; left: 0的位置,完全无视 Flex 的居中设置。
- 如果子元素没有设置偏移量(top/left/right/bottom):
Flex 容器的对齐属性(
-
父级定位基准: 你注释掉了
.menu的position: relative;。- 如果
.menu没有定位属性,.btn的position: absolute会向上寻找最近的已定位祖先元素作为参考点。 - 如果找不到,它就会相对于
body(或者说初始包含块)进行定位。 - 但在你的例子中,因为
.btn没有写top/left,它默认就停留在它在文档流中“本该在”的位置(也就是被 Flex 居中的位置)。
- 如果
总结建议: 虽然 Flex 对齐能影响无偏移的绝对定位元素,但为了代码的健壮性,通常建议:
- 给父元素
.menu加上position: relative;。 - 如果你想让子元素居中,既然已经用了
absolute,也可以直接用top: 50%; left: 50%; transform: translate(-50%, -50%);来强制居中,这样就不依赖父级的 Flex 属性了。或者保留现在的写法利用 Flex 居中也是一种常见的技巧。
设置绝对定位后,如果不设置top,元素会停在原先的位置
是的,你的理解完全正确。这是一个非常实用但经常被忽略的 CSS 特性。
原理解析
当一个元素设置了 position: absolute,它确实会脱离文档流(不再占据空间),但是:
-
如果没有设置偏移量(
top,left,right,bottom): 浏览器会把它渲染在它原本在普通文档流中应该出现的位置。这被称为元素的**“静态位置” (Static Position)**。 -
结合你的代码:
- 你的父盒子
.menu设置了 Flex 布局居中:display: flex;justify-content: center;align-items: center; - 这意味着,如果子元素
.btn和span不是绝对定位的话,它们本来就会被 Flex 挤到正中间。 - 当你加上
position: absolute但不写top/left时,它们就乖乖地停留在那个“本该在的正中间位置”,只是不再占据物理空间了(所以它们会重叠在一起)。
- 你的父盒子
总结: 利用这个特性配合 Flex 布局,是让绝对定位元素快速居中的一个非常巧妙的技巧!总结: 利用这个特性配合 Flex 布局,是让绝对定位元素快速居中的一个非常巧妙的技巧!
案例完整代码
<!DOCTYPE html><html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>炫彩工具箱.html</title> <link rel="stylesheet" href="https://at.alicdn.com/t/c/font_4090357_z2qpnic06um.css"> <style> * { margin: 0; padding: 0; list-style: none; }
body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: #303640; }
.menu { position: relative; width: 200px; height: 200px; display: flex; justify-content: center; align-items: center; }
.menu .btn { position: absolute; z-index: 1000; width: 60px; height: 60px; background-color: #303640; color: #fff; border: 2px solid #fff; border-radius: 50%; display: flex; justify-content: center; align-items: center; transition: all 1.25s;
}
.menu .btn i { font-size: 32px; }
.menu:hover .btn { transform: rotate(315deg); }
.menu span { position: absolute; border: 2px solid var(--clr); border-radius: 50%; /* 分开写两个过渡 */ transition: all 0.5s calc(var(--i) * 0.1s); width: 40px; height: 40px; display: flex; justify-content: center; align-items: center; color: var(--clr); }
.menu span i { font-size: 24px; /* color: var(--clr); */ }
.menu:hover span { transform: rotate(calc(360deg / 8 * var(--i))) translateX(80px); }
.menu:hover span i { transform: rotate(calc(-360deg / 8 * var(--i))); }
.menu span:hover { box-shadow: 0 0 10px var(--clr), 0 0 30px var(--clr), 0 0 50px var(--clr); background-color: var(--clr); color: #333; /* 想要阴影立马显示,所以去掉过渡 */ transition: all 0s; } </style></head>
<body> <div class="menu"> <div class="btn"><i class="iconfont icon-add"></i></div> <span style="--i:0;--clr: #ff2972;"> <i class="iconfont icon-home"></i> </span> <span style="--i:1;--clr: #fee800;"> <i class="iconfont icon-more"></i> </span> <span style="--i:2;--clr: #04fc43;"> <i class="iconfont icon-gift"></i> </span> <span style="--i:3;--clr: #fe00f1;"> <i class="iconfont icon-setting"></i> </span> <span style="--i:4;--clr: #00b0fe;"> <i class="iconfont icon-message"></i> </span> <span style="--i:5;--clr: #fea600;"> <i class="iconfont icon-cart"></i> </span> <span style="--i:6;--clr: #a529ff;"> <i class="iconfont icon-money"></i> </span> <span style="--i:7;--clr: #01bdab;"> <i class="iconfont icon-star"></i> </span> </div></body>
</html>赞助支持
如果这篇文章对你有帮助,欢迎赞助支持!
最后更新于 2026-01-03,距今已过 1 天
部分内容可能已过时