前言

定位是 CSS 里蛮重要的一课.

图片黑影 (overlay), back to top button, header, footer 紧贴在屏幕上下方等效果都是靠 position 完成的.

参考:

Youtube – #CSS 認識 Position 粤语

阮一峰 – CSS 定位详解

Static

position 一共有 5 种, 默认是 static.

假设有 5 个 box

<div class="container">
<div class="box1">box1</div>
<div class="box2">box2</div>
<div class="box3">box3</div>
<div class="box4">box4</div>
<div class="box5">box5</div>
</div>

它的效果就是一个一个往下放. 彼此是不重叠的.

fixed

fixed 的使用场景是在 scrolling 的时候, 我们想让某个元素一直保持在一个位置上. 比如 back to top button.

.box3 {
position: fixed;
}

效果

当设置 fixed 以后, box3 发生了几个变化.

1.飘起来了

即便没有 scroll, 一开始 box3 就和 box4 重叠了. 这是因为 box3 飘起来了.

这个过程类似把 box3 从布局中抽走, 整个布局变成 box1, 2, 4, 5.

2. top, right, bottom, left, inset

通常 fixed 一定是搭配 offset 属性一起用的. 它的玩法是这样:

有 2 个对象

第 1 个是外面的 offset 对标框 (fixed 对标框就是 viewport 屏幕框)

第 2 个是里面的定位元素咯

白色区域就是整个 viewport (屏幕框)

inset 是 top, right, bottom, left 的 shorthand, 和 padding, margin 用法完全一样.

inset: 0 相等于 4 边都是 0, inset 10px 20px 则是 top,bottom: 10px, left, right: 20px

3. offset 的默认值

当 box3 没有设置 top 偏移时, 游览器的默认行为是把它定位到它原本的位置上, 所以效果就是和 box4 发生了重叠.

如果设置 top: 60px 的话

 box3 不在和 box4 重叠, 而是和 box1,2 重叠.

注: 很少会用默认的, 而且默认的 "原地" 是依赖排版方式的, 如果是用 margin 来布局, 或者 Flex, 游览器很有可能无法正确的计算到 "原地".

absolute

offset parent

absolute 和 fixed 很像. 只有 2 个点不同, 第一是它们的 offset 对标框不同.

fixed 的 offset 对标框是 viewport. 而 absolute 的 offset 对标框是不固定的.

它有个术语叫 offset parent.

通过 JS 可以拿到哦 (注: chrome position fixed offsetParent will be null. 不清楚为什么 chrome 那么特别...哈哈)

document.querySelector(".box3").offsetParent;

从 absolute element 往 parent 走, 第一个 position 不是 static 的 element 就是它的 offset parent.

虽然红框是第一个 parent 但它是 static, 所以继续往上找, 蓝框才是第一个不是 static 的 element, 所以它成为了 offset parent.

所有 offset 位置都基于它来计算.

fixed 则是不管什么 parent, 它就对着 viewport

absolute 不被 scroll 影响

第二个不同是 absolute 不会被 scroll 影响. fixed 对标的是 viewport 所以才会随着 scroll 而改变.

box3 是 absolute; top: 0; rigth: 0; 如果要它随着 scroll 改变, 可以用 stikcy (下面会讲到)

border 不算在内

还有一个点是, top, right, bottom, left 是从 padding 算起的, border 不算在内.

top left: 50px

黑线不算哦

冷知识 – Position absolute 导致 parent overflow

冷知识 – 当 position: absolute 遇上 grid container

relative

relation 和 ablsolute 就有差别了.

第 1 它没有被抽出布局的概念.

.box3 {
position: relative;
top: -50px;
}

效果

先不管 top: -50px 的逻辑. 当 box3 relation 以后, box2, box4 并没有连在一起. 中间依然空了一个 box3 的距离.

这就类似灵魂出窍一样.

第 2 它的 offset 计算不是对着 offset parent 也不是对着 viewport.

而是对着元素原本的位置.

过程类似, 在元素原本的位置画一个虚拟框作为它的 offset parent. 然后依据框做偏移.

上面例子中 top: -50px

红框就是元素本来的位置, -50px 往上偏移, 所以最终 box3 和 box2 重叠了.

小总结:

static: 默认 position

fixed: 会飘起来, 抽离原先的布局. 会导致原本的布局不一样. 始终和 viewport 保持固定的偏移.

absolute: 会飘起来, 抽离原先的布局. 会导致原本的布局不一样, 始终和 offset parent (第一个不是 static 的 parent) 保持固定的偏移.

最常用的手法就是给 parent position: relation 让它变成 offset parent. 因为 relation 不会对原本的布局有影响. 同时它又不是 static, 就可以成为 offset parent 了.

