如何无需按住点击、纯CSS实现点击表格行后箭头图标滑出淡出动画
问题:CSS实现表格行点击后箭头自动飘走效果
我在ReactJS中有一个包含多个可点击行的表格。
每行在hover时会轻微高亮,同时箭头图标会通过传统CSS animations/transitions效果从左侧淡入的小方块中出现。
我想要实现的效果是:点击行后,已出现的箭头会继续沿路径向右淡出。
我已编写了如下代码,hover后按住点击行时可以看到箭头确实会向外移动,但松开后效果就会中断,这符合:active伪类的预期表现。
我想知道是否可以不依赖:active伪类,实现点击行后元素自动飘走的效果?能否完全不用JavaScript实现?
原有CSS代码
table { display: table; border-collapse: separate; box-sizing: border-box; text-indent: initial; border-spacing: 2px; border-color: grey; width: 100%; border: 1px solid #dee2e6; margin-bottom: 1rem; } .table > thead > tr > th { font-size: 14px; font-weight: 700; padding-bottom: 0; text-transform: uppercase; border: 0; } table td { padding: 15px; height: 20px; } .table.table-striped tbody tr:nth-of-type(odd) { background-color: #f6f6f6; } .table-striped tbody tr:nth-of-type(odd) { background-color: rgba(0, 0, 0, 0.05); } tr.has-click-handler { cursor: pointer; } tr.has-click-handler:hover td { background-color: rgba(10, 138, 241, 0.192); } tr.has-click-handler td.row-click-indicator { justify-content: center; flex-direction: column; position: relative; display: flex; align-items: flex-start; } tr.has-click-handler td.row-click-indicator:after { transition: all 300ms ease-out; font-family: Arial; position: absolute; right: 100px; content: ">"; font-size: 22px; font-weight: 900; opacity: 0; background-color: #004990; color: #fff; width: 30px; height: 30px; text-align: center; border-radius: 5px; } tr.has-click-handler td.row-click-indicator:hover:after { opacity: 1; right: 10px; } tr.has-click-handler td.row-click-indicator:active:after { right: -25px; opacity: 0; }
原有HTML代码
<table class="table table-striped table-bordered"> <thead> <tr> <th class="text-right pr-2">#</th> <th>Class Name</th> <th class="text-right">Meta Count</th> </tr> </thead> <tbody> <tr class="has-click-handler"> <td class="text-right pr-2">1.</td> <td class="row-click-indicator">Auth Security</td> <td align="right"><span class="badge badge-pill badge-primary">7</span></td> </tr> <tr class="has-click-handler"> <td class="text-right pr-2">2.</td> <td class="row-click-indicator">Data Storage</td> <td align="right"><span class="badge badge-pill badge-primary">5</span></td> </tr> <tr class="has-click-handler"> <td class="text-right pr-2">3.</td> <td class="row-click-indicator">Data Receiving </td> <td align="right"><span class="badge badge-pill badge-primary">5</span></td> </tr> <tr class="has-click-handler"> <td class="text-right pr-2">4.</td> <td class="row-click-indicator">Data Integrity</td> <td align="right"><span class="badge badge-pill badge-primary">3</span></td> </tr> <tr class="has-click-handler"> <td class="text-right pr-2">5.</td> <td class="row-click-indicator">Vulnerabilities</td> <td align="right"><span class="badge badge-pill badge-primary">3</span></td> </tr> <tr class="has-click-handler"> <td class="text-right pr-2">6.</td> <td class="row-click-indicator">Network</td> <td align="right"><span class="badge badge-pill badge-primary">0</span></td> </tr> </tbody> </table>
更新说明
我需要说明,我希望尽可能使用非JavaScript方案,有没有办法用CSS触发transition后,无论元素当前处于hover/active/focus哪种状态,都能让过渡效果持续执行完成?
解决方案
可以完全用纯CSS实现,不需要引入JavaScript,核心调整思路如下:
- 给所有
.row-click-indicator元素加上tabindex="0"属性,让普通td元素可以获得焦点,点击后会保持:focus状态,不会因为松开鼠标就丢失状态 - 将原来的单transition改为CSS关键帧动画,配合
animation-fill-mode: forwards保证动画执行完后保持最终状态,不会回弹 - 调整状态优先级,让:focus状态的动画优先级高于hover状态,点击后自动触发飘走动画,不受后续hover状态变化影响
修改后的CSS代码
/* 原有其他CSS规则保持不变,仅修改箭头相关的规则 */ tr.has-click-handler td.row-click-indicator:after { font-family: Arial; position: absolute; right: 100px; content: ">"; font-size: 22px; font-weight: 900; opacity: 0; background-color: #004990; color: #fff; width: 30px; height: 30px; text-align: center; border-radius: 5px; } /* hover时的进入动画 */ tr.has-click-handler td.row-click-indicator:hover:after { animation: arrowIn 300ms ease-out forwards; } /* 点击(获得焦点)时的飘走淡出动画 */ tr.has-click-handler td.row-click-indicator:focus:after { animation: arrowOut 300ms ease-out forwards; /* 取消点击后的焦点轮廓,不影响原有视觉效果 */ outline: none; } @keyframes arrowIn { from { opacity: 0; right: 100px; } to { opacity: 1; right: 10px; } } @keyframes arrowOut { from { opacity: 1; right: 10px; } to { right: -25px; opacity: 0; } }
修改后的HTML示例
只需要给每个.row-click-indicator的td加上tabindex="0"即可:
<!-- 仅展示修改后的行示例,其他行同理修改 --> <tr class="has-click-handler"> <td class="text-right pr-2">1.</td> <td class="row-click-indicator" tabindex="0">Auth Security</td> <td align="right"><span class="badge badge-pill badge-primary">7</span></td> </tr>
补充说明
如果需要点击一次后下次hover仍能正常显示箭头,可以给:focus状态加一个非常长的动画延迟重置,或者用:focus-visible做兼容调整,以上基础方案已经可以满足描述的核心需求。
内容的提问来源于stack exchange,提问作者Barry Chapman
相关产品推荐
相关产品推荐

