时间线!使用 CSS 和 JavaScript 构建垂直时间线(更新)

在本教程中,我们将学习如何从头开始构建响应式垂直时间线的两个版本。

1. HTML 标记

我们将使用的标记非常简单;一个普通的无序列表,每个列表项内都有一个元素。当我们沿着时间轴处理事件时,我们将为每个列表项提供一个元素来显示年份。div,time

此外,我们将把整个事情包装在一个元素中,类为 :sectiont,imeline

<section class="intro">
  <div class="container">
    <h1>Vertical Timeline &darr;</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: -439pxdiv

每个列表项的宽度 + 所需间距 – 每个列表项的宽度 = 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;
}

以下可视化显示了我们时间线的初始状态。在这里,您可以看到时间轴元素,因为我给它们带来了一丝不透明感,只是为了说明它们最初的位置:

图片[1]-时间线!使用 CSS 和 JavaScript 构建垂直时间线(更新)-得设创意

这是时间线的最终状态:

图片[2]-时间线!使用 CSS 和 JavaScript 构建垂直时间线(更新)-得设创意

5. 自定义圆圈

默认情况下,每个时间轴元素的伪元素看起来像一个圆圈。但是,让我们提供一些自定义其初始外观的选择。::after

最重要的是,我们将使用该属性来创建一些复杂的形状。但令人高兴的是,我们不需要从头开始创建它们。我们将利用 Clippy,一个剪辑路径生成器。clip-path

  • 如果您想要一个星号而不是一个圆圈,请将 and 类添加到时间轴中,如下所示:timeline-clippy,timeline-star
<section class="timeline timeline-clippy timeline-star">
图片[3]-时间线!使用 CSS 和 JavaScript 构建垂直时间线(更新)-得设创意

如果您想要一个菱形而不是一个圆圈,请将 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">
图片[4]-时间线!使用 CSS 和 JavaScript 构建垂直时间线(更新)-得设创意

当然,您也可以将此动画与上述自定义形状组合在一起,如下所示:

<section class="timeline timeline-clippy timeline-star timeline-infinite">
图片[5]-时间线!使用 CSS 和 JavaScript 构建垂直时间线(更新)-得设创意

以下是所有关联的样式:

.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*/
  }
}
图片[6]-时间线!使用 CSS 和 JavaScript 构建垂直时间线(更新)-得设创意

然而,在小屏幕(≤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;
  }
}

在较小的屏幕上,时间线如下所示:

图片[7]-时间线!使用 CSS 和 JavaScript 构建垂直时间线(更新)-得设创意

注意:在小屏幕上,我们使用单位来指定时间轴元素的宽度。这种方法背后没有任何特殊原因。我们同样可以使用百分比或像素。vw

结论

在本教程中,我们创建了一个响应式垂直时间线。我们已经介绍了很多东西,所以让我们回顾一下:

  • 通过使用一个简单的无序列表和CSS伪元素,我们设法构建了时间线的主要结构。这种方法的一个缺点是,CSS伪元素不是100%可访问的,所以请记住这一点。
  • 我们利用从 Stack Overflow 上的一个热门线程中获取的代码片段来测试列表项是否在视图中。然后,我们编写了自己的CSS来动画化它们的子元素。或者,我们可以使用JavaScript库或编写自己的代码。

但我们并没有就此止步!作为奖励,我们构建了一个替代的完全响应式垂直时间线组件,您可以在不同的场景中使用。如果你喜欢它,别忘了表达你的❤!

我希望你喜欢这个教程,你将使用这些时间线中的任何一个作为构建有趣的东西的基础。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享