relation: 会飘起来, 但是不会抽离原先布局, 对原本的布局没有影响. 原地偏移.

sticky

参考:Position: stuck; — and a way to fix it

以前写过Angular 学习笔记 (Material table sticky 原理)

重要概念:

1. sticky scroll container

sticky element 会找到第一个 overflow hidden, scroll, auto, overlay 的 parent 作为它的 sticky scroll container (不管是 vertical 还是 horizontal, 只要有那些 overflow 就是 sticky scroll container).

注:overflow overlay 是 auto 的前生,已经废弃了。overflow visible 和 clip 就不算是 sticky scroll container,clip 比较冷门,我不熟。

2. sticky max area container

sticky 的第一个 parent 就是 max area container, 没有任何要求, 第一个 parent 就是了, sticky 的可移动空间就看这个 max area container.

3. sticky top, right, bottom, left

position sticky 一定要要配上 offset 这些会 start working.

它的计算和 absolute 是不同的. absolute 不 cover padding, 但是 sticky cover.

scroll container 的 border 和 padding 会保留, sticky element 会在 padding 下面.

absolution 的话 element 是会盖掉 padding 的.

什么时候会 stick ?

中间长方形是 viewport, 当 scroll 的时候,红色的 sticky top 会不会触发, 取决于红色 element 是否在 viewport 的前面.

蓝色的 sticky bottom 会不会触发取决于它是否在 viewport 的下面.

比如黄色在中间, 那么它是没有任何 sticky 的. 上下都不粘.

它并不完美

上面说的 1, 2 条件 sticky scroll container 和 sticky max area container 大大限制了使用的场景.

sticky 的 first overflow 很有可能是 horizontal 但是需求是更上一层的 vertical 才是 scroll container. 这就不能用了.

first parent 是 max area 更恐怖. 比如需求要做一个 animation, 你 wrap 它起来就 gg.com 了.

它适合的场景是, first parent 刚好是 max area container 同时也是 scroll container. 这样才比较顺.

可以通过 JS 实现突破这些局限. 以前没有 position: sticky 的时候大家都是这样干的. 确保性能 ok 就可以了. 它的基本原理就是做计算, 然后配上 relative or absolute 都可以 (只要定位就可以了, 其它的就是计算偏移量问题而已).

细节看这篇: CSS & JS Effect – Simulation Position Sticky

当 sticky 遇上 <table>

上面我们有提到 sticky max area container 的概念,sticky element 的 first parent 就是 sticky 可移动的 max area。

但这个概念不适用于 native table 里的 tr td。

这是一个用 div flex layout 做的 table

<div class="table-container">
<div class="table">
<div class="tr">
<div class="th" style="position: sticky; top: 0; left: 0; background-color: red; color: white;">First Name</div>
<div class="th">Last Name</div>
<div class="th">Age</div>
<div class="th">Address</div>
<div class="th">Email</div>
</div>
<div class="tr">
<div class="td">John</div>
<div class="td">Doe</div>
<div class="td">30</div>
<div class="td">123 Main St</div>
<div class="td">john.doe@example.com</div>
</div>
<div class="tr">
<div class="td">Jane</div>
<div class="td">Smith</div>
<div class="td">25</div>
<div class="td">456 Elm St</div>
<div class="td">jane.smith@example.com</div>
</div>
<div class="tr">
<div class="td">Michael</div>
<div class="td">Johnson</div>
<div class="td">35</div>
<div class="td">789 Oak St</div>
<div class="td">michael.johnson@example.com</div>
</div>
<div class="tr">
<div class="td">Sarah</div>
<div class="td">Williams</div>
<div class="td">28</div>
<div class="td">321 Pine St</div>
<div class="td">sarah.williams@example.com</div>
</div>
<div class="tr">
<div class="td">David</div>
<div class="td">Brown</div>
<div class="td">40</div>
<div class="td">654 Cedar St</div>
<div class="td">david.brown@example.com</div>
</div>
<div class="tr">
<div class="td">Emily</div>
<div class="td">Miller</div>
<div class="td">33</div>
<div class="td">987 Maple St</div>
<div class="td">emily.miller@example.com</div>
</div>
<div class="tr">
<div class="td">James</div>
<div class="td">Wilson</div>
<div class="td">27</div>
<div class="td">753 Walnut St</div>
<div class="td">james.wilson@example.com</div>
</div>
<div class="tr">
<div class="td">Emma</div>
<div class="td">Anderson</div>
<div class="td">29</div>
<div class="td">159 Birch St</div>
<div class="td">emma.anderson@example.com</div>
</div>
</div>
</div>

CSS Styles

