水平时间轴css代码_使用CSS和JavaScript构建水平时间线
水平时间轴css代码
在上一篇文章中 ,我向您展示了如何从头开始构建响应式垂直时间轴。 今天,我将介绍创建相关的水平时间线的过程。
与往常一样,要初步了解我们将要构建的内容,请查看相关的CodePen演示(请查看较大的版本以获得更好的体验):
我们有很多内容需要介绍,所以让我们开始吧!
1. HTML标记
标记与我们为垂直时间轴定义的标记相同,除了以下三点:
- 我们使用有序列表而不是无序列表,因为在语义上更正确。
- 还有一个额外的列表项(最后一个)为空。 在下一部分中,我们将讨论原因。
- 还有一个额外的元素(即
.arrows
)负责时间轴导航。
这是必需的标记:
<section class="timeline">
<ol>
<li>
<div>
<time>1934</time>
Some content here
</div>
</li>
<!-- more list items here -->
<li></li>
</ol>
<div class="arrows">
<button class="arrow arrow__prev disabled" disabled>
<img src="arrow_prev.svg" alt="prev timeline arrow">
</button>
<button class="arrow arrow__next">
<img src="arrow_next.svg" alt="next timeline arrow">
</button>
</div>
</section>
时间轴的初始状态如下所示:
2.添加初始CSS样式
为了简单起见,在这里省略了一些基本的字体样式,颜色样式等之后,我们指定了一些结构性CSS规则:
.timeline {
white-space: nowrap;
overflow-x: hidden;
}
.timeline ol {
font-size: 0;
width: 100vw;
padding: 250px 0;
transition: all 1s;
}
.timeline ol li {
position: relative;
display: inline-block;
list-style-type: none;
width: 160px;
height: 3px;
background: #fff;
}
.timeline ol li:last-child {
width: 280px;
}
.timeline ol li:not(:first-child) {
margin-left: 14px;
}
.timeline ol li:not(:last-child)::after {
content: '';
position: absolute;
top: 50%;
left: calc(100% + 1px);
bottom: 0;
width: 12px;
height: 12px;
transform: translateY(-50%);
border-radius: 50%;
background: #F45B69;
}
在这里最重要的是,您会注意到两件事:
- 我们为列表分配较大的顶部和底部填充。 再次,我们将在下一节中解释为什么会发生这种情况。
- 正如您将在以下演示中注意到的那样,由于列表的
width: 100vw
,其父级的overflow-x: hidden
,因此,此时我们无法看到所有列表项。 这有效地“掩盖”了列表项。 但是,由于有了时间轴导航,我们以后才能浏览所有项目。
有了这些规则,这就是时间轴的当前状态(没有任何实际内容,以使情况保持清楚):
3.时间轴元素样式
至此,我们将对div
元素(从现在开始将它们称为“时间轴元素”)进行样式设置,这些元素属于列表项以及它们的::before
伪元素。
另外,我们将使用:nth-child(odd)
和:nth-child(even)
CSS伪类来区分奇数和偶数div的样式。
以下是时间轴元素的常用样式:
.timeline ol li div {
position: absolute;
left: calc(100% + 7px);
width: 280px;
padding: 15px;
font-size: 1rem;
white-space: normal;
color: black;
background: white;
}
.timeline ol li div::before {
content: '';
position: absolute;
top: 100%;
left: 0;
width: 0;
height: 0;
border-style: solid;
}
然后是一些奇怪的样式:
.timeline ol li:nth-child(odd) div {
top: -16px;
transform: translateY(-100%);
}
.timeline ol li:nth-child(odd) div::before {
top: 100%;
border-width: 8px 8px 0 0;
border-color: white transparent transparent transparent;
}
最后是一些偶数样式:
.timeline ol li:nth-child(even) div {
top: calc(100% + 16px);
}
.timeline ol li:nth-child(even) div::before {
top: -8px;
border-width: 8px 0 0 8px;
border-color: transparent transparent transparent white;
}
这是时间轴的新状态,再次添加了内容:
您可能已经注意到,时间轴元素是绝对定位的。 这意味着它们已从常规文档流中删除。 考虑到这一点,为了确保显示整个时间轴,我们必须为列表设置较大的顶部和底部填充值。 如果我们不应用任何填充,时间线将被裁剪:
4.时间线导航样式
现在该设置导航按钮的样式了。 请记住,默认情况下,我们禁用上一个箭头,并为其赋予disabled
类。
以下是相关CSS样式:
.timeline .arrows {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.timeline .arrows .arrow__prev {
margin-right: 20px;
}
.timeline .disabled {
opacity: .5;
}
.timeline .arrows img {
width: 45px;
height: 45px;
}
上面的规则为我们提供了以下时间表:
5.增加互动性
时间轴的基本结构已准备就绪。 让我们添加一些交互性!
变数
首先,我们设置了一堆变量,稍后将使用它们。
const timeline = document.querySelector(".timeline ol"),
elH = document.querySelectorAll(".timeline li > div"),
arrows = document.querySelectorAll(".timeline .arrows .arrow"),
arrowPrev = document.querySelector(".timeline .arrows .arrow__prev"),
arrowNext = document.querySelector(".timeline .arrows .arrow__next"),
firstItem = document.querySelector(".timeline li:first-child"),
lastItem = document.querySelector(".timeline li:last-child"),
xScrolling = 280,
disabledClass = "disabled";
初始化事物
当所有页面资产准备就绪时,将调用init
函数。
window.addEventListener("load", init);
此功能触发四个子功能:
function init() {
setEqualHeights(elH);
animateTl(xScrolling, arrows, timeline);
setSwipeFn(timeline, arrowPrev, arrowNext);
setKeyboardFn(arrowPrev, arrowNext);
}
稍后我们将看到,这些功能中的每一个都完成特定的任务。
等高时间轴元素
如果您跳回到上一个演示 ,您会注意到时间轴元素的高度不相等。 这不会影响我们时间轴的主要功能,但是如果所有元素的高度都相同,您可能会更喜欢它。 为了实现这一点,我们可以通过CSS(简单的解决方案)为它们提供固定的高度,或者通过JavaScript为它们提供与最高元素的高度相对应的动态高度。
第二个选项更加灵活和稳定,因此这是一个实现此行为的函数:
function setEqualHeights(el) {
let counter = 0;
for (let i = 0; i < el.length; i++) {
const singleHeight = el[i].offsetHeight;
if (counter < singleHeight) {
counter = singleHeight;
}
}
for (let i = 0; i < el.length; i++) {
el[i].style.height = `${counter}px`;
}
}
此函数检索最高时间轴元素的高度,并将其设置为所有元素的默认高度。
演示的外观如下:
6.动画时间线
现在,让我们集中讨论时间轴动画。 我们将逐步构建实现此行为的功能。
首先,我们为时间线按钮注册一个click事件监听器:
function animateTl(scrolling, el, tl) {
for (let i = 0; i < el.length; i++) {
el[i].addEventListener("click", function() {
// code here
});
}
}
每次单击按钮时,我们都会检查时间轴按钮的禁用状态,如果未禁用它们,则将其禁用。 这样可以确保在动画结束之前,仅两次单击两个按钮。
因此,就代码而言,点击处理程序最初包含以下几行:
if (!arrowPrev.disabled) {
arrowPrev.disabled = true;
}
if (!arrowNext.disabled) {
arrowNext.disabled = true;
}
后续步骤如下:
- 我们检查这是否是我们第一次单击按钮。 同样,请记住,默认情况下上一个按钮是禁用的,因此最初可以单击的唯一按钮是下一个按钮。
- 如果确实是第一次,我们将使用
transform
属性将时间轴向右移动280px。xScrolling
变量的值确定移动量。 - 相反,如果我们已经单击了一个按钮,则将检索时间轴的当前
transform
值,并向该值添加或移除所需的移动量(即280px)。 因此,只要单击上一个按钮,transform
属性的值就会减小,并且时间线会从左移到右。 但是,单击下一个按钮时,transform
属性的值增加,并且时间线从右移到左。
实现此功能的代码如下:
let counter = 0;
for (let i = 0; i < el.length; i++) {
el[i].addEventListener("click", function() {
// other code here
const sign = (this.classList.contains("arrow__prev")) ? "" : "-";
if (counter === 0) {
tl.style.transform = `translateX(-${scrolling}px)`;
} else {
const tlStyle = getComputedStyle(tl);
// add more browser prefixes if needed here
const tlTransform = tlStyle.getPropertyValue("-webkit-transform") || tlStyle.getPropertyValue("transform");
const values = parseInt(tlTransform.split(",")[4]) + parseInt(`${sign}${scrolling}`);
tl.style.transform = `translateX(${values}px)`;
}
counter++;
});
}
很好! 我们刚刚定义了一种对时间轴进行动画处理的方法。 下一个挑战是弄清楚该动画何时应停止。 这是我们的方法:
- 当第一个时间轴元素完全可见时,这意味着我们已经到达了时间轴的开始,因此我们禁用了上一个按钮。 我们还确保启用了下一个按钮。
- 当最后一个元素完全可见时,这意味着我们已经到达时间线的末尾,因此我们禁用了下一个按钮。 因此,我们还要确保启用上一个按钮。
请记住,最后一个元素是一个空元素,其宽度等于时间轴元素的宽度(即280px)。 我们给它一个值(或更高的值)是因为我们要确保在禁用下一个按钮之前,最后一个时间轴元素将可见。
为了检测目标元素在当前视口中是否完全可见,我们将利用与垂直时间轴相同的代码。 来自此Stack Overflow线程的所需代码如下:
function isElementInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
除了上述功能之外,我们还定义了另一个帮助器:
function setBtnState(el, flag = true) {
if (flag) {
el.classList.add(disabledClass);
} else {
if (el.classList.contains(disabledClass)) {
el.classList.remove(disabledClass);
}
el.disabled = false;
}
}
此函数根据flag
参数的值在元素中添加或删除disabled
类。 另外,它可以更改此元素的禁用状态。
鉴于以上所述,下面是我们定义的用于检查动画是否应该停止的代码:
for (let i = 0; i < el.length; i++) {
el[i].addEventListener("click", function() {
// other code here
// code for stopping the animation
setTimeout(() => {
isElementInViewport(firstItem) ? setBtnState(arrowPrev) : setBtnState(arrowPrev, false);
isElementInViewport(lastItem) ? setBtnState(arrowNext) : setBtnState(arrowNext, false);
}, 1100);
// other code here
});
}
请注意,执行此代码之前有1.1秒的延迟。 为什么会这样?
如果回到CSS,我们将看到以下规则:
.timeline ol {
transition: all 1s;
}
因此,时间轴动画需要1秒才能完成。 只要完成,我们将等待100毫秒,然后执行检查。
这是动画的时间表:
7.添加滑动支持
到目前为止,时间轴尚未响应触摸事件。 如果可以添加此功能,那就太好了。 为此,我们可以编写自己JavaScript实现或使用其中存在的相关库之一(例如Hammer.js , TouchSwipe.js )。
对于我们的演示,我们将使其保持简单并使用Hammer.js,因此,首先,在笔中包含该库:
然后,我们声明关联的函数:
function setSwipeFn(tl, prev, next) {
const hammer = new Hammer(tl);
hammer.on("swipeleft", () => next.click());
hammer.on("swiperight", () => prev.click());
}
在上面的函数中,我们执行以下操作:
- 创建Hammer的实例。
- 为
swipeleft
和swiperight
事件注册处理程序。 - 当我们向左滑动时间线时,我们触发了对下一个按钮的点击,因此时间线从右到左具有动画效果。
- 当我们沿向右方向滑动时间轴时,触发对上一个按钮的单击,因此时间轴从左到右具有动画效果。
支持滑动的时间轴:
添加键盘导航
通过提供对键盘导航的支持,让我们进一步增强用户体验。 我们的目标:
- 当按下向左或向右箭头键时 ,文档应滚动到时间线的顶部(如果当前可以看到另一个页面部分)。 这样可以确保整个时间轴都可见。
- 具体来说,当按左箭头键时 ,时间线应从左到右设置动画。
- 同样,当按向右箭头键时 ,时间线应从右到左设置动画。
关联的功能如下:
function setKeyboardFn(prev, next) {
document.addEventListener("keydown", (e) => {
if ((e.which === 37) || (e.which === 39)) {
const timelineOfTop = timeline.offsetTop;
const y = window.pageYOffset;
if (timelineOfTop !== y) {
window.scrollTo(0, timelineOfTop);
}
if (e.which === 37) {
prev.click();
} else if (e.which === 39) {
next.click();
}
}
});
}
具有键盘支持的时间轴:
8.积极响应
我们快完成了! 最后但并非最不重要的一点是,让我们对时间轴做出响应。 当视口小于600像素时,它应具有以下堆叠布局:
当我们使用桌面优先方法时,以下是我们必须覆盖CSS规则:
@media screen and (max-width: 599px) {
.timeline ol,
.timeline ol li {
width: auto;
}
.timeline ol {
padding: 0;
transform: none !important;
}
.timeline ol li {
display: block;
height: auto;
background: transparent;
}
.timeline ol li:first-child {
margin-top: 25px;
}
.timeline ol li:not(:first-child) {
margin-left: auto;
}
.timeline ol li div {
width: 94%;
height: auto !important;
margin: 0 auto 25px;
}
.timeline ol li:nth-child div {
position: static;
}
.timeline ol li:nth-child(odd) div {
transform: none;
}
.timeline ol li:nth-child(odd) div::before,
.timeline ol li:nth-child(even) div::before {
left: 50%;
top: 100%;
transform: translateX(-50%);
border: none;
border-left: 1px solid white;
height: 25px;
}
.timeline ol li:last-child,
.timeline ol li:nth-last-child(2) div::before,
.timeline ol li:not(:last-child)::after,
.timeline .arrows {
display: none;
}
}
注意 :对于以上两个规则,我们必须使用!important
规则来覆盖通过JavaScript应用的相关内联样式。
我们时间表的最终状态:
浏览器支持
该演示可以在所有最新的浏览器和设备上正常运行。 另外,您可能已经注意到,我们使用Babel将我们的ES6代码编译为ES5。
我在测试时遇到的唯一小问题是在对时间轴进行动画处理时发生的文本呈现更改。 尽管我尝试了在不同的Stack Overflow线程中提出的各种方法,但并未找到适用于所有操作系统和浏览器的直接解决方案。 因此,请记住,在对时间轴进行动画处理时,可能会遇到小的字体渲染问题。
结论
在这个相当重要的教程中,我们从一个简单的有序列表开始,并创建了一个响应式水平时间线。 毫无疑问,我们涵盖了很多有趣的事情,但是我希望您喜欢为最终结果而努力,并且它可以帮助您获得一些新知识。
如果您有任何疑问或有任何您不了解的内容,请在下面的评论中告诉我!
如果您想进一步改善或延长此时间表,可以执行以下操作:
翻译自: https://webdesign.tutsplus.com/tutorials/building-a-horizontal-timeline-with-css-and-javascript--cms-28378
水平时间轴css代码
水平时间轴css代码_使用CSS和JavaScript构建水平时间线相关推荐
- html水平进度轴代码,水平时间轴 html + css
比较粗糙,效果如图 这个是写微信页面时写的,pc 也是一样的效果 代码如下: 预约 行家确认 付款 见面 评价 付款剩余时间:: css: .time_line_box{ position: rela ...
- html css 水平时间轴,纯css+js水平时间轴
自定义,并自动加载时间节点 当前时间节点居中,突出显示 时间动态无痕添加 效果图: 初始状态 时间左走到一定2016.1月后 html: + - 对应 JS 设置处理: var left = docu ...
- 简洁纯CSS3横向水平时间轴js特效代码
下载地址 这是一款基于Bootstrap网格系统的响应式横向水平时间轴特效.该水平时间轴特效采用bootstrap网格进行布局,然后通过css代码来进行美化,效果简洁时尚.核心CSS3代码.main- ...
- vue图片时间轴滑动_Vue实现可移动水平时间轴
本文实例为大家分享了Vue实现可移动水平时间轴的具体代码,供大家参考,具体内容如下 里程碑时间轴具体实现 效果图 编辑里程碑效果图 编辑里程碑 里程碑状态: 开始 超期 关闭 {{'阶段名称:'+it ...
- android 炫酷时间轴,这38款超级炫酷的时间轴特效代码案例,总有一款是你需要的...
最近,看到一些很漂亮的时间轴图表,效果真的非常不错.这些图表,写到需要的项目中,也是非常棒的.当然,你也可以拿它来当作学习的小练习.时间轴,在很多企业官网或者关于企业历史大事件介绍的时候,使用的频率还 ...
- 带时间轴 歌词 示例_带有示例JavaScript externalHTML
带时间轴 歌词 示例 In this tutorial, I will tell you about outerHTML in javascript. outerHTML provides devel ...
- css网格_使用CSS网格构建的澳大利亚初创企业的周期表
css网格 by Shooting Unicorns 通过射击独角兽 使用CSS网格构建的澳大利亚初创企业的周期表 (The Periodic Table of Australian Startups ...
- 时间轴ui设计_我应该在UI设计上花更多时间吗?
时间轴ui设计 Let's start with an example of communication skills: they are important for any profession, ...
- css网格_一个CSS网格可以全部统治
css网格 The case for using one CSS grid for your entire website 在整个网站上使用一个CSS网格的情况 CSS网格与Flexbox (CSS ...
最新文章
- SIP协议的传输层原理报文解析(解读rfc3581)(待排版)
- cruzer php sandisk 闪迪u盘量产工具_SanDisk Cruzer Micro下载
- [Leetcode]50. Pow(x, n)
- C语言:L1-036 A乘以B (5分)
- SharePoint 2013 本地开发解决方案以及程调试
- D - 卿学姐与魔法
- word2vec python 代码实现_python gensim使用word2vec词向量处理中文语料的方法
- 如果我是推荐算法面试官,我会问哪些问题?
- pythonqt项目_Qt项目之高亮关键字Python编辑器实现
- 有的字体,用黑色渲染,效果是灰色
- dedecms flag标签属性
- 逆流而上的你,送给现在的你
- 【初探篇】Nginx 虚拟主机与域名解析
- 什么是Google AMP
- html中加水印,静态html页面 添加水印效果 且 水印不可复制
- socket系列之什么是socket
- 《软件方法》第8章 分析 之 分析类图(3)
- MongoError: Cannot use a session that has ended ---- NodeJs报错
- UDP-RTP协议解析
- 奥鹏英语计算机统考时间2019,关于2019年9月统考工作安排的通知
热门文章
- 2022-2027年中国维生素A行业市场调研及未来发展趋势预测报告
- 注册电气工程师新旧专业对比
- 神级插件Bito介绍及使用
- mysql execute immediate_PostgreSQL中function中实现类似Oracle的execute immediate的功能
- java 利用printf格式化输出
- MATLAB美图软件算法研究,【网络多媒体学】matlab实现美图秀秀基本功能.ppt
- 文件直接下载( 解决图片,视频点击下载的时候在浏览器默认是打开)
- 1092 最好吃的月饼 (20 分)
- 2月券商App行情刷新及交易体验报告,东方与安信升至领导者象限
- 湖南大学_数电实验_模型机设计_CPU设计_verilog_课程实验报告