定位

定位允许你从正常的文档流布局中取出元素,并使它们具有不同的行为,例如放在另一个元素的上面,或者始终保持在浏览器视窗内的同一位置。

定位是你的工具。或者,如果你想要创建一个浮动在页面其他部分顶部的 UI 元素,并且/或者始终停留在浏览器窗口内的相同位置,无论页面滚动多少?定位使这种布局工作成为可能。

文档流

默认情况下,块级元素的内容宽度是其父元素的宽度的100%,并且与其内容一样高。

内联元素高宽与他们的内容高宽一样。你不能对内联元素设置宽度或高度——它们只是位于块级元素的内容中。如果要以这种方式控制内联元素的大小,则需要将其设置为类似块级元素 display: block;

静态定位

静态定位是每个元素获取的默认值——它只是意味着“将元素放入它在文档布局流中的正常位置 ——这里没有什么特别的。

相对定位

与静态定位相似,占据在正常的文档流中。

1
position: relative;

介绍 top、bottom、left 和 right

这四个属性分别用来精确定位元素要移动的位置。

相对移动(理解成一个力在推动):

  1. top ->力从上往下
  2. bottom->从下往上
  3. left->从左往右
  4. right->从右往左
1
2
3
4
5
6
.positioned{
position: relative;
top: 30px;
right: 30px;
background: yellow;
}

image-20221012135733019

绝对定位

1
position: absolute;

image-20221012135943088

我们观察到,定位的元素在文档流的间隙不再存在,第一个元素和第三个元素已经靠在一起,仿佛第二个元素不存在了。

绝对元素不再存在于正常的文档流中。

可以使用top等设置元素位置。

定位上下文

如果所有的父元素都没有显式地定义 position 属性,那么所有的父元素默认情况下 position 属性都是 static。

绝对定位元素会被包含在初始块容器中。这个初始块容器有着和浏览器视口一样的尺寸,并且<html>元素也被包含在这个容器里面。简单来说,绝对定位元素会被放在<html>元素的外面,并且根据浏览器视口来定位。

绝对定位元素在 HTML 源代码中,是被放在<body>中的,但是在最终的布局里面,它的显示位置是相对于浏览器页面的。

我们可以改变定位上下文 —— 绝对定位的元素的相对位置元素。通过设置其中一个父元素的定位属性 —— 也就是包含绝对定位元素的那个元素(如果要设置绝对定位元素的相对元素,那么这个元素一定要包含绝对定位元素)。

例如:我们在body元素中设置position:relative,则body中使用绝对定位的元素将以body作为参照。

image-20221012141817529

image-20221012141758771

介绍 z-index

决定哪些元素出现在其他元素的顶部

在源代码中的后定位的元素将赢得先定位的元素,也就是说后定位的元素将覆盖显示在先定义的元素之上。

使用z-index属性。

“z-index”是对 z 轴的参考。

你可以从源代码中的上一点回想一下,我们使用水平(x 轴)和垂直(y 轴)坐标来讨论网页,以确定像背景图像和阴影偏移之类的东西的位置。

(0,0)位于页面(或元素)的左上角,x 和 y 轴跨页面向右和向下(适合从左到右的语言,无论如何)。

网页也有一个 z 轴:一条从屏幕表面到你的脸(或者在屏幕前面你喜欢的任何其他东西)的虚线。z-index 值影响定位元素位于该轴上的位置;正值将它们移动到堆栈上方,负值将它们向下移动到堆栈中。默认情况下,定位的元素都具有 z-index 为 auto,实际上为 0。

z-index 只接受无单位索引值

固定定位

这与绝对定位的工作方式完全相同,只有一个主要区别:绝对定位将元素固定在相对于其位置最近的祖先。(如果没有,则为初始包含它的块)而固定定位固定元素则是相对于浏览器视口本身。这意味着你可以创建固定的有用的 UI 项目,如持久导航菜单

position: sticky

比起其他位置值要新一些。它基本上是相对位置和固定位置的混合体,它允许被定位的元素表现得像相对定位一样,直到它滚动到某个阈值点(例如,从视口顶部起 10 像素)为止,此后它就变得固定了。

定位实例练习

列表消息盒子

效果

image-20221012145451882

结构

1
2
3
4
5
6
section(info-box)-	ul-	li-a(active)
li-a
li-a
div(panels)-acticle(active-panel)
acticle
acticle

思路

  1. 将样式化选项卡看起来是一个标准的水平导航菜单,使用绝对定位样式化面板互相坐落其顶上。
  2. 当选项卡被按下时,显示对应的面板,并且样式化选项卡本身。

实现

一般设置

1
2
3
4
5
6
7
8
9
10
11
html {
font-family: sans-serif;
}

* {
box-sizing: border-box;
}

body {
margin: 0;
}

样式设置

设置信息盒子宽高、位置

1
2
3
4
5
.info-box {
width: 450px;
height: 400px;
margin: 0 auto;
}

设置选项卡样式

从外到内,设置边框,选项卡高度,内外边距,设置外溢部分自动隐藏

1
2
3
4
5
6
7
.info-box ul {
border: 1px solid #b60000;
overflow: hidden;
height: 50px;
margin: 0;
padding: 0;
}

设置选项卡选项,左浮动,取消无序列表图形,设置每个选项的宽度

1
2
3
4
5
.info-box li {
float: left;
list-style-type: none;
width: 150px;
}

