在本教程中,咱们将学习如何从头开始构建响应式垂直时间线。
首先,咱们将使用最少的标记和 css 伪元素的强大功能创建基本结构。然后,当咱们向下滚动页面时,咱们将使用一些 javascript 添加一些过渡效果。
让咱们了解一下咱们将要构建什么(查看CodePen 上的更大版本)。
See the Pen Building a Vertical Timeline With CSS and a Touch of JavaScript by Envato Tuts+ (@tutsplus) on CodePen.
1. html 标记
咱们将使用的标记非常简单;一个普通的无序列表,div在咱们的每个列表项中都有一个元素。当咱们沿着时间线处理事件时,咱们将为每个列表项提供一个time元素来显示年份。
此外,咱们将把整个东西包装在一个section 元素中,其类为timeline:
<section class="timeline">
<ul>
<li>
<div>
<time>1934</time>
Some content here
</div>
</li>
<!-- more list items here -->
</ul>
</section>
这为咱们提供了以下无样式输出:
See the Pen Vertical Timeline Step 1 by Envato Tuts+ (@tutsplus) on CodePen.
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;
}
我已删除列表项中的内容以使此步骤更清晰,为咱们提供以下内容:
See the Pen Vertical Timeline Step 2 by Envato Tuts+ (@tutsplus) on CodePen.
3. 时间线元素样式
div现在让咱们为列表项中的元素(从现在起咱们将它们称为“时间线元素”)设置样式。::before同样,咱们对这些元素的伪元素进行 样式设置。
此外,正如咱们稍后将看到的,并非所有divs 都具有相同的样式。感谢 :nth-child(odd)和 :nth-child(even) CSS 伪类,咱们能够区分它们的样式。
看看下面对应的 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;
}
有了这些规则(并且咱们的 HTML 再次包含内容),咱们的时间线如下所示:
See the Pen Vertical Timeline Step 3 by Envato Tuts+ (@tutsplus) on CodePen.
“奇数”和“偶数”之间的主要区别在于div它们的位置。第一个有left: 45px,而第二个left: -439px。为了理解咱们 evendiv的定位,让咱们做一些简单的数学运算:
每个的宽度div+ 所需间距 - 每个列表项的宽度 = 400px + 45px - 6px = 439px
第二个不太重要的区别是它们的伪元素生成的箭头。这意味着,每个“奇数”div的伪元素都有一个左箭头,而每个“偶数”的伪元素div显示为一个右箭头。
4.增加交互性
现在时间线的基本结构已经准备好了,咱们来弄清楚新的需求:
默认情况下,时间线元素 ( divs) 应该是隐藏的。
它们应该在其父项(列表项)进入视口时出现。
第一项任务相对简单。但是,第二个要复杂一些。咱们需要检测目标元素(列表项)是否在当前视口中完全可见,如果发生这种情况,咱们会显示它们的子元素。为了实现这个功能,咱们不会使用任何外部 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,如果咱们重新加载页面,咱们应该会看到类似这样的结果:
隐藏和揭示
现在让咱们重新审视咱们最初的需求。请记住,默认情况下,所有divs 都应该被隐藏。为此,咱们使用visibility和opacityCSS 属性。此外,咱们使用该translate3d()函数将它们从原始位置移动 200 像素。只要它们的父级在视图中,咱们就会显示它们并删除预定义的偏移量。通过这种方式,咱们创建了漂亮的滑入效果。
最后,当 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每个时间线元素的伪元素看起来像一个圆圈。但是,让咱们为自定义其初始外观提供一些选择。
最重要的是,咱们将使用该clip-path属性来创建一些复杂的形状。但令人高兴的是,咱们不需要从头开始创建它们。咱们将利用Clippy,一个剪辑路径生成器。
如果您想要星形而不是圆形,请将timeline-clippy和timeline-star类添加到时间轴,如下所示:
<section class="timeline timeline-clippy timeline-star"> |
如果您想要菱形而不是圆形,请将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)上,咱们只做了一个小的修改。具体来说,咱们减小了divs 的宽度。
以下是咱们必须更改的规则:
@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),所有时间线元素看起来都一样;“奇数”和“偶数”之间没有区别div。同样,咱们必须覆盖一些 CSS 规则:
@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单位来指定时间线元素的宽度。这种方法背后没有任何特殊原因。咱们同样可以使用百分比或像素。
浏览器支持
该演示在最新的浏览器和设备中运行良好。然而,在 ios 设备上,时间线元素始终可见,而不是在其父元素进入视口时出现。
从我的测试中,我发现在这些设备上window.innerHeight 和document.documentElement.clientHeight 属性不会返回实际的视口高度。具体来说,它们返回的数字要大得多。由于这种不一致,所有列表项都会在页面加载时收到in-view该类。
虽然这不是什么大问题(您可能只希望在大屏幕上播放动画),但如果您对此问题了解更多或以前见过,请不要忘记通过社交媒体留下详细信息。
结论
在本教程中,咱们创建了一个响应式垂直时间线。咱们已经介绍了很多东西,所以让咱们回顾一下:
通过使用简单的无序列表和 CSS 伪元素,咱们设法构建了时间线的主要结构。不过,这种方法的一个缺点是,正如我在另一篇文章中已经提到的,CSS 伪元素不是 100% 可访问的,因此请记住这一点。
咱们利用从 Stack Overflow 上一个流行线程中提取的代码片段来测试列表项是否在视图中。然后,咱们编写了自己的 CSS 来为它们的子元素设置动画。或者,咱们可以使用 JavaScript 库或编写自己的代码。
我希望您喜欢本教程,并且您将使用此时间线作为构建有趣内容的基础。
- 在视图中添加类
- 隐藏和揭示