CSS 提供了一些控制网页布局的几个重要工具,这里介绍定位。
定
元素的定位类型:
定位方式 | 属性值 | 描述 |
---|---|---|
静态定位 | static | 默认值,即标准流,不能通过方位属性进行移动。让盒子固定在屏幕中的某个位置。 |
固定定位 | fixed | 在页面中不占位置,相对于浏览器可视区域进行移动。 |
相对定位 | relative | 相对于自己之前的位置移动,在页面中占位置(未脱标)。配置绝对定位组(子绝父相),用于小范围的移动 |
绝对定位 | absolute | 在页面中不占位置,默认相对于浏览器可视区域进行移动。配置绝对定位组(子绝父相) |
前面的布局方式是用各种操作来控制文档流的行为,而定位则不同:它将元素彻底从文档流中移走。它允许你将元素放在屏幕的任意位置。还可以将一个元素放在另一个元素的前面或后面,彼此重叠。
定位使用 position 属性,初始值是static。它可以用来构建下拉菜单、模态框以及现代Web应用程序的一些基本效果。定位可能让布局变得很复杂。如果不完全了解定位以及它可能带来的后果,就很容易给自己挖坑。有时候你可能会把错误的元素放在其他元素前面,要解决这个问题却没有那么简单。
固定定位
固定定位是比较好理解的一种定位类型。
给一个元素设置 position: fixed 就能将元素放在视口的任意位置。这需要搭配四种属性一起使用:top、right、bottom和left。这些属性的值决定了固定定位的元素与浏览器视口边缘的距离。比如,top: 3em表示元素的上边缘距离视口顶部3em。
实现一个模态框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Position Document</title>
<style>
:root {
box-sizing: border-box;
}
*,
::before,
::after {
box-sizing: inherit;
}
/* 设置网页高度,让页面出现滚动条(只为演示) */
body {
min-height: 200vh;
margin: 0;
font-family: Arial, Helvetica, sans-serif;
}
button {
padding: 0.5em 0.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;
}
/* 默认隐藏模态框。打开时,js会设置display: block */
.modal {
display: none;
}
/* 打开模态框时,用半透明的蒙层遮挡网页剩余内容。四个方向都设置为0,让蒙层填满整个视口 */
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1; /* 将模态框的蒙层拉到没有设置z-index的元素前面 */
}
/* 模态框主体定位 */
.modal-body {
position: fixed;
top: 3em;
bottom: 3em;
right: 20%;
left: 20%;
padding: 2em 3em;
background-color: white;
overflow: auto; /* 允许模态框主体在需要时滚动 */
z-index: 1; /* 将模态框的主体拉到蒙层前面 */
}
.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 + li {
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 newsletter. No spam. We promise!
</p>
<form action="">
<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</a></li>
</ul>
</div>
</div>
</nav>
<h1>Wombat Coffee Roasters</h1>
</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>
</html>
控制定位元素的大小
定位一个元素时,不要求指定四个方向的值,可以只指定需要的方向值,然后用width和/或height来决定它的大小,也可以让元素本身来决定大小。
position: fixed;
top: 1em;
right: 1em;
width: 20%;
上面定位,将元素放在距离视口顶部和右边1em的位置,宽度为视口宽度的20%。它省略了bottom和height属性,元素的高度由自身的内容决定。例如,这可以用于将一个导航菜单固定到屏幕上。即使用户滚动网页内容,该元素的位置也不会改变。
因为固定元素从文档流中移除了,所以它不再影响页面其他元素的位置。别的元素会跟随正常文档流,就像固定元素不存在一样。也就是说它们通常会在固定元素下面排列,视觉上被遮挡。
绝对定位
固定定位让元素相对视口定位,此时视口被称作元素的包含块(containing block)。
绝对定位的包含块不一样。绝对定位不是相对视口,而是相对最近的祖先定位元素。跟固定元素一样,属性top、right、bottom和left决定了元素的边缘在包含块里的位置。
让Close按钮绝对定位
为了让Close按钮绝对定位,将其放在模态框的右上角:
.modal-close {
position: absolute;
top: 0.3em;
right: 0.3em;
padding: 0.3em;
cursor: pointer;
}
如果父元素未被定位,那么浏览器会沿着DOM树往上找它的祖父、曾祖父,直到找到一个定位元素,用它作为包含块。
如果祖先元素都没有定位,那么绝对定位的元素会基于初始包含块(initial containing block)来定位。初始包含块跟视口一样大,固定在网页的顶部。
定位伪元素
将Close按钮改成 x:
.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; /* text-indent属性将文字推到右边,溢出元素 */
overflow: hidden;
border: 0;
}
.modal-close::after {
position: absolute;
line-height: 0.5;
top: 0.2em;
left: 0.1em;
text-indent: 0; /* text-indent是继承属性,需要在伪类元素选择器上设为0,x便不会缩进 */
content: "\00D7"; /*相比字母x,推荐用乘法符号的Unicode字符。它更对称,也更好看。HTML字符×;可以显示为这个字符,但在CSS的content属性里,必须写成转义的Unicode数字:\00D7。*/
}
相对定位
相对定位不太好理解。当第一次给元素加上position: relative的时候,你通常看不到页面上有任何视觉改变。相对定位的元素以及它周围的所有元素,都还保持着原来的位置。
如果加上top、right、bottom和left属性,元素就会从原来的位置移走,但是不会改变它周围任何元素的位置。
跟固定或者绝对定位不一样,不能用top、right、bottom和left改变相对定位元素的大小。这些值只能让元素在上、下、左、右方向移动。可以用top或者bottom,但它们不能一起用(bottom会被忽略)。同理,可以用left或right,但它们也不能一起用(right会被忽略)。
更常见的用法是使用position: relative给它里面的绝对定位元素创建一个包含块。
创建一个下拉菜单
将下面代码添加到HTML中,放在
<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</a></li>
</ul>
</div>
</div>
</nav>
<h1>Wombat Coffee Roasters</h1>
</div>
使用伪元素创建一个三角形
用边框画一个三角形当作向下箭头。这里用标签的::after伪元素来画三角形,然后使用绝对定位将它放到标签的右边。
/* 在标签的右边定位元素 */
.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; /* 鼠标悬停时,让箭头向上 */
}
伪元素因为没有内容,所以没有宽或高。用border-color简写属性设置上边框为黑色,左右和下面的边框为透明,构造一个向下的箭头。
打开菜单,箭头方向反转,朝向上面,表示菜单可以被关闭。微调top值(从1em到0.7em),让向上的箭头看起来跟向下的箭头处于相同的位置。