粘性定价表非常适合展示具有一长串类似功能的产品和服务。在本教程中,我们将创建一个带有粘性标题的定价表;在此过程中,我们将学习如何在一定量的滚动后固定和取消固定元素。
我们正在构建的定价表
对于这个动手练习,我们将设计一个定价页面,该页面将在定价表的列中包含不同的订阅计划。当我们向下滚动时,标题会变得粘滞以保持在视图中,然后将在稍后释放。带有粘性标题组合的定价表是一种流行的 UI 模式,您可能在monday. com等网站上看到过。
See the Pen How to Create a Stylish Pricing Table with a Sticky Header by Envato Tuts+ (@tutsplus) on CodePen.
请记住,我们的演示触发器在大于 779 像素的视口上的粘性功能。您可能需要查看全屏演示才能充分欣赏它!
什么时候应该使用定价表?
当产品、服务或变体的集合为消费者提供了太多选择时,定价表就会出现。如果消费者发现难以决定选择哪个选项,他们更有可能什么都不选择。信息过载=转换失败。
浪费时间做出选择会抵消任何实际上拥有选择的优势!
“研究 [..] 表明,一旦我们真正做出决定,过多的选择往往会导致我们变得更不满意,而不是更多。” —— 阿丽娜·图根德,纽约时报
定价表的作用是帮助用户直观地解释他们可用的选项,有时甚至可能鼓励他们专注于最吸引人的选择。
阅读 Val Geisler 的 如何设计可在 InVision 博客上转换的定价页面的更多信息。
wordpress 定价表插件
在深入学习本教程之前,您可能需要查看Envato Market 上可用于 WordPress 的一系列定价表插件。
话虽如此,现在让我们通过创建一个超级清晰的表格供他们选择来帮助我们的用户!
1. 从页面标记开始
我们将从三个部分开始:
<section>...</section>
<section>...</section>
<section>...</section>
第一和第三部分不会起重要作用;它们将包含虚拟内容和样式,以确保页面足够长以触发所需的滚动效果。
在第二部分中,我们将放置表格。我们将它包装在一个容器中,这将使它在小屏幕上响应:
<div class="container">
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>...</th>
<th>...</th>
<th>...</th>
<th>...</th>
</tr>
</thead>
<tbody>
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
<!-- more rows here -->
</tbody>
</table>
</div>
该表本身将包含四列,代表产品或服务的定价计划。在我们的案例中,我们将提供三种订阅计划:入门版、基本版和专业版。
表头
表格的粘性标题将清楚地标识这些计划。每个计划还将包括一个号召性用语按钮。
这是表头的标记:
<tr>
<th>
<div>
Select your plan
<div class="svg-wrapper">
<svg viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm1 17v-4h-8v-2h8v-4l6 5-6 5z"/></svg>
</div>
</div>
</th>
<th>
<div class="heading">...</div>
<div class="info">
<div class="amount">...</div>
<div class="billing-msg">...</div>
<button type="button">...</button>
</div>
</th>
<th>
<div class="heading">...</div>
<div class="info">
<div class="popular">...</div>
<div class="amount">...</div>
<div class="billing-msg">...</div>
<button type="button">...</button>
</div>
</th>
<th>
<div class="heading">...</div>
<div class="info">
<div class="amount">...</div>
<div class="billing-msg">...</div>
<button type="button">...</button>
</div>
</th>
</tr>
表行
每个表格行将描述所有计划中某个功能的可用性。如果计划包含此功能,则会出现一个 SVG 复选标记图标。否则,将出现一个灰色的十字图标。
这是所有计划都支持的功能的标记:
<tr>
<td>...</td>
<td>
<svg class="starter" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z"/></svg>
</td>
<td>
<svg class="essential" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z"/></svg>
</td>
<td>
<svg class="professional" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z"/></svg>
</td>
</tr>
这是仅在“专业”计划中可用的功能的标记:
<tr>
<td>...</td>
<td>
<svg class="not-included" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm4.151 17.943l-4.143-4.102-4.117 4.159-1.833-1.833 4.104-4.157-4.162-4.119 1.833-1.833 4.155 4.102 4.106-4.16 1.849 1.849-4.1 4.141 4.157 4.104-1.849 1.849z"/></svg> </td>
<td>
<svg class="not-included" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm4.151 17.943l-4.143-4.102-4.117 4.159-1.833-1.833 4.104-4.157-4.162-4.119 1.833-1.833 4.155 4.102 4.106-4.16 1.849 1.849-4.1 4.141 4.157 4.104-1.849 1.849z"/></svg> </td>
<td>
<svg class="professional" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z"/></svg>
</td>
</tr>
2. 定义一些基本样式
准备好标记后,我们将继续使用 css。我们的第一步是设置一些 CSS 变量和常见的重置样式。
对于每个计划,我们将定义其对应的变量。如果需要,这将使我们能够轻松更改其外观和感觉。
以下是重置样式:
:root {
--white: white;
--gray: #999;
--lightgray: whitesmoke;
--popular: #ffdd40;
--starter: #f73859;
--essential: #00AEEF;
--professional: #FF7F45;
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
button {
background: none;
border: none;
cursor: pointer;
}
table {
border-collapse: collapse;
}
body {
font: 18px/1.5 'Noto Sans', sans-serif;
background: var(--lightgray);
}
注意:为简单起见,我不会 在教程中介绍所有CSS 规则。这里有将近 290 行 CSS。我只会讨论最重要的。 确保通过单击演示项目的CSS选项卡来检查它们 。
3. 设计定价表
定价表将具有最大宽度并在页面内水平居中:
.container {
max-width: 850px;
padding: 0 10px;
margin: 0 auto;
}
table {
width: 100%;
}
这些行将表现为 flex 容器:
table tr { display: flex;}
所有单元格将具有相同的宽度:
table th,table td { width: 25%; min-width: 150px;}
为了分离计划并提供每个计划属于哪个单元格的清晰视图,我们将为目标元素添加浅灰色边框:
--lightgray: whitesmoke;
table th .info,
table td:not(:first-child) {
border-left: 1px solid var(--lightgray);
}
使定价表具有响应性
正如我们将在接下来的部分中看到的,粘性效果将在大于 779px 的视口上触发(您可以更改此值以适应)。在较小的视口上,我们将展示一个可以水平滚动的典型表格。
Bootstrap 也为响应式表格使用了类似的功能。还有其他(更好的?)处理响应式表的方法,但这种方法确实可以在这里完成工作。
4. 固定/取消固定表头
有了 html 和 CSS,我们现在将专注于使用一些 javascript 的滚动效果。这将使我们能够使我们的标题具有粘性。
变量
第一步,我们将获取所需元素的副本。我们将在变量中存储我们稍后将使用的两个类:
const body = document.body;
const firstSection = document.queryselector("section:nth-child(1)");
const lastSection = document.querySelector("section:nth-child(3)");
const table = document.querySelector("table");
const thead = document.querySelector("table thead");
const mq = window.matchMedia("(min-width: 780px)");
const stickyClass = "sticky-table";
const sticky2Class = "sticky2-table";
下一步是执行一些计算。具体来说,我们要计算以下内容:
表格宽度。
表格相对于视口的顶部位置。
的高度thead。这是将被固定/取消固定的元素。
这是执行此操作所需的 JavaScript:
let tableWidth = table.offsetWidth;
let tableOffsetTop = table.getBoundingClientRect().top;
let theadHeight = thead.offsetHeight;
请注意,我们将上述值存储在let变量中。我们是故意这样做的。当页面调整大小时,我们应该重新计算上面描述的东西,从而将这些新值重新分配给这些变量。
在滚动
每次我们向上或向下滚动时,scrollHandler都会执行该函数:
在该函数中,我们将执行以下操作,这些操作仅在窗口宽度至少为 780 像素时运行:
获取用户从视口顶部滚动的像素数。
获取最后一部分相对于视口的顶部位置。
检查用户是否滚动超过或等于表格的初始顶部位置。
如果发生这种情况,我们将thead' 的宽度设置为表格的初始宽度。
然后,我们检查步骤 2 的结果值是否大于thead' 的高度。
如果发生这种情况,我们thead通过将sticky-table类添加到同一元素并从同一元素中body删除该类来固定该元素。sticky-table2此时,thead 成为一个固定定位的元素。然后我们将它定位在视口的顶部。我们还给了 body一个等于thead' 高度的顶部填充。
如果这没有发生,我们thead通过将 sticky-table2 类添加到 同一元素并 从同一元素中body 删除 类来停止固定。sticky-table此时,thead 被释放并成为绝对定位的元素。然后我们将它放在表格的底部。
如果用户滚动的次数少于表格的初始顶部位置(thead 尚未固定),我们sticky-table会stick-table2从body. 此外,我们将其顶部填充设置为 0。此时,thead没有任何位置(静态元素),因此我们重置其默认 top位置。最后,我们将其宽度设置为 100%(我们可以跳过它)。
实现所有这些行为的代码如下:
window.addeventListener("scroll", scrollHandler);
function scrollHandler() {
if (mq.matches) {
// 1
const scrollY = window.pageYOffset;
// 2
const lastSectionOffsetTop = lastSection.getBoundingClientRect().top;
// 3
if (scrollY >= tableOffsetTop) {
// 4
thead.style.width = `${tableWidth}px`;
// 5
if (lastSectionOffsetTop > theadHeight) {
// 6
body.classList.remove(sticky2Class);
body.classList.add(stickyClass);
thead.style.top = 0;
body.style.paddingTop = `${theadHeight}px`;
} else {
// 7
body.classList.remove(stickyClass);
body.classList.add(sticky2Class);
thead.style.top = `calc(100% - ${theadHeight}px)`;
}
} else {
// 8
body.classList.remove(stickyClass, sticky2Class);
body.style.paddingTop = 0;
thead.style.width = "100%";
thead.style.top = "auto";
}
}
}
以及每个类的相关样式:
table thead {
transition: box-shadow 0.2s;
}
.sticky-table table thead {
position: fixed;
left: 50%;
transform: translateX(-50%);
}
.sticky-table table thead {
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.12);
}
.sticky2-table table thead {
position: absolute;
left: 0;
}
5. 调整页面大小
伙计们,我们几乎完成了这项工作!到目前为止,粘性页眉效果在页面加载时可以正常工作。但是当页面被调整大小时会发生什么?好吧,如果我们能让这个演示也适用于调整大小,那就太好了,对吧?我们开始做吧!
所以每次我们调整页面大小时,resizeHandler都会执行该函数。
在该函数中,我们将首先检查窗口宽度,然后更新上述let变量的值,或者重置thead和body内联样式。请注意,我们通过抓取第一部分的高度来检索表格的顶部位置。您可能想知道为什么我们不使用表的offsetTop属性?在我的测试中,我注意到它并不总是在调整大小时给出准确的结果。此外,该getBoundingClientRect()方法也不起作用,因为它也给出了不正确的(甚至是负的)值。
所需的 javaScript 代码:
window.addEventListener("resize", resizeHandler);
function resizeHandler() {
if (mq.matches) {
tableWidth = firstSection.offsetHeight;
tableOffsetTop = table.offsetTop;
theadHeight = thead.offsetHeight;
} else {
body.classList.remove(stickyClass, sticky2Class);
body.style.paddingTop = 0;
thead.style.width = "100%";
thead.style.top = "auto";
}
}
结论
就是这样,伙计们!在本教程中,我们设法构建了一个有用的滚动效果,而无需使用任何外部库。我们不仅学习了如何创建粘性元素,还学习了如何在一定量的滚动后取消固定(释放)它们。
所有这些结合起来为我们提供了一个非常有用的带有粘性标题的定价表。
See the Pen How to Create a Stylish Pricing Table with a Sticky Header by Envato Tuts+ (@tutsplus) on CodePen.
我希望这个练习能帮助你学到一些新东西,并启发你在即将到来的项目中使用它。
在结束之前,我想强调两点:
我使用 table 元素来构建这种效果。考虑到当今有更灵活和强大的布局解决方案(如 CSS Grid),这可能并不总是理想的方法。但是,表格通常是显示数据的最佳元素,所以这次我选择了它。
在移动设备上呈现表格数据始终是一个巨大的挑战。在这种情况下,我使用了一个简单的滚动解决方案。另一种方法可能是完全放弃 table 方法(仅将其保留在 >779px 上),用于具有三张幻灯片的轮播解决方案,其中每张幻灯片将代表一个定价计划。也许您有更好的想法,我们可以在下面的评论中讨论。
一如既往,非常感谢您的阅读!
- 表头
- 表行
- 使定价表具有响应性
- 变量
- 在滚动