.table-container {
margin-top: 128px;
margin-inline: auto;
max-width: 512px;
max-height: 360px;
overflow: auto;
} .table {
width: 1024px;
}
.table .tr {
display: flex;
min-width: max-content;
} .table .tr .th,
.table .tr .td {
padding: 16px;
flex: 1;
}

效果

vertical sticky 无效是因为 div.td 的 parent (max area) 是 div.tr,而它没有多余的高度。

我们把它换成 <table> <tr> <td> 结构

<div class="table-container">
<table>
<thead>
<tr>
<th style="position: sticky; top: 0; left: 0; background-color: red; color: white;">First Name</th>
<th>Last Name</th>
<th>Age</th>
<th>Address</th>
<th>Email</th>
<th>Phone</th>
<th>City</th>
<th>Country</th>
<th>Occupation</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>John</td>
<td>Doe</td>
<td>30</td>
<td>123 Main St</td>
<td>john.doe@example.com</td>
<td>123-456-7890</td>
<td>New York</td>
<td>USA</td>
<td>Software Engineer</td>
<td>$80,000</td>
</tr>
<tr>
<td>Jane</td>
<td>Smith</td>
<td>25</td>
<td>456 Elm St</td>
<td>jane.smith@example.com</td>
<td>987-654-3210</td>
<td>Los Angeles</td>
<td>USA</td>
<td>Graphic Designer</td>
<td>$60,000</td>
</tr>
<tr>
<td>Michael</td>
<td>Johnson</td>
<td>35</td>
<td>789 Oak St</td>
<td>michael.johnson@example.com</td>
<td>456-789-0123</td>
<td>Chicago</td>
<td>USA</td>
<td>Teacher</td>
<td>$50,000</td>
</tr>
<tr>
<td>Sarah</td>
<td>Williams</td>
<td>28</td>
<td>321 Pine St</td>
<td>sarah.williams@example.com</td>
<td>789-012-3456</td>
<td>Miami</td>
<td>USA</td>
<td>Accountant</td>
<td>$70,000</td>
</tr>
<tr>
<td>David</td>
<td>Brown</td>
<td>40</td>
<td>654 Cedar St</td>
<td>david.brown@example.com</td>
<td>210-987-6543</td>
<td>Houston</td>
<td>USA</td>
<td>Engineer</td>
<td>$90,000</td>
</tr>
<tr>
<td>Emily</td>
<td>Miller</td>
<td>33</td>
<td>987 Maple St</td>
<td>emily.miller@example.com</td>
<td>567-890-1234</td>
<td>Seattle</td>
<td>USA</td>
<td>Manager</td>
<td>$100,000</td>
</tr>
<tr>
<td>James</td>
<td>Wilson</td>
<td>27</td>
<td>753 Walnut St</td>
<td>james.wilson@example.com</td>
<td>890-123-4567</td>
<td>San Francisco</td>
<td>USA</td>
<td>Marketing Specialist</td>
<td>$75,000</td>
</tr>
<tr>
<td>Emma</td>
<td>Anderson</td>
<td>29</td>
<td>159 Birch St</td>
<td>emma.anderson@example.com</td>
<td>234-567-8901</td>
<td>Boston</td>
<td>USA</td>
<td>Consultant</td>
<td>$85,000</td>
</tr>
</tbody>
</table>
</div>

CSS Styles

table td {
padding: 16px;
} .table-container {
margin-top: 128px;
margin-inline: auto;
max-width: 512px;
max-height: 360px;
overflow: auto;
}

效果

照理说效果应该和 flex table 一样,但很奇怪,td sticky 竟然也可以 sticky vertical。

我是在用 Angular Material Table 发现的,估计是游览器动了手脚。参考:【前端】position:sticky解析 这次应该大结局了

当 absolute / fixed 遇上 width / height auto

参考

MDN – position

stackoverflow – width:auto and fixed position

有时候当我们修改 div 的 position 之后会发现它变小了.

div block element width: auto 相等于 100% 对标 parent. 但是经过 position absolute 以后变成了 hug content.

在 MDN 有一段就是声明这个的.

如果希望保留原本的效果可以设置 left:0; right:0. 或者不要使用 width: auto 改成 100%.

常见的 overlay 写法

  

3个写法是等价的, 通常会写第 3 种. 因为它最短嘛.

