position 属性的初始值是 static。如果把它改成其他值,就说元素就被定位了。而如果元素使用了静态定位,那么就说它未被定位。
布局方法是用各种操作来控制文档流的行为。定位则不同:它将元素彻底从文档流中移走。它允许将元素放在屏幕的任意位置。还可以将一个元素放在另一个元素的前面或后面,彼此重叠。
给一个元素设置 position: fixed
就能将元素放在视口的任意位置。这需要搭配四种属性一起使用:top、right、bottom 和 left。设置这四个值还隐式地定义了元素的宽高。
<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>Document</title>
<style>
body {
font-family: Helvetica, Arial, sans-serif;
min-height: 200vh;
margin: 0;
}
button {
padding: .5em .7em;
border: 1px solid #8d8d8d;
background-color: white;
font-size: 1em;
}
.top-banner {
padding: 1em 0;
background-color: #ffd698;
}
.top-banner-inner {
width: 80%;
max-width: 1000px;
margin: 0 auto;
}
.modal {
display: none;
}
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-body {
position: fixed;
top: 3em;
bottom: 3em;
right: 20%;
left: 20%;
padding: 2em 3em;
background-color: white;
overflow: auto;
}
.modal-close {
cursor: pointer;
}
</style>
</head>
<body>
<header class="top-banner">
<div class="top-banner-inner">
<p>Find out what's going on at Wombat Coffee each
month. Sign up for our newsletter:
<button id="open">Sign up</button>
</p>
</div>
</header>
<div class="modal" id="modal">
<div class="modal-backdrop"></div>
<div class="modal-body">
<button class="modal-close" id="close">Close</button>
<h2>Wombat Newsletter</h2>
<p>Sign up for our monthly newsletter. No spam.
We promise!</p>
<form>
<p>
<label for="email">Email address:</label>
<input type="text" name="email"/>
</p>
<p><button type="submit">Submit</button></p>
</form>
</div>
</div>
<script type="text/javascript">
var modal = document.getElementById('modal');
var open = document.getElementById('open');
var close = document.getElementById('close');
open.addEventListener('click', function(evt) {
evt.preventDefault();
modal.style.display = 'block';
});
close.addEventListener('click', function(evt) {
evt.preventDefault();
modal.style.display = 'none';
});
</script>
</body>
</html>
https://codepen.io/cellinlab/pen/oNpMMxQ
定位一个元素时,不要求指定四个方向的值,可以只指定需要的方向值,然后用 width 和/或 height 来决定它的大小,也可以让元素本身来决定大小。
.fixed {
position: fixed;
top: 1em;
right: 1em;
width: 20%;
}
这段代码会将元素放在距离视口顶部和右边 1em 的位置,宽度为视口宽度的20%。它省略了 bottom 和 height 属性,元素的高度由自身的内容决定。
因为固定元素从文档流中移除了,所以它不再影响页面其他元素的位置。别的元素会跟随正常文档流,就像固定元素不存在一样。也就是说它们通常会在固定元素下面排列,视觉上被遮挡。
固定定位让元素相对视口定位,此时视口被称作元素的包含块(containing block)。
绝对定位的行为也是如此,只是它的包含块不一样。绝对定位不是相对视口,而是相对最近的祖先定位元素。跟固定元素一样,属性 top、right、bottom 和 left 决定了元素的边缘在包含块里的位置。
<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>Document</title>
<style>
body {
font-family: Helvetica, Arial, sans-serif;
min-height: 200vh;
margin: 0;
}
button {
padding: .5em .7em;
border: 1px solid #8d8d8d;
background-color: white;
font-size: 1em;
}
.top-banner {
padding: 1em 0;
background-color: #ffd698;
}
.top-banner-inner {
width: 80%;
max-width: 1000px;
margin: 0 auto;
}
.modal {
display: none;
}
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-body {
position: fixed;
top: 3em;
bottom: 3em;
right: 20%;
left: 20%;
padding: 2em 3em;
background-color: white;
overflow: auto;
}
.modal-close {
position: absolute;
top: 0.3em;
right: 0.3em;
padding: 0.3em;
cursor: pointer;
}
</style>
</head>
<body>
<header class="top-banner">
<div class="top-banner-inner">
<p>Find out what's going on at Wombat Coffee each
month. Sign up for our newsletter:
<button id="open">Sign up</button>
</p>
</div>
</header>
<div class="modal" id="modal">
<div class="modal-backdrop"></div>
<div class="modal-body">
<button class="modal-close" id="close">Close</button>
<h2>Wombat Newsletter</h2>
<p>Sign up for our monthly newsletter. No spam.
We promise!</p>
<form>
<p>
<label for="email">Email address:</label>
<input type="text" name="email"/>
</p>
<p><button type="submit">Submit</button></p>
</form>
</div>
</div>
<script type="text/javascript">
var modal = document.getElementById('modal');
var open = document.getElementById('open');
var close = document.getElementById('close');
open.addEventListener('click', function(evt) {
evt.preventDefault();
modal.style.display = 'block';
});
close.addEventListener('click', function(evt) {
evt.preventDefault();
modal.style.display = 'none';
});
</script>
</body>
</html>
https://codepen.io/cellinlab/pen/BaJPPWo
通常情况下,包含块是元素的父元素。如果父元素未被定位,那么浏览器会沿着 DOM 树往上找它的祖父、曾祖父,直到找到一个定位元素,用它作为包含块。
如果祖先元素都没有定位,那么绝对定位的元素会基于初始包含块(initial containing block)来定位。初始包含块跟视口一样大,固定在网页的顶部。
text-indent 属性将文字推到右边,溢出元素。它的确切值不重要,只要大于按钮宽度即可。由于text-indent 是继承属性,需要在伪类元素选择器上设为 0,因此 x 便不会缩进。
<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>Document</title>
<style>
body {
font-family: Helvetica, Arial, sans-serif;
min-height: 200vh;
margin: 0;
}
button {
padding: .5em .7em;
border: 1px solid #8d8d8d;
background-color: white;
font-size: 1em;
}
.top-banner {
padding: 1em 0;
background-color: #ffd698;
}
.top-banner-inner {
width: 80%;
max-width: 1000px;
margin: 0 auto;
}
.modal {
display: none;
}
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-body {
position: fixed;
top: 3em;
bottom: 3em;
right: 20%;
left: 20%;
padding: 2em 3em;
background-color: white;
overflow: auto;
}
.modal-close {
position: absolute;
top: 0.3em;
right: 0.3em;
padding: 0.3em;
cursor: pointer;
font-size: 2em;
height: 1em;
width: 1em;
text-indent: 10em; /* 让元素里的文字溢出并隐藏 */
overflow: hidden;
border: 0;
}
.modal-close::after {
position: absolute;
line-height: 0.5;
top: 0.2em;
left: 0.1em;
text-indent: 0;
content: '\00D7';
}
</style>
</head>
<body>
<header class="top-banner">
<div class="top-banner-inner">
<p>Find out what's going on at Wombat Coffee each
month. Sign up for our newsletter:
<button id="open">Sign up</button>
</p>
</div>
</header>
<div class="modal" id="modal">
<div class="modal-backdrop"></div>
<div class="modal-body">
<button class="modal-close" id="close">Close</button>
<h2>Wombat Newsletter</h2>
<p>Sign up for our monthly newsletter. No spam.
We promise!</p>
<form>
<p>
<label for="email">Email address:</label>
<input type="text" name="email"/>
</p>
<p><button type="submit">Submit</button></p>
</form>
</div>
</div>
<script type="text/javascript">
var modal = document.getElementById('modal');
var open = document.getElementById('open');
var close = document.getElementById('close');
open.addEventListener('click', function(evt) {
evt.preventDefault();
modal.style.display = 'block';
});
close.addEventListener('click', function(evt) {
evt.preventDefault();
modal.style.display = 'none';
});
</script>
</body>
</html>
https://codepen.io/cellinlab/pen/NWXBBvR
伪类元素现在是绝对定位。因为它表现得像按钮的子元素一样,所以定位的按钮就成为其伪元素的包含块。设置一个较小的 line-height 让伪元素不要太高,用 top 和 left 属性让它在按钮中间定位。
绝对定位是定位类型里的重量级选手。它经常跟 JavaScript 配合,用于弹出菜单、工具提示以及消息盒子。
当第一次给元素加上 position: relative
的时候,通常看不到页面上有任何视觉改变。相对定位的元素以及它周围的所有元素,都还保持着原来的位置。如果加上 top、right、bottom 和 left 属性,元素就会从原来的位置移走,但是不会改变它周围任何元素的位置。
如图,四个 inline-block 元素,给第二个元素加上三个额外的属性:position: relative、top: 1em、left: 2em
,将其从初始位置移走,但是其他元素没有受到影响。它们还是围绕着被移走元素的初始位置,跟随着正常的文档流。
跟固定或者绝对定位不一样,不能用 top、right、bottom 和 left 改变相对定位元素的大小。这些值只能让元素在上、下、左、右方向移动。可以用 top 或者 bottom,但它们不能一起用(bottom 会被忽略)。同理,可以用 left 或 right,但它们也不能一起用(right 会被忽略)。
有时可以用这些属性调整相对元素的位置,把它挤到某个位置,但这只是相对定位的一个冷门用法。更常见的用法是使用 position: 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>Document</title>
<style>
body {
font-family: Helvetica, Arial, sans-serif;
min-height: 200vh;
margin: 0;
}
button {
padding: .5em .7em;
border: 1px solid #8d8d8d;
background-color: white;
font-size: 1em;
}
.top-banner {
padding: 1em 0;
background-color: #ffd698;
}
.top-banner-inner {
width: 80%;
max-width: 1000px;
margin: 0 auto;
}
.modal {
display: none;
}
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-body {
position: fixed;
top: 3em;
bottom: 3em;
right: 20%;
left: 20%;
padding: 2em 3em;
background-color: white;
overflow: auto;
}
.modal-close {
position: absolute;
top: 0.3em;
right: 0.3em;
padding: 0.3em;
cursor: pointer;
font-size: 2em;
height: 1em;
width: 1em;
text-indent: 10em; /* 让元素里的文字溢出并隐藏 */
overflow: hidden;
border: 0;
}
.modal-close::after {
position: absolute;
line-height: 0.5;
top: 0.2em;
left: 0.1em;
text-indent: 0;
content: '\00D7';
}
.container {
width: 80%;
max-width: 1000px;
margin: 1em auto;
}
.dropdown {
display: inline-block;
position: relative;
}
.dropdown-label {
padding: .5em 1.5em;
border: 1px solid #ccc;
background-color: #eee;
}
.dropdown-menu {
display: none;
position: absolute;
left: 0;
top: 2.1em;
min-width: 100%;
background-color: #eee;
}
.dropdown:hover .dropdown-menu {
display: block;
}
.submenu {
padding-left: 0;
margin: 0;
list-style-type: none;
border: 1px solid #999;
}
.submenu > li > a {
display: block;
padding: .5em 1.5em;
background-color: #eee;
color: #369;
text-decoration: none;
}
.submenu > li > a:hover {
background-color: #fff;
}
</style>
</head>
<body>
<header class="top-banner">
<div class="top-banner-inner">
<p>Find out what's going on at Wombat Coffee each
month. Sign up for our newsletter:
<button id="open">Sign up</button>
</p>
</div>
</header>
<div class="modal" id="modal">
<div class="modal-backdrop"></div>
<div class="modal-body">
<button class="modal-close" id="close">Close</button>
<h2>Wombat Newsletter</h2>
<p>Sign up for our monthly newsletter. No spam.
We promise!</p>
<form>
<p>
<label for="email">Email address:</label>
<input type="text" name="email"/>
</p>
<p><button type="submit">Submit</button></p>
</form>
</div>
</div>
<div class="container">
<nav>
<div class="dropdown">
<div class="dropdown-label">Main Menu</div>
<div class="dropdown-menu">
<ul class="submenu">
<li><a href="/">Home</a></li>
<li><a href="/coffees">Coffees</a></li>
<li><a href="/brewers">Brewers</a></li>
<li><a href="/specials">Specials</a></li>
<li><a href="/about">About us</a></li>
</ul>
</div>
</div>
</nav>
<h1>Wombat Coffee Roasters</h1>
</div>
<script type="text/javascript">
var modal = document.getElementById('modal');
var open = document.getElementById('open');
var close = document.getElementById('close');
open.addEventListener('click', function(evt) {
evt.preventDefault();
modal.style.display = 'block';
});
close.addEventListener('click', function(evt) {
evt.preventDefault();
modal.style.display = 'none';
});
</script>
</body>
</html>
https://codepen.io/cellinlab/pen/OJzwoJp
.dropdown-label {
padding: 0.5em 2em 0.5em 1.5em;
border: 1px solid #ccc;
background-color: #eee;
}
.dropdown-label::after {
content: ' ';
position: absolute;
right: 1em;
top: 1em;
border: 0.3em solid;
border-color: black transparent transparent;
}
.dropdown:hover .dropdown-label::after {
top: 0.7em;
border-color: transparent transparent black;
}
<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>Document</title>
<style>
body {
font-family: Helvetica, Arial, sans-serif;
min-height: 200vh;
margin: 0;
}
button {
padding: .5em .7em;
border: 1px solid #8d8d8d;
background-color: white;
font-size: 1em;
}
.top-banner {
padding: 1em 0;
background-color: #ffd698;
}
.top-banner-inner {
width: 80%;
max-width: 1000px;
margin: 0 auto;
}
.modal {
display: none;
}
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-body {
position: fixed;
top: 3em;
bottom: 3em;
right: 20%;
left: 20%;
padding: 2em 3em;
background-color: white;
overflow: auto;
}
.modal-close {
position: absolute;
top: 0.3em;
right: 0.3em;
padding: 0.3em;
cursor: pointer;
font-size: 2em;
height: 1em;
width: 1em;
text-indent: 10em; /* 让元素里的文字溢出并隐藏 */
overflow: hidden;
border: 0;
}
.modal-close::after {
position: absolute;
line-height: 0.5;
top: 0.2em;
left: 0.1em;
text-indent: 0;
content: '\00D7';
}
.container {
width: 80%;
max-width: 1000px;
margin: 1em auto;
}
.dropdown {
display: inline-block;
position: relative;
}
.dropdown-label {
padding: 0.5em 2em 0.5em 1.5em;
border: 1px solid #ccc;
background-color: #eee;
}
.dropdown-label::after {
content: ' ';
position: absolute;
right: 1em;
top: 1em;
border: 0.3em solid;
border-color: black transparent transparent;
}
.dropdown:hover .dropdown-label::after {
top: 0.7em;
border-color: transparent transparent black;
}
.dropdown-menu {
display: none;
position: absolute;
left: 0;
top: 2.1em;
min-width: 100%;
background-color: #eee;
}
.dropdown:hover .dropdown-menu {
display: block;
}
.submenu {
padding-left: 0;
margin: 0;
list-style-type: none;
border: 1px solid #999;
}
.submenu > li > a {
display: block;
padding: .5em 1.5em;
background-color: #eee;
color: #369;
text-decoration: none;
}
.submenu > li > a:hover {
background-color: #fff;
}
</style>
</head>
<body>
<header class="top-banner">
<div class="top-banner-inner">
<p>Find out what's going on at Wombat Coffee each
month. Sign up for our newsletter:
<button id="open">Sign up</button>
</p>
</div>
</header>
<div class="modal" id="modal">
<div class="modal-backdrop"></div>
<div class="modal-body">
<button class="modal-close" id="close">Close</button>
<h2>Wombat Newsletter</h2>
<p>Sign up for our monthly newsletter. No spam.
We promise!</p>
<form>
<p>
<label for="email">Email address:</label>
<input type="text" name="email"/>
</p>
<p><button type="submit">Submit</button></p>
</form>
</div>
</div>
<div class="container">
<nav>
<div class="dropdown">
<div class="dropdown-label">Main Menu</div>
<div class="dropdown-menu">
<ul class="submenu">
<li><a href="/">Home</a></li>
<li><a href="/coffees">Coffees</a></li>
<li><a href="/brewers">Brewers</a></li>
<li><a href="/specials">Specials</a></li>
<li><a href="/about">About us</a></li>
</ul>
</div>
</div>
</nav>
<h1>Wombat Coffee Roasters</h1>
</div>
<script type="text/javascript">
var modal = document.getElementById('modal');
var open = document.getElementById('open');
var close = document.getElementById('close');
open.addEventListener('click', function(evt) {
evt.preventDefault();
modal.style.display = 'block';
});
close.addEventListener('click', function(evt) {
evt.preventDefault();
modal.style.display = 'none';
});
</script>
</body>
</html>
https://codepen.io/cellinlab/pen/ZEvjMLV
在同一页面定位多个元素时,可能会遇到两个不同定位的元素重叠的现象。
浏览器将 HTML 解析为 DOM 的同时还创建了另一个树形结构,叫作渲染树(render tree)。它代表了每个元素的视觉样式和位置。同时还决定浏览器绘制元素的顺序。顺序很重要,因为如果元素刚好重叠,后绘制的元素就会出现在先绘制的元素前面。
通常情况下(使用定位之前),元素在 HTML 里出现的顺序决定了绘制的顺序。
<div>one</div>
<div>two</div>
<div>three</div>
定位元素时,这种行为会改变。浏览器会先绘制所有非定位的元素,然后绘制定位元素。默认情况下,所有的定位元素会出现在非定位元素前面。
如图所示,给前两个元素加了 position: relative
,它们就绘制到了前面,覆盖了静态定位的第三个元素,尽管元素在 HTML 里的顺序并未改变。
注意,在定位元素里,第二个定位元素还是出现在第一个定位元素前面。定位元素会被放到前面,但是基于源码的层叠关系并没有改变。
通常情况下,模态框要放在网页内容的最后,</body>
关闭标签之前。大多数构建模态框的 JavaScript 库会自动这样做。因为模态框使用固定定位,所以不必关心它的标记出现在哪里,它会一直定位到屏幕中间。
改变固定定位元素的标记位置不会产生不好的影响,但是对相对定位或绝对定位的元素来说,通常无法用改变标记位置的方法解决层叠问题。相对定位依赖于文档流,绝对定位元素依赖于它的定位祖先节点。这时候需要用 z-index 属性来控制它们的层叠行为。
z-index属性的值可以是任意整数(正负都行)。z 表示的是笛卡儿 x-y-z 坐标系里的深度方向。拥有较高 z-index 的元素出现在拥有较低 z-index 的元素前面。拥有负数 z-index 的元素出现在静态元素后面。
使用 z-index 是解决网页层叠问题的第二个方法。该方法不要求修改 HTML 的结构。
z-index 的行为很好理解,但是使用它时要注意两个小陷阱。第一,z-index 只在定位元素上生效,不能用它控制静态元素。第二,给一个定位元素加上 z-index 可以创建层叠上下文。
一个层叠上下文包含一个元素或者由浏览器一起绘制的一组元素。其中一个元素会作为层叠上下文的根,比如给一个定位元素加上 z-index 的时候,它就变成了一个新的层叠上下文的根。所有后代元素就是这个层叠上下文的一部分。
不要将层叠上下文跟 BFC 弄混了,它们是两个独立的概念,尽管不一定互斥。层叠上下文负责决定哪些元素出现在另一些元素前面,而 BFC 负责处理文档流,以及元素是否会重叠。
实际上将层叠上下文里的所有元素一起绘制会造成严重的后果:层叠上下文之外的元素无法叠放在层叠上下文内的两个元素之间。换句话说,如果一个元素叠放在一个层叠上下文前面,那么层叠上下文里没有元素可以被拉到该元素前面。同理,如果一个元素被放在层叠上下文后面,层叠上下文里没有元素能出现在该元素后面。
叠放在第二个盒子后面的第一个盒子是一个层叠上下文的根。因此,虽然它的z-index值很高,但是它内部的绝对定位元素不会跑到第二个盒子前面。
<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>Document</title>
<style>
body {
margin: 40px;
}
.box {
display: inline-block;
width: 200px;
line-height: 200px;
text-align: center;
border: 2px solid black;
background-color: #ea5;
margin-left: -60px;
vertical-align: top;
}
.one {
margin-left: ;
}
.two {
margin-top: 30px;
}
.three {
margin-top: 60px;
}
.positioned {
position: relative;
background-color: #5ae;
z-index: ;
}
.absolute {
position: absolute;
top: 1em;
right: 1em;
height: 2em;
background-color: #fff;
border: 2px dashed #000;
z-index: ;
line-height: initial;
padding: 1em;
}
</style>
</head>
<body>
<div class="box one positioned">
one
<div class="absolute">nested</div>
</div>
<div class="box two positioned">
two
</div>
<div class="box three">
three
</div>
</body>
</html>
https://codepen.io/cellinlab/pen/MWrBPaW
给一个定位元素加上 z-index 是创建层叠上下文最主要的方式,但还有别的属性也能创建,比如小于 1 的 opacity 属性,还有 transform、filter属性。由于这些属性主要会影响元素及其子元素渲染的方式,因此一起绘制父子元素。文档根节点(<html>
)也会给整个页面创建一个顶级的层叠上下文。
所有层叠上下文内的元素会按照以下顺序,从后到前叠放:
如果不根据组件的优先级定义清晰的层叠顺序,那么一个样式表很容易演变成一场 z-index 大战。如果没有清晰的说明,开发人员在给一个模态框之类的元素添加样式时,为了不被其他元素遮挡,就会设置一个高得离谱的 z-index,比如 999999。这样的事情重复几次后,大家就只能凭感觉给一个新的组件设置 z-index。
如果你使用预处理器,比如 LESS 或 SASS,或者支持的所有浏览器都支持自定义属性,就能很方便地处理这个问题。将所有的 z-index 都定义为变量放到同一个地方。这样就能清晰地看到哪些元素在前哪些元素在后。
--z-loading-indicator: 100;
--z-nav-menu: 200;
--z-dropdown-menu: 300;
--z-modal-backdrop: 400;
--z-modal-body: 410;
如果发现 z-index 没有按照预期表现,就在 DOM 树里往上找到元素的祖先节点,直到发现层叠上下文的根。然后给它设置 z-idnex,将整个层叠上下文向前或者向后放。还要注意多个层叠上下文嵌套的情况。
网页很复杂时,很难判断是哪个层叠上下文导致的问题。因此,在创建层叠上下文的时候就一定要多加小心,没有特殊理由的话不要随意创建,尤其是当一个元素包含了网页很大一部分内容的时候。尽可能将独立的定位元素(比如模态框)放到 DOM 的顶层,结束标签 </body>
之前,这样就没有外部的层叠上下文能束缚它们了。
有些开发人员会忍不住给页面的大量元素使用定位。一定要克制这种冲动。定位用得越多,网页就越复杂,也就越难调试。
如果能够依靠文档流,而不是靠明确指定定位的方式实现布局,那么浏览器会处理好很多边缘情况。记住,定位会将元素拉出文档流。一般来说,只有在需要将元素叠放到别的元素之前时,才应该用定位。
粘性定位(sticky positioning),是相对定位和固定定位的结合体:正常情况下,元素会随着页面滚动,当到达屏幕的特定位置时,如果用户继续滚动,它就会“锁定”在这个位置。最常见的用例是侧边栏导航。
<head>
<style>
body {
font-family: Helvetica, Arial, sans-serif;
min-height: 200vh;
margin: 0;
}
button {
padding: .5em .7em;
border: 1px solid #8d8d8d;
background-color: white;
font-size: 1em;
}
.top-banner {
padding: 1em 0;
background-color: #ffd698;
}
.top-banner-inner {
width: 80%;
max-width: 1000px;
margin: 0 auto;
}
.modal {
display: none;
}
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1;
}
.modal-body {
position: fixed;
top: 3em;
bottom: 3em;
right: 20%;
left: 20%;
padding: 2em 3em;
background-color: white;
overflow: auto;
z-index: 2;
}
.modal-close {
position: absolute;
top: 0;
right: 0;
padding: 0.3em;
font-size: 2em;
height: 1.5em;
width: 1.5em;
cursor: pointer;
border: 0;
}
.modal-close::before {
display: block;
content: '\00D7';
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
}
.container {
display: flex;
width: 80%;
max-width: 1000px;
margin: 1em auto;
min-height: 100vh;
}
.dropdown {
display: inline-block;
position: relative;
}
.dropdown-label {
padding: 0.5em 2em 0.5em 1.5em;
border: 1px solid #ccc;
background-color: #eee;
}
.dropdown-label::after {
content: "";
position: absolute;
right: 1em;
top: 1em;
border: 0.3em solid;
border-color: black transparent transparent;
}
.dropdown:hover .dropdown-label::after {
top: 0.7em;
border-color: transparent transparent black;
}
.dropdown-menu {
display: none;
position: absolute;
left: 0;
top: 2.1em;
min-width: 100%;
background-color: #eee;
}
.dropdown:hover .dropdown-menu {
display: block;
}
.submenu {
padding-left: 0;
margin: 0;
list-style-type: none;
border: 1px solid #999;
}
.submenu > li + li {
border-top: 1px solid #999;
}
.submenu > li > a {
display: block;
padding: .5em 1.5em;
background-color: #eee;
color: #369;
text-decoration: none;
}
.submenu > li > a:hover {
background-color: #fff;
}
.col-main {
flex: 1 80%;
}
.col-sidebar {
flex: 20%;
}
.affix {
position: sticky;
top: 1em;
}
</style>
</head>
<body>
<header class="top-banner">
<div class="top-banner-inner">
<p>Find out what's going on at Wombat Coffee each
month. Sign up for our newsletter:
<button id="open">Sign up</button>
</p>
</div>
</header>
<div class="modal" id="modal">
<div class="modal-backdrop"></div>
<div class="modal-body">
<button class="modal-close" id="close">
<span class="sr-only">close</span>
</button>
<h2>Wombat Newsletter</h2>
<p>Sign up for our monthly newsletter. No spam.
We promise!</p>
<form>
<p>
<label for="email">Email address:</label>
<input type="text" name="email"/>
</p>
<p><button type="submit">Submit</button></p>
</form>
</div>
</div>
<div class="container">
<main class="col-main">
<nav>
<div class="dropdown">
<div class="dropdown-label">Main Menu</div>
<div class="dropdown-menu">
<ul class="submenu">
<li><a href="/">Home</a></li>
<li><a href="/coffees">Coffees</a></li>
<li><a href="/brewers">Brewers</a></li>
<li><a href="/specials">Specials</a></li>
<li><a href="/about">About us</a></li>
</ul>
</div>
</div>
</nav>
<h1>Wombat Coffee Roasters</h1>
</main>
<aside class="col-sidebar">
<div class="affix">
<ul class="submenu">
<li><a href="/">Home</a></li>
<li><a href="/coffees">Coffees</a></li>
<li><a href="/brewers">Brewers</a></li>
<li><a href="/specials">Specials</a></li>
<li><a href="/about">About us</a></li>
</ul>
</div>
</aside>
</div>
<script type="text/javascript">
var button = document.getElementById('open');
var close = document.getElementById('close');
var modal = document.getElementById('modal');
button.addEventListener('click', function(event) {
event.preventDefault();
modal.style.display = 'block';
});
close.addEventListener('click', function(event) {
event.preventDefault();
modal.style.display = 'none';
});
</script>
</body>