我报名了Goldstone Project Phase 1 Challenge——瓜分100,000奖池,这是我的第7篇文章, 点击查看活动详情
时间线效果介绍
在前端开发中,我们会遇到一些特别适合用时间轴显示的场景。例如,根据日期和时间记录以下事件:
![]()
您还可以制作以下更流行的左右对称卡片样式时间线:
![]()
如果加一点装饰,还可以有更显高的效果:
![]()
时间线效果精华
从上图我们可以看出时间线效果的本质不外乎以下两点:
- 使用从上到下的分隔线将可视区域分为左右两部分
- 分割线中间有一些点代表时间节点,左右显示相关信息
只要掌握如何画分割线,在分割线上画出小圆点,其实可以做出各种时间线效果。今天就带领大家实现下面这个可滚动的时间线,在项目中非常实用。学会了以后,你再也不怕对产品有类似的视觉要求了。
![]()
从头开始编写时间线
初始状态
为了教学方便,我们先定义如下空白模板:
![]()
HTML结构如下:
<身体>
<div类=“容器”>
< div 类 = "调试区域" >
< button onclick = "add()" >添加活动 </ button >
</ div >
< div class = "时间线区域" >
< div 类 = "时间线包装器" >
< div 类 = “时间线” >
</ div >
</ div >
</ div >
</ div >
</ body >
复制代码
最初的 CSS 样式是:
。容器 {
保证金:汽车;
宽度:350 像素;
高度:350px;
溢出:隐藏;
显示:弯曲;
弹性方向:列;
填充:0;
--左:62px;
--颜色:#0d5dff;
}
.调试区域{
边距:30px 0;
}
.timeline-area {
弹性:1;
位置:相对;
显示:弯曲;
弹性方向:列;
溢出-y:自动;
底部填充:10px;
padding-right: 5px;
边框:1px 实心#ccc;
}
复制代码
布局结构没什么好说的。是一个固定宽高的div,通过flex布局分为上下两部分。上方区域放置了一个按钮用于调试,下方区域是用于显示时间线内容的div,并添加了边框方便大家查看。
您可能注意到上面定义了两个变量 - 剩下 和 - 颜色 ,这是干什么用的?接下来你就知道了,请继续阅读。
添加分隔线
分隔线很关键,应该如何实现?先不急着写CSS代码,先看一下HTML结构:
< div 类 = "时间线包装器" >
< div 类 = “时间线” >
</ div >
</ div >
复制代码
timeline-wrapper 是一个包装容器,它的宽度和高度是固定的,时间线就是真正的时间线。当时间轴的内容超过容器的高度时,可以自由上下滚动。所以添加以下 CSS 代码:
.timeline-wrapper {
弹性:1;
溢出-y:自动;
填充:15px 5px 0 0;
}
。时间线 {
位置:相对;
}
复制代码
最关键的地方就是这里,使用伪元素 前 实现分频器:
.timeline ::之前{
内容: ””;
位置:绝对;
左:var(--左);
宽度:1px;
顶部:20px;
底部:0;
背景图像:线性渐变(
到底部,
RGBA(144, 156, 173, 0.6) 60%,
RGBA(255, 255, 255, 0) 0%
);
背景位置:左;
背景尺寸:1px 5px;
背景重复:重复-y;
}
复制代码
设置一个绝对定位,然后从左边开始的宽度就是上面的CSS变量 - 剩下 定义距离,将其宽度设置为 1px,然后我们将样式添加到时间轴:
。时间线 {
高度:500px;
宽度:100%;
}
复制代码
可以看到,中间的分界线已经出来了:
![]()
可能很多人不知道怎么脱线?实现虚线的效果有两种。第一个使用边框来设置 dotted 或 dashed 属性:
左边框:1px 虚线 rgba(144、156、173、0.6);
复制代码
另一种是使用 background-image 来模拟:
背景图像:线性渐变(
到底部,
RGBA(144, 156, 173, 0.6) 60%,
RGBA(255, 255, 255, 0) 0%
);
背景位置:左;
背景尺寸:1px 5px;
背景重复:重复-y;
复制代码
后者的确定性更强,控制虚线的间距非常方便。
添加点
线出来后,怎么加一个小点?这时候就需要补充HTML结构了。我们必须在时间线分隔线的两侧布置内容。为了方便用 JS 动态插入内容,我们使用模板来定义时间线中每一项的 HTML 结构:
<模板>
< div class = "时间线项目" >
< div class = "时间线-左" ></ div >
< div 类 = “时间线点” ></ div >
< div class = "时间线-右" ></ div >
</ div >
</ template >
复制代码
然后在head中添加add函数:
<脚本>
常量节点 = [] 函数添加 () { 常量 tpl = 文档。 querySelector ('template') const item = tpl.内容 。儿童 [0] 常量时间线 = 文档。 querySelector ('.timeline') 节点。 forEach (it => it.classList.remove ('current')) const node = item. cloneNode ( true ) 节点。类列表。添加(“当前”)节点。推送(节点)时间线。 appendChild(节点)节点。 scrollIntoView ({ 行为 : 'smooth' , block : 'nearest' , inline : 'center' }) }</ script >
复制代码
这时候,每当我们点击上面的添加活动按钮,就可以动态的复制插入上面的DOM了!
可以看出,时间线-项目内容区域分为时间线-左、时间线-点和时间线-右。顾名思义,它们是时间线内容的左、点和右。我们先写点的样式:
.timeline-dot {
左:var(--左);
宽度:7px;
高度:7px;
位置:绝对;
边界半径:50%;
盒子阴影:0 0 0 1px #d8d8d8;
背景:白色;
文本对齐:居中;
顶部:0;
行高:40px;
左边距:- 3.5px;
}
复制代码
然后为当前活动的点添加高亮样式:
.timeline-item .current .timeline-dot {
宽度:10px;
高度:10px;
背景颜色:var(--color);
盒子阴影:0 0 4px var(--color);
边框:1px 纯白色;
左边距: - 5px;
}
复制代码
此时 - 颜色 变量的作用很明确:用来控制主题颜色。我们反复点击添加活动按钮,可以看到小圆点的效果出来了!
![]()
设置左右容器
其实到这里,时间线的原型就已经完成了,剩下的就是根据业务来定义左右两边的内容了。对于left区域,我们需要定义一个宽度小于left的值,否则会超过分割线:
.timeline-left {
显示:块;
宽度:计算(var(--left)- 7px);
位置:绝对;
边距顶部: - 5px;
文本对齐:右;
颜色:#8492a5;
}
复制代码
在右边区域,我们需要定义margin-left的值大于left的值,否则会超过分割线:
.timeline-right {
位置:相对;
边距:- 3px 0 10px calc(var(--left) + 15px);
}
复制代码
为了让大家看到效果,暂时给左右两边设置了背景颜色和高度:
.timeline-left {
背景:黄绿色;
高度:50px;
}
.timeline-right {
背景:黄绿色;
高度:50px;
}
复制代码
可以看到效果出来了:
![]()
填写左右内容
为了达到初始动画中的效果,我们来丰富模板中的内容:
<模板>
< div class = "时间线项目" >
< div class = "时间线-左" >
< div class = "开始时间" >14:00</ div >
< div 类 = “持续时间” >1h</ div >
</ div >
< div 类 = “时间线点” ></ div >
< div class = "时间线-右" >
< div class = "title" >和詹姆斯打羽毛球 </ div >
<div类=“内容”>
<div类=“信息”>
< div class = "信息-no" >
< img src = "clock.svg" />
< span class = "info-content" >14:00 ~ 15:00</ span >
</ div >
< div 类 = "信息位置" >
![]()
< span class = "info-content" >市中心羽毛球场 </ span >
</ div >
</ div >
<div类=“加入”>
< 按钮 >
报名
</ button >
</ div >
</ div >
</ div >
</ div >
</ template >
复制代码
然后添加一些样式:
.timeline-left {
。开始时间 {
字体大小:16px;
}
。期间 {
字体大小:14px;
显示:弯曲;
对齐项目:居中;
证明内容:弹性结束;
}
}
.timeline-right {
。标题 {
字体大小:15px;
字体粗细:粗体;
@扩展.省略号2;
}
。内容 {
显示:弯曲;
弹性方向:行;
填充:5px 0;
.info {
字体大小:15px;
颜色:rgba($颜色:#1f3858,$alpha:0.6);
弹性:1;
图像{
右边距:5px;
边距顶部: - 2px;
高度:15px;
}
.info-不,
.info-位置{
显示:弯曲;
对齐项目:居中;
边距:5px 0;
.info-icon {
右边距:5px;
}
.info-内容{
弹性:1;
@扩展.省略号2;
}
& .隐藏{
显示:无;
}
}
}
。加入 {
显示:弯曲;
证明内容:弹性结束;
对齐项目:弹性开始;
& .隐藏{
显示:无;
}
}
}
}
复制代码
注意上面的代码是SCSS,这是为了方便使用嵌套语法写,如果想看转换后的CSS源码,可以使用下面的命令全局安装sass预处理器,然后生成上面的SCSS代码到 CSS 中:
$ yarn global 添加 sass
$ sass 时间线.scss > 时间线.css
复制代码
加点修饰,你终于可以达到最初的效果了!
![]()
完整代码
HTML 代码:
< html lang = "en" >
<头>
<元字符集=“UTF-8”>
< meta http-equiv = "X-UA-Compatible" 内容 = "IE=edge" >
<元名称=“视口”内容=“宽度=设备宽度,初始比例=1.0”>
时间线</ title ><br>
<链接 rel = "样式表" href = "./timeline.css" ><br>
<脚本><br>
常量节点 = [] 函数添加 () { 常量 tpl = 文档。 querySelector ('template') const item = tpl.内容 。儿童 [0] 常量时间线 = 文档。 querySelector ('.timeline') 节点。 forEach (it => it.classList.remove ('current')) const node = item. cloneNode ( true ) 节点。类列表。添加(“当前”)节点。推送(节点)控制台。日志(节点,节点。classList)时间线。 appendChild(节点)节点。 scrollIntoView ({ 行为 : 'smooth' , block : 'nearest' , inline : 'center' }) }</ script ><br>
</ head ></p>
<p><身体><br>
<div类=“容器”><br>
< div 类 = "调试区域" ><br>
< button onclick = "add()" >添加活动 </ button ><br>
</ div ><br>
< div class = "时间线区域" ><br>
< div 类 = "时间线包装器" ><br>
< div 类 = “时间线” ><br>
</ div ><br>
</ div ><br>
</ div ><br>
</ div ><br>
</ body ></p>
<p><模板><br>
< div class = "时间线项目" ><br>
< div class = "时间线-左" ><br>
< div class = "开始时间" >14:00</ div ><br>
< div 类 = “持续时间” >1h</ div ><br>
</ div ><br>
< div 类 = “时间线点” ></ div ><br>
< div class = "时间线-右" ><br>
< div class = "title" >和詹姆斯打羽毛球 </ div ><br>
<div类=“内容”><br>
<div类=“信息”><br>
< div class = "信息-no" ><br>
< img src = "clock.svg" /><br>
< span class = "info-content" >14:00 ~ 15:00</ span ><br>
</ div ><br>
< div 类 = "信息位置" ><br>
<img src = "location.svg" /><br>
< span class = "info-content" >市中心羽毛球场 </ span ><br>
</ div ><br>
</ div ><br>
<div类=“加入”><br>
< 按钮 ><br>
报名<br>
</ button ><br>
</ div ><br>
</ div ><br>
</ div ><br>
</ div ><br>
</ template ></p>
<p></ html ><br>
复制代码</p>
<p>SCSS代码:</p>
<p>.省略号 {<br>
溢出:隐藏;<br>
文本溢出:省略号;<br>
空白:nowrap;<br>
}<br>
.省略号2 {<br>
溢出:隐藏;<br>
空白:nowrap;<br>
文本溢出:省略号;<br>
@supports (-webkit-line-clamp: 2) {<br>
空白:初始;<br>
显示:-webkit-box;<br>
-webkit-line-clamp:2;<br>
-webkit-box-orient:垂直;<br>
}<br>
}</p>
<p>按钮 {<br>
显示:弯曲;<br>
证明内容:中心;<br>
对齐项目:居中;<br>
填充:0 12px;<br>
字体大小:14px;<br>
字体粗细:粗体;<br>
高度:30px;<br>
边框样式:实心;<br>
背景:#0d5dff;<br>
边框颜色:透明;<br>
白颜色;<br>
光标:指针;<br>
}</p>
<p>。容器 {<br>
保证金:汽车;<br>
宽度:350 像素;<br>
高度:350px;<br>
溢出:隐藏;<br>
显示:弯曲;<br>
弹性方向:列;<br>
填充:0;<br>
--左:60px;<br>
--颜色:#0d5dff;<br>
}</p>
<p>.调试区域{<br>
边距:30px 0;<br>
}</p>
<p>.timeline-area {<br>
弹性:1;<br>
位置:相对;<br>
显示:弯曲;<br>
弹性方向:列;<br>
溢出-y:自动;<br>
底部填充:10px;<br>
padding-right: 5px;<br>
边框:1px 实心#ccc;<br>
}</p>
<p>.timeline-area ::之前{<br>
内容: ””;<br>
显示:块;<br>
位置:绝对;<br>
z指数:2;<br>
左:0;<br>
右:12px;<br>
顶部:0;<br>
高度:25px;<br>
背景:线性渐变(<br>
到底部,<br>
RGBA(255、255、255、1)、<br>
RGBA(255、255、255、0)<br>
);<br>
}</p>
<p>.timeline-area::after {<br>
内容: ””;<br>
显示:块;<br>
位置:绝对;<br>
z指数:2;<br>
左:0;<br>
右:12px;<br>
底部:10px;<br>
高度:25px;<br>
背景:线性渐变(<br>
到达顶点,<br>
RGBA(255、255、255、1)、<br>
RGBA(255、255、255、0)<br>
);<br>
}</p>
<p>.timeline-wrapper {<br>
弹性:1;<br>
溢出-y:自动;<br>
填充:15px 5px 0 0;<br>
}</p>
<p>.timeline-wrapper::-webkit-scrollbar {<br>
宽度:6px;<br>
背景颜色:透明;<br>
}</p>
<p>.timeline-wrapper::-webkit-scrollbar-track-piece {<br>
边距:20px;<br>
}</p>
<p>.timeline-wrapper::-webkit-scrollbar-thumb {<br>
背景颜色:rgba($color: #000000, $alpha: 0.08);<br>
}</p>
<p>。时间线 {<br>
位置:相对;<br>
}</p>
<p>.timeline ::之前{<br>
内容: ””;<br>
位置:绝对;<br>
左:var(--左);<br>
宽度:1px;<br>
顶部:20px;<br>
底部:0;<br>
背景图像:线性渐变(<br>
到底部,<br>
RGBA(144, 156, 173, 0.6) 60%,<br>
RGBA(255, 255, 255, 0) 0%<br>
);<br>
背景位置:左;<br>
背景尺寸:1px 5px;<br>
背景重复:重复-y;<br>
}</p>
<p>.时间线项目{<br>
位置:相对;<br>
显示:内联块;<br>
宽度:100%;<br>
边距顶部:15px;<br>
}</p>
<p>.timeline-dot {<br>
左:var(--左);<br>
宽度:7px;<br>
高度:7px;<br>
位置:绝对;<br>
边界半径:50%;<br>
盒子阴影:0 0 0 1px #d8d8d8;<br>
背景:白色;<br>
文本对齐:居中;<br>
顶部:0;<br>
行高:40px;<br>
左边距:- 3.5px;<br>
}</p>
<p>.timeline-item .current .timeline-dot {<br>
宽度:10px;<br>
高度:10px;<br>
背景颜色:var(--color);<br>
盒子阴影:0 0 4px var(--color);<br>
边框:1px 纯白色;<br>
左边距: - 5px;<br>
}</p>
<p>.timeline-left {<br>
显示:块;<br>
宽度:计算(var(--left)- 7px);<br>
位置:绝对;<br>
边距顶部: - 5px;<br>
文本对齐:右;<br>
颜色:#8492a5;<br>
}</p>
<p>.timeline-right {<br>
位置:相对;<br>
边距:- 3px 0 10px calc(var(--left) + 15px);<br>
}</p>
<p>.timeline-item .current .title {<br>
颜色: var(--color);<br>
}</p>
<p>.timeline-left {<br>
。开始时间 {<br>
字体大小:16px;<br>
}<br>
。期间 {<br>
字体大小:14px;<br>
显示:弯曲;<br>
对齐项目:居中;<br>
证明内容:弹性结束;<br>
}<br>
}</p>
<p>.timeline-right {<br>
。标题 {<br>
字体大小:15px;<br>
字体粗细:粗体;<br>
@扩展.省略号2;<br>
}<br>
。内容 {<br>
显示:弯曲;<br>
弹性方向:行;<br>
填充:5px 0;<br>
.info {<br>
字体大小:15px;<br>
颜色:rgba($颜色:#1f3858,$alpha:0.6);<br>
弹性:1;<br>
图像{<br>
右边距:5px;<br>
边距顶部: - 2px;<br>
高度:15px;<br>
}<br>
.info-不,<br>
.info-位置{<br>
显示:弯曲;<br>
对齐项目:居中;<br>
边距:5px 0;<br>
.info-icon {<br>
右边距:5px;<br>
}<br>
.info-内容{<br>
弹性:1;<br>
@扩展.省略号2;<br>
}<br>
& .隐藏{<br>
显示:无;<br>
}<br>
}<br>
}<br>
。加入 {<br>
显示:弯曲;<br>
证明内容:弹性结束;<br>
对齐项目:弹性开始;<br>
& .隐藏{<br>
显示:无;<br>
}<br>
}<br>
}<br>
}<br>
复制代码</p>
<p>这里有很多细节与时间线无关,我在文章中没有解释,但其实很实用。例如,ellipsis和ellipsis2用于设置内容超过1或2行时的溢出效果,-webkit-scrollbar,--webkit-scrollbar-track-piece和-webkit-scrollbar-thumb用于自定义滚动条,有兴趣的读者可以参考我以前的<a href="https://juejin.cn/post/7139049177656819749" target="_blank"> 文章</a> .</p>
<p>版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议。转载请附上原文出处链接和本声明。</p>
<p>这篇文章的链接:<a href="https://homecpp.art/5223/10409/1834" target="_blank"> https://homecpp.art/5223/10409/1834</a></p>
<p>版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明</p>
<p>本文链接:<a href="https://www.qanswer.top/39024/38092411" target="_blank">https://www.qanswer.top/39024/38092411</a></p>