设置选项卡选项超链接文本样式

inline-block

1
2
3
4
5
6
7
8
9
10
.info-box li a{
display: inline-block;
text-decoration: none;
width: 100%;
line-height: 50px;
background: white;
color: #b60000;
text-align: center;
font-weight: bold;
}

设置鼠标悬停时和点击后的选项卡样式

1
2
3
4
.info-box li a:focus, .info-box li a:hover {
background-color: #b60000;
color: white;
}

设置默认时选中的选项卡样式

1
2
3
4
.info-box li a.active {
background-color: #b60000;
color: white;
}

设置信息面板盒子样式

从外到内,清除面板盒子两侧浮动、设置面板盒子子元素的参照为父元素、设置面板盒子高度

1
2
3
4
5
6
.info-box .panels{
clear: both;
position: relative;
height: 352px;
/* border: 1px solid; */
}

设置acticle盒子样式、设置背景颜色、设置为绝对定位、设置内边距、设置高度、设置偏移量

1
2
3
4
5
6
7
8
9
.info-box article{
background: #b60000;
color: white;
position: absolute;
padding: 10px 20px;
height: 352px;
top: 0;
left: 0;
}

设置默认显示的面板

1
2
3
.info-box .active-panel {
z-index: 1;
}

脚本设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script>

var tabs = document.querySelectorAll('.info-box li a');
var panels = document.querySelectorAll('.info-box article');

for(i = 0; i < tabs.length; i++) {
var tab = tabs[i];
setTabHandler(tab, i); //遍历执行函数,设置onclick事件、记录所有选项卡位置信息
}

function setTabHandler(tab, tabPos) {
tab.onclick = function() {
for(i = 0; i < tabs.length; i++) {
tabs[i].className = '';
}

tab.className = 'active';

for(i = 0; i < panels.length; i++) {
panels[i].className = '';
}

panels[tabPos].className = 'active-panel';
}
}

</script>
  • 首先我们保存所有的选项卡和所有的面板引用到两个变量中,名为 tabspanels,这样此后我们可以容易地为它们做事。
  • 然后我们使用 for 循环遍历所有的选项卡,并且在每一个上运行叫做setTabHandler() 的函数,此函数建立当每个选项卡被点击时应该发生的功能。运行时,函数会被传递选项卡,和一个索引数i 指明选项卡在tabs 数组中的位置。
  • setTabHandler()函数中,这个标签创建了一个onclick事件来处理点击,所以当标签被点击的时候,接下来会发生:
    • 用一个 for 循环清除所有标签当前存在的类。
    • 当点击的时候在标签上创建了一个 active 类——从相关联的元素中继承了 CSS 的一些属性,具有和 panels 的样式相同的 colorbackground-color
    • 用一个 for 循环清除所有面板当前存在的类。
    • 当标签被点击的时候在和标签相对应的面板上创建了一个 active-panel 类——从相关联的元素中继承了 CSS 的一些属性,使其 z-index 属性被设置为 1,让它能位于所有的面板的上面。

一个固定位置的列表消息盒子

使用position:fixed固定

一个滑动隐藏的面板

效果

点击某处,然后消息盒子从边界滑出主界面。

结构

1
2
3
body-lable(for="toggle")
input(type="checkbox" id="toggle")
aside

思路

利用有名的 checkbox hack 技术,可以提供无 JavaScript 的方法来通过按钮来控制一个元素。本例中利用labelinput标签控制aside的隐藏和显示。

通过for属性绑定id到了<input>标签的 checkbox 元素。(实现的效果是点击lable,相当于是点击了label和input标签,因为他们绑定在了一起。)

实现

样式设置

设置label样式,字体大小、固定位置、设置z-index避免信息面板覆盖图标、改变悬浮时鼠标指针为手型

1
2
3
4
5
6
7
8
label[for="toggle"] {
font-size: 3rem;
position: absolute;
top: 4px;
right: 5px;
z-index: 1;
cursor: pointer;
}

设置checkbox样式,只需要隐藏掉就行,我们不需要用户看到它

使用checkbox是为了记录当前的状态。

1
2
3
4
input[type="checkbox"] {
position: absolute;
top: -100px;
}

面板设置

设置背景、字体颜色、

设置宽高和内边距、

设置位置,默认时隐藏(将绝对定位的偏移值设置为负值)、

设置过渡效果、滑出时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
aside {
background-color: #a60000;
color: white;

width: 340px;
height: 98%;
padding: 10px 1%;

position: fixed;
top: 0;
right: -370px;

transition: 0.6s all;
}

设置checkbox被选中后,aside滑出

我们选择与 <input> 元素邻接的 <aside> 元素,但是仅仅在它被选择时(请注意使用 :checked 伪类来实现此目的),在这种情况下,我们将 <aside>right 属性设置为 0px,会造成面板再次出现在屏幕上(由于过渡属性会平滑的出现)。再一次点击这个标签会取消选中 checkbox,面板将会跟着再一次消失。

1
2
3
input[type=checkbox]:checked + aside {
right: 0px;
}

这中hack方法的不足

这种效果确实有一些问题 ——这是有点滥用表单元素(它们不是为了这个目的),并且在无障碍方面效果不是很好——标签在默认情况下不可聚焦,并且表单元素的非语义使用可能会导致屏幕朗读器出现问题。JavaScript 和链接或按钮可能更合适,但这样的实验仍然很有趣。