css 垂直时间轴
在本教程中,我们将学习如何从头开始构建响应式垂直时间轴。 首先,我们将创建具有最少标记和CSS伪元素功能的基本结构。 然后,在向下滚动页面时,我们将使用一些JavaScript添加一些过渡效果。
让我们来了解一下我们将要构建的内容( 在CodePen上查看较大的版本 )。
1. HTML标记
我们将使用的标记非常简单; 一个普通的无序列表,每个列表项中都有一个div
元素。 当我们沿着时间线处理事件时,我们将为每个列表项提供一个time
元素以显示年份。
另外,我们将整个内容包装在带有timeline
类的section
元素中:
<section class="timeline">
<ul>
<li>
<div>
<time>1934</time>
Some content here
</div>
</li>
<!-- more list items here -->
</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;
}
我删除了列表项中的内容,以使此步骤更加清晰,并为我们提供以下内容:
3.时间轴元素样式
现在让我们设置div
元素的样式(从现在开始我们将它们称为“时间轴元素”),这些元素是列表项的一部分。 同样,我们为这些元素的::before
伪元素设置样式。
另外,稍后我们将看到,并非所有的div都具有相同的样式。 多亏了: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再次包含内容),我们的时间表如下所示:
“奇数”和“偶数” div之间的主要区别在于它们的位置。 第一个left:45px;
而left:-439px;
的第二个left:-439px;
。 要了解偶数div的位置,让我们做一些简单的数学运算:
每个div的宽度+所需的间距-每个列表项的宽度= 400px + 45px-6px = 439px
第二个不太重要的区别是它们的伪元素的生成箭头。 这意味着,每个“奇数” div的伪元素都有一个左箭头,而每个“偶数” div的伪元素却显示为右箭头。
4.增加互动性
现在时间轴的基本结构已经准备就绪,让我们找出新的要求:
- 默认情况下,时间线元素(divs)应该是隐藏的。
- 它们应在其父项(列表项)进入视口时出现。
第一项任务相对简单。 但是第二个要复杂一些。 我们需要检测目标元素(列表项)在当前视口中是否完全可见,然后,如果发生这种情况,我们将揭示其子级。 为了实现此功能,我们将不使用任何外部JavaScript库(例如WOW.js或ScrollReveal.js )或编写我们自己的复杂代码。 令人高兴的是,StackOverlow上有一个有关此问题的流行线程 。 因此,首先让我们利用建议的答案来测试元素在当前视口中是否可见。
这是我们将要使用的简化函数:
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
类添加到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,如果重新加载页面,我们应该看到类似于以下的结果:
隐藏和显示
现在让我们重新考虑我们的初始要求。 请记住,默认情况下,所有div都应隐藏。 为此,我们使用visibility
和opacity
CSS属性。 此外,我们使用translate3d()
将它们从其原始位置移开200px。 只要它们的父项处于可见状态,我们就会显示它们并删除预定义的偏移量。 这样,我们可以在效果中创建漂亮的幻灯片。
最后,当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.积极响应
我们快准备好了! 我们要做的最后一件事是使时间轴响应。
首先,在我们称为“中型屏幕”(> 600像素且≤900像素)的情况下,我们仅做一个小修改。 具体来说,我们减小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*/
}
}
在这种情况下,时间轴如下所示:
但是,在小屏幕(≤600像素)上,所有时间轴元素看起来都相同; “奇数”和“偶数” 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和JavaScript构建水平时间线 ,请尝试一下!
如有任何疑问,请在下面的评论中告诉我。
css 垂直时间轴