使用 CSS 从头开始​​编写时间线效果

我报名了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 类 = "信息位置" >  
 <img src = "location.svg" />  
 < 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 代码:

 <!DOCTYPE html >  
 < html lang = "en" >  
  
 <头>  
 <元字符集=“UTF-8”>  
 < meta http-equiv = "X-UA-Compatible" 内容 = "IE=edge" >  
 <元名称=“视口”内容=“宽度=设备宽度,初始比例=1.0”>  
 <title>时间线</ title >  
 <链接 rel = "样式表" href = "./timeline.css" >  
 <脚本>  
 常量节点 = [] 函数添加 () { 常量 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 >  
 </ head >  
  
 <身体>  
 <div类=“容器”>  
 < div 类 = "调试区域" >  
 < button  onclick = "add()" >添加活动 </ button >  
 </ div >  
 < div class = "时间线区域" >  
 < div 类 = "时间线包装器" >  
 < div 类 = “时间线” >  
 </ div >  
 </ div >  
 </ div >  
 </ div >  
 </ body >  
  
 <模板>  
 < 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 类 = "信息位置" >  
 <img src = "location.svg" />  
 < span  class = "info-content" >市中心羽毛球场 </ span >  
 </ div >  
 </ div >  
 <div类=“加入”>  
 < 按钮 >  
 报名  
 </ button >  
 </ div >  
 </ div >  
 </ div >  
 </ div >  
 </ template >  
  
 </ html >  
 复制代码

SCSS代码:

 .省略号 {  
 溢出:隐藏;  
 文本溢出:省略号;  
 空白:nowrap;  
 }  
 .省略号2 {  
 溢出:隐藏;  
 空白:nowrap;  
 文本溢出:省略号;  
 @supports (-webkit-line-clamp: 2) {  
 空白:初始;  
 显示:-webkit-box;  
 -webkit-line-clamp:2;  
 -webkit-box-orient:垂直;  
 }  
 }  
  
 按钮 {  
 显示:弯曲;  
 证明内容:中心;  
 对齐项目:居中;  
 填充:0 12px;  
 字体大小:14px;  
 字体粗细:粗体;  
 高度:30px;  
 边框样式:实心;  
 背景:#0d5dff;  
 边框颜色:透明;  
 白颜色;  
 光标:指针;  
 }  
  
 。容器 {  
 保证金:汽车;  
 宽度:350 像素;  
 高度:350px;  
 溢出:隐藏;  
 显示:弯曲;  
 弹性方向:列;  
 填充:0;  
 --左:60px;  
 --颜色:#0d5dff;  
 }  
  
 .调试区域{  
 边距:30px 0;  
 }  
  
 .timeline-area {  
 弹性:1;  
 位置:相对;  
 显示:弯曲;  
 弹性方向:列;  
 溢出-y:自动;  
 底部填充:10px;  
 padding-right: 5px;  
 边框:1px 实心#ccc;  
 }  
  
  
 .timeline-area ::之前{  
 内容: ””;  
 显示:块;  
 位置:绝对;  
 z指数:2;  
 左:0;  
 右:12px;  
 顶部:0;  
 高度:25px;  
 背景:线性渐变(  
 到底部,  
 RGBA(255、255、255、1)、  
 RGBA(255、255、255、0)  
 );  
 }  
  
 .timeline-area::after {  
 内容: ””;  
 显示:块;  
 位置:绝对;  
 z指数:2;  
 左:0;  
 右:12px;  
 底部:10px;  
 高度:25px;  
 背景:线性渐变(  
 到达顶点,  
 RGBA(255、255、255、1)、  
 RGBA(255、255、255、0)  
 );  
 }  
  
 .timeline-wrapper {  
 弹性:1;  
 溢出-y:自动;  
 填充:15px 5px 0 0;  
 }  
  
  
 .timeline-wrapper::-webkit-scrollbar {  
 宽度:6px;  
 背景颜色:透明;  
 }  
  
 .timeline-wrapper::-webkit-scrollbar-track-piece {  
 边距:20px;  
 }  
  
 .timeline-wrapper::-webkit-scrollbar-thumb {  
 背景颜色:rgba($color: #000000, $alpha: 0.08);  
 }  
  
  
 。时间线 {  
 位置:相对;  
 }  
  
 .timeline ::之前{  
 内容: ””;  
 位置:绝对;  
 左:var(--左);  
 宽度:1px;  
 顶部:20px;  
 底部:0;  
 背景图像:线性渐变(  
 到底部,  
 RGBA(144, 156, 173, 0.6) 60%,  
 RGBA(255, 255, 255, 0) 0%  
 );  
 背景位置:左;  
 背景尺寸:1px 5px;  
 背景重复:重复-y;  
 }  
  
 .时间线项目{  
 位置:相对;  
 显示:内联块;  
 宽度:100%;  
 边距顶部:15px;  
 }  
  
 .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;  
 }  
  
 .timeline-left {  
 显示:块;  
 宽度:计算(var(--left)- 7px);  
 位置:绝对;  
 边距顶部: - 5px;  
 文本对齐:右;  
 颜色:#8492a5;  
 }  
  
 .timeline-right {  
 位置:相对;  
 边距:- 3px 0 10px calc(var(--left) + 15px);  
 }  
  
 .timeline-item .current .title {  
 颜色: var(--color);  
 }  
  
 .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;  
 }  
 & .隐藏{  
 显示:无;  
 }  
 }  
 }  
 。加入 {  
 显示:弯曲;  
 证明内容:弹性结束;  
 对齐项目:弹性开始;  
 & .隐藏{  
 显示:无;  
 }  
 }  
 }  
 }  
 复制代码

这里有很多细节与时间线无关,我在文章中没有解释,但其实很实用。例如,ellipsis和ellipsis2用于设置内容超过1或2行时的溢出效果,-webkit-scrollbar,--webkit-scrollbar-track-piece和-webkit-scrollbar-thumb用于自定义滚动条,有兴趣的读者可以参考我以前的 文章 .

版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议。转载请附上原文出处链接和本声明。

这篇文章的链接: https://homecpp.art/5223/10409/1834

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/39024/38092411

posted @ 2022-09-24 11:38  哈哈哈来了啊啊啊  阅读(952)  评论(0编辑  收藏  举报