前言

定位是 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. 解决方案 | 获取所有的打印输出的图纸尺寸的名称GetCanonicalMediaNames返回为空的原因竟然是官方帮助文件给我带来了误导-CAD VBA

    巨大的坑,该代码来自于acadauto_2014--AutoCAD2014 ActiveX Reference Guide.chm 但是存在一个巨大的bug. '获取所有的打印输出的图纸尺寸的名称 , ...

  2. oeasy教您玩转vim - 78 - # 操作系统文件格式 fileformat

    ​ 文件系统换行格式 fileformat 回忆保留环境的细节 上次我们了解了viminfo 他能够保存 命令行历史 标记 寄存器 把他和 :mksession 一起使用就可以完美复原环境了 还有什么 ...

  3. vue小知识~ref和$refs

    $refs表示的是获取被ref标识的标签的DM实例. 用法简单: 标签上: <div ref='refName'></div> 获取: this.$refs.refName 就 ...

  4. OpenGL 4.0中数据缓冲VBO,VAO,EBO的使用总结

    Opengl是大家常用的一个API,我们用它绘制数据的时候需要使用vao,vbo,ebo等对象,绘制方式分为 vao绘制,ebo绘制等.使用不同api还能分为普通调用以及Instance绘制. 首先申 ...

  5. Python和RPA网页自动化-处理iframe嵌入式框架

    以网易云为例,歌曲列表都在<iframe>框架下,使用Python和RPA网页自动化依次点击10首歌的播放键 1.python代码 从网页源代码可见,整个歌曲列表都在<iframe& ...

  6. Linux系统——删除用户命令

      背景: 负责管理实验室的服务器,近期有保研的大三同学放弃保送到实验室而选择其他实验室,因此需要把之前给他开的账号取消掉. ===================================== ...

  7. 老代码报错:scipy.misc.imresize报错: AttributeError: module 'scipy.misc' has no attribute 'imresize'

    运行老代码报错: image = misc.imresize(image, [Config.IMAGE_HEIGHT, Config.IMAGE_WIDTH], 'bilinear')Attribut ...

  8. jQuery Eazyui的学习和使用(一)

    工作需要,需要学习使用据说非常简单好用的前端框架-----Eazyui 先看看简介吧:"jQuery EasyUI 是一个基于 jQuery 的框架,集成了各种用户界面插件.jQuery E ...

  9. selenium复习之---原理+基础用法

    简介 1.是什么 selenium是用来进行页面元素定位的第三方库,用来进行web自动化测试的工具,可以直接运行在浏览器中. 2.原理: selenium在工作过程中有三个角色,selenium客户端 ...

  10. StartImage.DLL使用说明

    StartImage.DLL使用说明 一.库的引入 库包含以下物件,请按照要求将以下库映入到项目中 StartImage.dll StartImage.lib StartImage.h 二.注意事项 ...