实用定位示例
本文介绍了如何构建一些现实世界的示例,以说明使用定位可以完成哪些操作。
带选项卡的信息框
我们将首先介绍一个经典的选项卡信息框,这是一个非常常见的特性,用于在有限的区域内容纳大量信息。这包括信息量大的应用程序(如策略/战争游戏)、网站的移动版本(屏幕较窄,空间有限)以及紧凑的信息框(您可能希望提供大量信息,而不会让信息占据整个用户界面)。在我们完成示例后,它将看起来像这样:
注意:您可以访问 tabbed-info-box.html(源代码)查看正在运行的最终示例。查看它可以了解您将在本文节中构建的内容。
您可能会想,“为什么不将单独的选项卡创建为单独的网页,然后让选项卡点击切换到单独的页面来实现效果?” 这种代码确实会更简单,但是,每个单独的“页面”视图实际上都是一个新加载的网页,这将使跨视图保存信息变得更加困难,并且会使此功能更难集成到更大的用户界面设计中。
首先,我们希望您创建起始文件的本地副本 - tabbed-info-box-start.html 和 tabs-manual.js。将它们保存在本地计算机上的某个合理位置,并在文本编辑器中打开 tabbed-info-box-start.html
。让我们看一下 body
中包含的 HTML 代码:
<section class="info-box">
<div role="tablist" class="manual">
<button
id="tab-1"
type="button"
role="tab"
aria-selected="true"
aria-controls="tabpanel-1">
<span>Tab 1</span>
</button>
<button
id="tab-2"
type="button"
role="tab"
aria-selected="false"
aria-controls="tabpanel-2">
<span>Tab 2</span>
</button>
<button
id="tab-3"
type="button"
role="tab"
aria-selected="false"
aria-controls="tabpanel-3">
<span>Tab 3</span>
</button>
</div>
<div class="panels">
<article id="tabpanel-1" role="tabpanel" aria-labelledby="tab-1">
<h2>The first tab</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque
turpis nibh, porttitor nec venenatis eu, pulvinar in augue. Vestibulum
et orci scelerisque, vulputate tellus quis, lobortis dui. Vivamus varius
libero at ipsum mattis efficitur ut nec nisl. Nullam eget tincidunt
metus. Donec ultrices, urna maximus consequat aliquet, dui neque
eleifend lorem, a auctor libero turpis at sem. Aliquam ut porttitor
urna. Nulla facilisi.
</p>
</article>
<article id="tabpanel-2" role="tabpanel" aria-labelledby="tab-2">
<h2>The second tab</h2>
<p>
This tab hasn't got any Lorem Ipsum in it. But the content isn't very
exciting all the same.
</p>
</article>
<article id="tabpanel-3" role="tabpanel" aria-labelledby="tab-3">
<h2>The third tab</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque
turpis nibh, porttitor nec venenatis eu, pulvinar in augue. And now an
ordered list: how exciting!
</p>
<ol>
<li>dui neque eleifend lorem, a auctor libero turpis at sem.</li>
<li>Aliquam ut porttitor urna.</li>
<li>Nulla facilisi</li>
</ol>
</article>
</div>
</section>
因此,这里有一个带有 class
为 info-box
的 <section>
元素,它包含两个 <div>
。第一个 div 包含三个按钮,这些按钮将成为用于显示我们内容面板的实际选项卡。第二个 div 包含三个 <article>
元素,它们将构成与每个选项卡相对应的内容面板。每个面板都包含一些示例内容。
这里的想法是,我们将对选项卡进行样式设置,使其看起来像一个标准的水平导航菜单,并对面板进行样式设置,使其使用绝对定位叠加在一起。我们还将提供一些 JavaScript 代码供您在页面中包含,以在按下选项卡时显示相应的面板,并对选项卡本身进行样式设置。您现在不需要理解 JavaScript 代码本身,但您应该考虑尽快学习一些基本的 JavaScript - 您的用户界面功能越复杂,就越有可能需要一些 JavaScript 来实现您想要的功能。
常规设置
首先,在 <style>
的开始和结束标签之间添加以下内容:
html {
font-family: sans-serif;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
这只是一些常规设置,用于在我们的页面上设置无衬线字体,使用 border-box
box-sizing
模型,并删除默认的 <body>
边距。
接下来,在您之前的 CSS 下面添加以下内容:
.info-box {
width: 452px;
height: 400px;
margin: 1.25rem auto 0;
}
这会对内容设置特定的宽度和高度,并使用旧的 margin: 1.25rem auto 0
将其居中在屏幕上。之前在课程中,我们建议尽可能避免对内容容器设置固定高度;在这种情况下是可以的,因为我们在选项卡中具有固定内容。
对选项卡进行样式设置
现在,我们希望对选项卡进行样式设置,使其看起来像选项卡 - 基本上,它们是水平导航菜单,但与我们在课程中之前看到的点击时加载不同的网页不同,它们会使同一个页面上显示不同的面板。首先,在 CSS 底部添加以下规则,使 tablist
成为一个 flex
容器,并使其跨越 100% 的宽度:
.info-box [role="tablist"] {
min-width: 100%;
display: flex;
}
注意:在本示例中,我们在整个链中使用后代选择器,并在开头使用 .info-box
- 这样可以将此功能插入到已经存在其他内容的页面中,而不用担心会干扰应用于页面其他部分的样式。
接下来,我们将对按钮进行样式设置,使其看起来像选项卡。添加以下 CSS:
.info-box [role="tab"] {
padding: 0 1rem 0 1rem;
line-height: 3rem;
background: white;
color: #b60000;
font-weight: bold;
border: none;
outline: none;
}
接下来,我们将设置选项卡的 :focus
和 :hover
状态,使其在获得焦点/悬停时看起来不同,为用户提供一些视觉反馈。
.info-box [role="tab"]:focus span,
.info-box [role="tab"]:hover span {
outline: 1px solid blue;
outline-offset: 6px;
border-radius: 4px;
}
然后,我们将设置一个规则,当 aria-selected
属性在其上设置为 true
时,突出显示其中一个选项卡。我们将使用 JavaScript 在点击选项卡时设置此属性。将以下 CSS 放置在其他样式的下方:
.info-box [role="tab"][aria-selected="true"] {
background-color: #b60000;
color: white;
}
对面板进行样式设置
下一步是为我们的面板进行样式设置。让我们开始吧!
首先,添加以下规则以对 .panels
<div>
容器进行样式设置。在这里,我们设置了固定 height
,以确保面板紧密地适合信息框内部,position
relative
将 <div>
设置为定位上下文,这样您就可以将定位子元素相对于它而不是初始视窗进行定位,最后,我们 clear
在上面的 CSS 中设置的浮动,这样就不会干扰布局的其余部分。
.info-box .panels {
height: 352px;
clear: both;
position: relative;
}
最后,在本节中,我们将对构成我们面板的单个 <article>
元素进行样式设置。我们将添加的第一条规则将对面板进行绝对 position
设置,并使它们都紧贴 top
和 left
它们的 <div>
容器 - 这一部分是整个布局功能的关键,因为它使面板叠加在一起。该规则还为面板提供了与容器相同的高度,并为内容提供了一些填充、文本 color
和 background-color
。
.info-box [role="tabpanel"] {
background-color: #b60000;
color: white;
position: absolute;
padding: 0.8rem 1.2rem;
height: 352px;
top: 0;
left: 0;
}
我们将在这里添加的第二条规则,使设置了 is-hidden
类别的面板隐藏起来。同样,我们将在适当的时候使用 JavaScript 添加/删除此类。当选择一个选项卡时,其对应的面板将删除其 is-hidden
类,所有其他面板将设置 is-hidden
类,因此一次只能看到一个面板。
.info-box [role="tabpanel"].is-hidden {
display: none;
}
JavaScript
使此功能生效的最后一部分是 JavaScript 代码。tabs-manual.js
文件已使用 <script>
标签包含在内:
<script src="tabs-manual.js"></script>
这段代码执行以下操作:
- 在 窗口加载事件 中,它为所有
tablist
元素初始化TabsManual
类。 - 当创建一个
TabsManual
对象时,构造函数会将所有选项卡和面板引用收集到tabs
和tabpanels
变量中,这样我们以后就可以轻松地对它们进行操作。 - 构造函数还会在所有选项卡上注册
click
和keydown
事件处理程序。事件处理程序包括有关使用点击或按键选择选项卡时应该发生什么的逻辑。 - 在
setSelectedTab(currentTab)
函数中,会发生以下情况:- 使用
for
循环遍历所有选项卡,并通过将aria-selected
属性设置为false
以及在相应面板上设置is-hidden
类来取消选择它们。 - 在选定的选项卡(
currentTab
)上,aria-selected
设置为true
,并且从相应的面板中删除了is-hidden
类。
- 使用
- 该代码还包含使用
向左箭头
、向右箭头
、Home
和End
键进行键盘导航的逻辑。
固定位置带选项卡的信息框
在我们的第二个示例中,我们将使用第一个示例(我们的信息框),并将它添加到完整网页的上下文中。但不仅如此,我们还将为它提供固定位置,使其始终保持在浏览器窗口的相同位置。当主要内容滚动时,信息框将保持在屏幕上的相同位置。我们完成的示例将看起来像这样:
注意:您可以访问 fixed-info-box.html(源代码)查看正在运行的最终示例。查看它可以了解您将在本文节中构建的内容。
作为起点,您可以使用您在本文第一节中完成的示例,或者从我们的 GitHub 存储库中创建 info-box.html 的本地副本。
HTML 添加
首先,我们需要一些额外的 HTML 代码来表示网页的主要内容。在 <body>
的开始标签之后,现有 section
之前添加以下 <section>
:
<section class="fake-content">
<h1>Fake content</h1>
<p>
This is fake content. Your main web page contents would probably go here.
</p>
<p>
This is fake content. Your main web page contents would probably go here.
</p>
<p>
This is fake content. Your main web page contents would probably go here.
</p>
<p>
This is fake content. Your main web page contents would probably go here.
</p>
<p>
This is fake content. Your main web page contents would probably go here.
</p>
<p>
This is fake content. Your main web page contents would probably go here.
</p>
<p>
This is fake content. Your main web page contents would probably go here.
</p>
<p>
This is fake content. Your main web page contents would probably go here.
</p>
</section>
注意:您可以随意更改虚假内容,使其成为真实内容。
对现有 CSS 进行更改
接下来,我们需要对现有的 CSS 进行一些小的更改,以使信息框放置并定位。更改 .info-box
规则,删除 margin: 0 auto;
(我们不再希望信息框居中),添加 position: fixed;
,并将其粘贴到浏览器视窗的 top
处。
它现在应该看起来像这样:
.info-box {
width: 452px;
height: 400px;
margin: 0 auto;
position: fixed;
top: 0;
}
对主要内容进行样式设置
本示例中剩下的唯一事情是为主要内容提供一些样式。在 CSS 的其余部分下方添加以下规则:
.fake-content {
background-color: #a60000;
color: white;
padding: 10px;
height: 2000px;
margin-left: 470px;
}
.fake-content p {
margin-bottom: 200px;
}
首先,我们为内容提供与信息框面板相同的 background-color
、color
和 padding
。然后,我们为它提供一个较大的 margin-left
,以便将其移到右侧,为信息框腾出空间,因此它不会与任何其他内容重叠。
这标志着第二个示例的结束;我们希望您会发现第三个示例同样有趣。
滑动隐藏面板
我们将在此处介绍的最后一个示例是一个面板,它会在点击图标时滑入和滑出屏幕 - 正如前面提到的,这在移动布局等情况下很受欢迎,在移动布局中,可用的屏幕空间很小,因此您不希望通过显示菜单或信息面板而不是有用的内容来占用大部分空间。
我们完成的示例将看起来像这样:
注意:您可以访问 hidden-info-panel.html(源代码)查看正在运行的最终示例。查看它可以了解您将在本文节中构建的内容。
首先,从我们的 GitHub 仓库中创建一个 hidden-info-panel-start.html 的本地副本。这与之前的示例无关,因此需要一个新的起始文件。让我们看一下文件中的 HTML 代码。
<button
type="button"
id="menu-button"
aria-haspopup="true"
aria-controls="info-panel"
aria-expanded="false">
❔
</button>
<aside id="info-panel" aria-labelledby="menu-button">
…
</aside>
首先,我们有一个带有特殊问号字符作为按钮文本的 <button>
元素。按下此按钮将显示/隐藏 aside
信息面板。在接下来的部分中,我们将解释这一切是如何运作的。
为按钮设置样式
首先,让我们处理按钮 - 在你的 <style>
标签之间添加以下 CSS 代码
#menu-button {
position: absolute;
top: 0.5rem;
right: 0.5rem;
z-index: 1;
font-size: 3rem;
cursor: pointer;
border: none;
background-color: transparent;
}
第一个规则为 <button>
设置样式;在这里我们已经
为面板设置样式
现在该为实际的滑动面板本身设置样式了。在你的 CSS 代码底部添加以下规则
#info-panel {
background-color: #a60000;
color: white;
width: 340px;
height: 100%;
padding: 0 20px;
position: fixed;
top: 0;
right: -370px;
transition: 0.6s right ease-out;
}
这里有很多内容 - 让我们逐一讨论
- 首先,我们为信息框设置了一些简单的
background-color
和color
属性。 - 接下来,我们为面板设置了一个固定的
width
,并使它的height
占据浏览器视窗的整个高度。 - 我们还包括一些水平
padding
来增加间距。 - 接下来,我们为面板设置
position: fixed;
,这样它将始终出现在相同的位置,即使页面有内容需要滚动。我们将它固定在视窗的top
位置,并默认将其设置为在right
方向超出屏幕。 - 最后,我们为元素设置一个
transition
。Transition 是一个有趣的特性,它允许你使状态之间的变化平滑过渡,而不是突然地“开启”或“关闭”。在本例中,我们打算在复选框被选中时使面板平滑地滑入屏幕。(或者换句话说,当问号图标被点击时。)
设置选中状态
最后需要添加一段 CSS 代码 - 将以下代码放在你的 CSS 代码底部
#info-panel.open {
right: 0px;
}
该规则表明,当信息面板上设置了 .open
类时,将 <aside>
的 right
属性设置为 0px
,这会导致面板再次出现在屏幕上(由于过渡而平滑过渡)。移除 .open
类将再次隐藏面板。
为了通过点击按钮在信息面板上添加/移除 .open
类,我们需要使用一些 JavaScript 代码。在 <script>
标签之间添加以下代码
const button = document.querySelector("#menu-button");
const panel = document.querySelector("#info-panel");
button.addEventListener("click", () => {
panel.classList.toggle("open");
button.setAttribute("aria-expanded", panel.classList.contains("open"));
});
该代码为按钮添加一个点击事件处理程序。点击处理程序在信息框面板上切换 open
类,这会导致面板滑入或滑出视图。事件处理程序还为按钮设置了 aria-expanded
属性以提高可访问性。
这就是它 - 创建切换信息面板效果的最简单方法。
总结
这样我们就结束了对定位的介绍 - 到现在,你应该对基本机制的工作原理以及如何将它们应用于构建一些有趣的 UI 功能有了了解。如果你没有立即理解所有内容,不要担心 - 定位是一个相当高级的主题,你可以随时再次阅读文章来帮助你理解。