纯CSS实现水平时间轴单选选中后进度线渐变填充效果
纯CSS实现单选触发水平时间轴填充效果
代码无法触发填充效果,核心是3个问题:CSS选择器逻辑不成立、属性值无效、选中状态规则不全,按下面步骤修改即可,全程不需要编写JavaScript。
核心问题说明
- 原代码使用的兄弟选择器
~只能选中同父级下、排在当前元素后面的元素,你把单选按钮放在li标签内部,无法选中外层的时间轴填充条,所有选中后的样式规则全部失效 - 填充条初始宽度写的
width: 2没有单位,属于无效CSS值,浏览器无法识别 - 同组单选按钮给前两个都加了
checked属性,默认选中状态冲突 - 只写了第二个节点选中时的填充宽度,其他节点的宽度规则缺失
- 时间轴节点的圆点样式被注释,选中高亮效果缺失
修复代码
修正后的 index.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>水平时间轴组件</title> <link rel="stylesheet" href="style.css" /> </head> <body> <div class="container"> <!-- 把单选按钮移到容器最开头,保证可以通过兄弟选择器控制后续元素样式 --> <input type="radio" class="profile" checked name="timeline" > <input type="radio" class="setting" name="timeline" > <input type="radio" class="posts" name="timeline"> <input type="radio" class="books" name="timeline" > <input type="radio" class="extra" name="timeline" > <div class="head"> <ul class="nav"> <li class="st st1 active"> <img src="https://images.unsplash.com/photo-1593085512500-5d55148d6f0d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8Y2FydG9vbnxlbnwwfHwwfHw%3D&auto=format&fit=crop&w=600&q=60" alt="小黄人" /> <p>Minions</p> </li> <li class="st st2"> <img src="https://images.unsplash.com/photo-1637858868799-7f26a0640eb6?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTN8fGNhcnRvb258ZW58MHx8MHx8&auto=format&fit=crop&w=600&q=60" alt="开心表情" /> <p>Happy</p> </li> <li class="st st3"> <img src="https://images.unsplash.com/photo-1638803040283-7a5ffd48dad5?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8NDF8fGNhcnRvb258ZW58MHx8MHx8&auto=format&fit=crop&w=600&q=60" alt="卡通形象" /> <p>Cartoon</p> </li> <li class="st st4"> <img src="https://images.unsplash.com/photo-1637855463319-9acb4e5aa44f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8NDl8fGNhcnRvb258ZW58MHx8MHx8&auto=format&fit=crop&w=600&q=60" alt="猫咪" /> <p>Cat</p> </li> <li class="st st5"> <img src="https://images.unsplash.com/photo-1578632767115-351597cf2477?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8YW5pbWV8ZW58MHx8MHx8&auto=format&fit=crop&w=600&q=60" alt="动漫形象" /> <p>anime</p> </li> </ul> <div class="line"> <span></span> </div> </div> <div class="content"> <section class="minion-section"> <span><i></i></span> <h1>Minion</h1> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate quaerat quos eligendi distinctio velit. Id, a, amet, similique saepe quaerat quam veniam suscipit exercitationem ut quidem odio? Necessitatibus, velit recusandae. </p> </section> <section class="happy-section"> <span><i></i></span> <h1>Happy</h1> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate quaerat quos eligendi distinctio velit. Id, a, amet, similique saepe quaerat quam veniam suscipit exercitationem ut quidem odio? Necessitatibus, velit recusandae. </p> </section> <section class="cartoon-section"> <span><i></i></span> <h1>Cartoon</h1> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate quaerat quos eligendi distinctio velit. Id, a, amet, similique saepe quaerat quam veniam suscipit exercitationem ut quidem odio? Necessitatibus, velit recusandae. </p> </section> <section class="cat-section"> <span><i></i></span> <h1>Cat</h1> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate quaerat quos eligendi distinctio velit. Id, a, amet, similique saepe quaerat quam veniam suscipit exercitationem ut quidem odio? Necessitatibus, velit recusandae. </p> </section> <section class="anime-section"> <span><i></i></span> <h1>Anime</h1> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Cupiditate quaerat quos eligendi distinctio velit. Id, a, amet, similique saepe quaerat quam veniam suscipit exercitationem ut quidem odio? Necessitatibus, velit recusandae. </p> </section> </div> </div> </body> </html>
修正后的 style.css
@import url('https://fonts.googleapis.com/css2?family=Epilogue:wght@200&display=swap'); *{ padding: 0 ; margin: 0; } body{ background-position: center; font-family: 'Epilogue', sans-serif; } img{ width: 80px; border-radius: 50%; object-fit: cover; } ul { text-align: center; list-style: none; } ul li { display: inline-block; width: 19%; text-transform: uppercase; font-weight: 700; transition: all .3s ease; position: relative; cursor: pointer; } .container{ margin: 50px auto; width: 80vw; position: relative; } /* 隐藏原生单选按钮 */ input[type="radio"]{ position: absolute; opacity: 0; width: 0; height: 0; } /* 时间轴节点圆点样式 */ ul.nav li::after{ content: ''; display: block; width: 15px; height: 15px; background: #eee; border-radius: 50%; margin: 20px auto 0; border: 3px solid #fff; box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, .2); position: relative; z-index: 3; transition: all .3s ease; } .line{ width: 95%; margin: auto; background: #eee; height: 7px; position: absolute; left: 2.5%; top: 135px; z-index: 1; border-radius: 50px; } .line span { width: 10%; height: 100%; background: #282d35; position: absolute; left: 0; top: 0; z-index: 2; border-radius: 50px; transition: all .8s ease; } .content{ position: relative; margin-top: 80px; } section { display: none; width: 70%; margin: 0 auto; background: #282d35; border-radius: 4px; color: #fff; animation: fadeIn .5s ease forwards; } @keyframes fadeIn{ from{opacity: 0; transform: translateY(10px);} to{opacity: 1; transform: translateY(0);} } section span { font-size: 3rem; display: flex; justify-content: center; margin-bottom: 30px; } section h1{ font-weight: 900; margin-top: 20px; text-align: center; text-transform: uppercase; letter-spacing: 2px; } section p{ padding: 30px 40px; text-align: center; font-size: 18px; line-height: 1.6; } /* 单选选中对应状态 */ /* 第一个节点选中 */ .profile:checked ~ .head .nav li.st1::after{ background: #282d35; } .profile:checked ~ .head .line span{ width: 10%; } .profile:checked ~ .content .minion-section{ display: block; } /* 第二个节点选中 */ .setting:checked ~ .head .nav li.st1::after, .setting:checked ~ .head .nav li.st2::after{ background: #282d35; } .setting:checked ~ .head .line span{ width: 32%; } .setting:checked ~ .content .happy-section{ display: block; } /* 第三个节点选中 */ .posts:checked ~ .head .nav li.st1::after, .posts:checked ~ .head .nav li.st2::after, .posts:checked ~ .head .nav li.st3::after{ background: #282d35; } .posts:checked ~ .head .line span{ width: 53%; } .posts:checked ~ .content .cartoon-section{ display: block; } /* 第四个节点选中 */ .books:checked ~ .head .nav li.st1::after, .books:checked ~ .head .nav li.st2::after, .books:checked ~ .head .nav li.st3::after, .books:checked ~ .head .nav li.st4::after{ background: #282d35; } .books:checked ~ .head .line span{ width: 74%; } .books:checked ~ .content .cat-section{ display: block; } /* 第五个节点选中 */ .extra:checked ~ .head .nav li.st1::after, .extra:checked ~ .head .nav li.st2::after, .extra:checked ~ .head .nav li.st3::after, .extra:checked ~ .head .nav li.st4::after, .extra:checked ~ .head .nav li.st5::after{ background: #282d35; } .extra:checked ~ .head .line span{ width: 95%; } .extra:checked ~ .content .anime-section{ display: block; }
效果说明
修改后点击任意时间节点的图片、文字或者圆点位置,都会触发对应单选按钮选中:
- 深色填充条会从起点平滑延伸到当前选中节点位置
- 选中节点及之前所有节点的圆点都会变成深色高亮
- 下方自动切换显示对应节点的介绍内容,带淡入动画
- 全程无JavaScript代码,纯CSS实现所有交互
内容的提问来源于stack exchange,提问作者Android Army
相关产品推荐
相关产品推荐