CSS – Position的更多相关文章

  1. css position的使用

    css position的使用 css 的 position 属性是用来设置元素的位置的,它还能设置一个元素出现在另一个元素的下层元素能用 top,bottom,left 和 right 属性设置位置 ...

  2. CSS position绝对定位absolute relative

    常常使用position用于层的绝对定位,比如我们让一个层位于一个层内具体什么位置,为即可使用position:absolute和position:relative实现. 一.position语法与结 ...

  3. jQuery offset,position,offsetParent,scrollLeft,scrollTop html控件定位 css position

    定位应用:点击一个按钮,然后在按钮的右边弹出一个提示框 1,提示框相对于屏幕进行定位,那么使用offset来取得当前按钮相对于body的top和left,然后通过$('body').prepend(t ...

  4. [CSS]position定位

    CSS position 属性 通过使用 position 属性,我们可以选择 4 种不同类型的定位,这会影响元素框生成的方式. position 属性值的含义: static 元素框正常生成.块级元 ...

  5. jQuery css,position,offset,scrollTop,scrollLeft用法

    jQuery css,position,offset,scrollTop,scrollLeft用法: <%@ page language="java" import=&quo ...

  6. CSS position(定位)属性

    关于CSS position,来自MDN的描述: CSS position属性用于指定一个元素在文档中的定位方式.top.right.bottom.left 属性则决定了该元素的最终位置. 然后来看看 ...

  7. CSS position &居中(水平,垂直)

    css position是个很重要的知识点: 知乎Header部分: 知乎Header-inner部分: position属性值: fixed:生成绝对定位的元素,相对浏览器窗口进行定位(位置可通过: ...

  8. CSS position属性absolute relative等五个值的解释

    DIV CSS position绝对定位absolute relative教程篇 常常使用position用于层的绝对定位,比如我们让一个层位于一个层内具体什么位置,为即可使用position:abs ...

  9. 前端开发必知必会:CSS Position 全解析

    此文根据Steven Bradley的<How Well Do You Understand CSS Positioning?>所译,整个译文带有我自己的理解与思想,如果译得不好或不对之处 ...

  10. jquery 获取css position的值

      jquery 获取css position的值 CreateTime--2018年5月28日14:03:12 Author:Marydon 1.情景展示 <div id="aa&q ...

随机推荐

  1. ELK Stack - Elasticsearch · 搜索引擎 · 部署应用 · 内部结构 · 倒排索引 · 服务接入

    系列目录 ELK Stack - Elasticsearch · 搜索引擎 · 全文检索 · 部署应用 · 内部结构 · 倒排索引 · 服务接入 ELK Stack - Kibana (待续) ELK ...

  2. CentOS 8安装docker

    1.查看Linux内核(Docker最低支持CentOS 7 64位 内核3.10) uname -a 2.安装docker(输入yes,然后等待-) yum install docker 3.启动d ...

  3. [oeasy]python0099_雅达利大崩溃_IBM的开放架构_兼容机_oem

    雅达利大崩溃 回忆上次内容 个人计算机浪潮已经来临 苹果公司迅速发展 微软公司脱离mits准备做纯软件公司 IBM用大型机思路制作的5100惨败 Commodore 64 既做计算机 又做游戏机 计算 ...

  4. Linux 提权-NFS 共享

    本文通过 Google 翻译 NFS Share no_root_squash – Linux Privilege Escalation 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校 ...

  5. 阅读翻译Prompting Engineering Guides之Introduction(提示工程简介)

    阅读翻译Prompting Engineering Guides之Introduction(提示工程简介) 关于 首次发表日期:2024-07-19 Prompting Engineering Gui ...

  6. SUM-ACM——VJ天梯训练赛

    这次比赛我暴露了很多问题,一些模拟还有贪心思路错误. 补题如下: E - E 题解:一道模拟题,我的问题在于不知道怎么替换下一个,就从0开始遍历数组然后数组的值--,如果为零就continue下一个, ...

  7. 张高兴的 MicroPython 入门指南:(三)使用串口通信

    目录 什么是串口 使用方法 使用板载串口相互通信 硬件需求 电路 代码 使用板载的 USB 串口 参考 什么是串口 串口是串行接口的简称,这是一个非常大的概念,在嵌入式中串口通常指 UART(Univ ...

  8. Rust 中 *、&、mut、&mut、ref、ref mut 的用法和区别

    Rust 中 *.&.mut.&mut.ref.ref mut 的用法和区别 在 Rust 中,*.ref.mut.& 和 ref mut 是用于处理引用.解引用和可变性的关键 ...

  9. 【Android】虚拟设备运行BUG

    虚拟设备是AndroidStudio提供的一个真机模拟运行环境 跑这个虚拟设备要下载手机系统镜像才能跑起来 然后项目中勾选这个虚拟设备,怎么设置就不赘述了 问题奇怪的是运行环境有了,App应用程序也能 ...

  10. 中国特供阉割版4090D建议安装最新驱动,据说不然的话会报error:4090和4090D对比

    资料来源: https://www.bilibili.com/video/BV1oa4y127fG/?spm_id_from=333.999.0.0&vd_source=f1d0f27367a ...