在本教程中,我们将学习如何从头开始构建响应式垂直时间线的两个版本。
1. HTML 标记
我们将使用的标记非常简单;一个普通的无序列表,每个列表项内都有一个元素。当我们沿着时间轴处理事件时,我们将为每个列表项提供一个元素来显示年份。div,
time
此外,我们将把整个事情包装在一个元素中,类为 :section
t,imeline
<section class="intro">
<div class="container">
<h1>Vertical Timeline ↓</h1>
</div>
</section>
<section class="timeline">
<ul>
<li>
<div>
<time>1934</time> At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium
</div>
</li>
<li>
<div>
<time>1937</time> Proin quam velit, efficitur vel neque vitae, rhoncus commodo mi. Suspendisse finibus mauris et bibendum molestie. Aenean ex augue, varius et pulvinar in, pretium non nisi.
</div>
</li>
<li>
<div>
<time>1940</time> Proin iaculis, nibh eget efficitur varius, libero tellus porta dolor, at pulvinar tortor ex eget ligula. Integer eu dapibus arcu, sit amet sollicitudin eros.
</div>
</li>
<li>
<div>
<time>1943</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>1946</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>1956</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>1957</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>1967</time> Aenean condimentum odio a bibendum rhoncus. Ut mauris felis, volutpat eget porta faucibus, euismod quis ante.
</div>
</li>
<li>
<div>
<time>1977</time> Vestibulum porttitor lorem sed pharetra dignissim. Nulla maximus, dui a tristique iaculis, quam dolor convallis enim, non dignissim ligula ipsum a turpis.
</div>
</li>
<li>
<div>
<time>1985</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>2000</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
<li>
<div>
<time>2005</time> In mattis elit vitae odio posuere, nec maximus massa varius. Suspendisse varius volutpat mattis. Vestibulum id magna est.
</div>
</li>
</ul>
</section>
2. 添加初始 CSS 样式
在一些基本颜色等之后(在下面的笔中查看 CSS 的上半部分),我们将为列表项定义一些结构化 CSS 规则。我们还将设置这些项的伪元素样式:::after
.timeline ul li {
list-style-type: none;
position: relative;
width: 6px;
margin: 0 auto;
padding-top: 50px;
background: #fff;
}
.timeline ul li::after {
content: '';
position: absolute;
left: 50%;
bottom: 0;
transform: translateX(-50%);
width: 30px;
height: 30px;
border-radius: 50%;
background: inherit;
z-index: 1;
}
3. 时间轴元素样式
现在,让我们设置元素的样式(从现在开始,我们将它们称为“时间轴元素”),这些元素是列表项的一部分。同样,我们设置了这些元素的伪元素的样式。div,
::before
此外,正如我们稍后将看到的那样,并非所有 s 都具有相同的风格。多亏了 和 CSS 伪类,我们才能区分它们的样式。div,
:nth-child(odd),
:nth-child(even)
请看下面对应的CSS规则:
.timeline ul li div {
position: relative;
bottom: 0;
width: 400px;
padding: 15px;
background: #F45B69;
}
.timeline ul li div::before {
content: '';
position: absolute;
bottom: 7px;
width: 0;
height: 0;
border-style: solid;
}
然后是我们奇数元素的一些样式:
.timeline ul li:nth-child(odd) div {
left: 45px;
}
.timeline ul li:nth-child(odd) div::before {
left: -15px;
border-width: 8px 16px 8px 0;
border-color: transparent #F45B69 transparent transparent;
}
最后是偶数元素的样式:
.timeline ul li:nth-child(even) div {
left: -439px;
}
.timeline ul li:nth-child(even) div::before {
right: -15px;
border-width: 8px 0 8px 16px;
border-color: transparent transparent transparent #F45B69;
}
“奇数”和“偶数”之间的主要区别在于它们的位置。第一个有,而第二个有.为了理解偶数 s 的位置,让我们做一些简单的数学运算:div,
left: 45px,
left: -439px
div
每个列表项的宽度 + 所需间距 – 每个列表项的宽度 = 400px + 45px – 6px = 439px,div
第二个不太重要的区别是它们的伪元素生成的箭头。这意味着每个“奇数”s 的伪元素都有一个左箭头,而每个“偶数”的伪元素显示为右箭头。div,
div
4. 添加交互性
现在时间线的基本结构已经准备好了,让我们弄清楚新的要求:
- 默认情况下,时间轴元素应处于隐藏状态。
div
- 当它们的父项(列表项)进入视口时,它们应该会出现。
第一项任务相对简单。不过,第二个有点复杂。我们需要检测目标元素(列表项)在当前视口中是否完全可见,如果发生这种情况,我们将显示其子元素。为了实现这个功能,我们不会使用任何外部JavaScript库(例如WOW.js或ScrollReveal.js)或编写我们自己的复杂代码。令人高兴的是,Stack Overflow 上有一个关于这个问题的热门话题。因此,首先让我们利用建议的答案来测试元素在当前视口中是否可见。
以下是我们将使用的简化函数:
function isElementInViewport(el) {
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
在视图中添加类
接下来,我们将该类添加到当前视口中可见的列表项中。in-view
注意:在以下情况下,我们必须测试它们是否可见:
- 页面加载时
- 当我们向下滚动时
如果需要,我们可以进行一些额外的测试(例如,当浏览器窗口的大小发生变化时)。
在我们的示例中,下面是我们使用的代码:
var items = document.querySelectorAll(".timeline li");
// code for the isElementInViewport function
function callbackFunc() {
for (var i = 0; i < items.length; i++) {
if (isElementInViewport(items[i])) {
items[i].classList.add("in-view");
}
}
}
window.addEventListener("load", callbackFunc);
window.addEventListener("scroll", callbackFunc);
现在我们已经添加了 JavaScript,如果我们重新加载页面,我们应该会看到类似于以下结果的结果:
隐藏和显示
现在让我们重新审视一下我们的初始要求。请记住,默认情况下,所有 s 都应隐藏。为了实现这一点,我们使用 和 CSS 属性。此外,我们使用该函数将它们从原始位置移动 200px。只要它们的父项在视图中,我们就会显示它们并删除预定义的偏移量。通过这种方式,我们创造了很好的滑入效果。div,
visibility,
opacity,
translate3d()
最后,当 a 在视口内时,我们要做的另一件小事是更改其伪元素的背景颜色。li
::after
以下样式可以解决所有这些问题:
.timeline ul li::after {
background: #fff;
transition: background .5s ease-in-out;
}
.timeline ul li.in-view::after {
background: #F45B69;
}
.timeline ul li div {
visibility: hidden;
opacity: 0;
transition: all .5s ease-in-out;
}
.timeline ul li:nth-child(odd) div {
transform: translate3d(200px,0,0);
}
.timeline ul li:nth-child(even) div {
transform: translate3d(-200px,0,0);
}
.timeline ul li.in-view div {
transform: none;
visibility: visible;
opacity: 1;
}
以下可视化显示了我们时间线的初始状态。在这里,您可以看到时间轴元素,因为我给它们带来了一丝不透明感,只是为了说明它们最初的位置:
这是时间线的最终状态:
5. 自定义圆圈
默认情况下,每个时间轴元素的伪元素看起来像一个圆圈。但是,让我们提供一些自定义其初始外观的选择。::after
最重要的是,我们将使用该属性来创建一些复杂的形状。但令人高兴的是,我们不需要从头开始创建它们。我们将利用 Clippy,一个剪辑路径生成器。clip-path
- 如果您想要一个星号而不是一个圆圈,请将 and 类添加到时间轴中,如下所示:
timeline-clippy,
timeline-star
<section class="timeline timeline-clippy timeline-star">
如果您想要一个菱形而不是一个圆圈,请将 and 类添加到时间轴中,如下所示:timeline-clippy,timeline-rhombus
<section class="timeline timeline-clippy timeline-rhombus">
如果您想要一个七边形而不是一个圆,请将 和 类添加到时间轴中,如下所示:timeline-clippy,timeline-heptagon
<section class="timeline timeline-clippy timeline-heptagon">
Clippy 可让您创建更多形状,因此如果您想要不同的东西,请务必查看其网站。
如果你仍然想保留圆圈,也可以使用这样的类来为它们提供一些无限比例的动画:timeline-infinite
<section class="timeline timeline-infinite">
当然,您也可以将此动画与上述自定义形状组合在一起,如下所示:
<section class="timeline timeline-clippy timeline-star timeline-infinite">
以下是所有关联的样式:
.timeline-clippy ul li::after {
width: 40px;
height: 40px;
border-radius: 0;
}
.timeline-rhombus ul li::after {
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}
.timeline-rhombus ul li div::before {
bottom: 12px;
}
.timeline-star ul li::after {
clip-path: polygon(
50% 0%,
61% 35%,
98% 35%,
68% 57%,
79% 91%,
50% 70%,
21% 91%,
32% 57%,
2% 35%,
39% 35%
);
}
.timeline-heptagon ul li::after {
clip-path: polygon(
50% 0%,
90% 20%,
100% 60%,
75% 100%,
25% 100%,
0% 60%,
10% 20%
);
}
.timeline-infinite ul li::after {
animation: scaleAnimation 2s infinite;
}
@keyframes scaleAnimation {
0% {
transform: translateX(-50%) scale(1)
}
50% {
transform: translateX(-50%) scale(1.25);
}
100% {
transform: translateX(-50%) scale(1);
}
}
6. 响应迅速
我们差不多准备好了!我们要做的最后一件事就是让我们的时间线具有响应性。
首先,在我们所说的“中等屏幕”(>600px 和 ≤900px)上,我们只做了一个小的修改。具体来说,我们减小了 s 的宽度。div
以下是我们必须更改的规则:
@media screen and (max-width: 900px) {
.timeline ul li div {
width: 250px;
}
.timeline ul li:nth-child(even) div {
left: -289px; /*250+45-6*/
}
}
然而,在小屏幕(≤600px)上,所有时间线元素看起来都一样;“奇数”和“偶数”之间没有区别。同样,我们必须覆盖一些 CSS 规则:div
@media screen and (max-width: 600px) {
.timeline ul li {
margin-left: 20px;
}
.timeline ul li div {
width: calc(100vw - 91px);
}
.timeline ul li:nth-child(even) div {
left: 45px;
}
.timeline ul li:nth-child(even) div::before {
left: -15px;
border-width: 8px 16px 8px 0;
border-color: transparent #F45B69 transparent transparent;
}
}
在较小的屏幕上,时间线如下所示:
注意:在小屏幕上,我们使用单位来指定时间轴元素的宽度。这种方法背后没有任何特殊原因。我们同样可以使用百分比或像素。vw
结论
在本教程中,我们创建了一个响应式垂直时间线。我们已经介绍了很多东西,所以让我们回顾一下:
- 通过使用一个简单的无序列表和CSS伪元素,我们设法构建了时间线的主要结构。这种方法的一个缺点是,CSS伪元素不是100%可访问的,所以请记住这一点。
- 我们利用从 Stack Overflow 上的一个热门线程中获取的代码片段来测试列表项是否在视图中。然后,我们编写了自己的CSS来动画化它们的子元素。或者,我们可以使用JavaScript库或编写自己的代码。
但我们并没有就此止步!作为奖励,我们构建了一个替代的完全响应式垂直时间线组件,您可以在不同的场景中使用。如果你喜欢它,别忘了表达你的❤!
我希望你喜欢这个教程,你将使用这些时间线中的任何一个作为构建有趣的东西的基础。