CSS最佳实践:如何将一个伪元素正确覆盖在另一伪元素之上
我从Frontend Mentor下载了如下设计用于练习CSS技能:
这是设计稿的hover状态效果:
这是我实现的效果:
我使用如下styled-components格式的CSS规则实现了上述效果:
const CardImage = styled.div` background-image: url(${(props) => props.cardImage || DefaultImage}); background-repeat: no-repeat; background-size: cover; border-radius: 15px; height: 270px; margin-bottom: 25px; width: 270px; &:hover:after { content: url(${ViewIcon}); position: absolute; left: calc(50% - 24px); top: calc(50% - 135px); } &:hover:before { position: relative; content:''; display: block; height: 100%; width: 100%; background-color: rgba(1,153,174,0.5); } `;
我是CSS新手,不确定当前实现是否为最优方案,请问还有什么更优的实现方式?这类hover叠加效果只能通过伪元素实现吗?
回答
你的基础实现已经可以达成需求效果,仍存在可优化空间,这类hover叠加效果并非只能通过伪元素实现,具体优化方案和替代实现如下:
现有实现的可优化点
- 父容器没有设置
position: relative,:after使用绝对定位时,定位基准是最近的非static定位的祖先元素,页面其他布局变动很容易导致图标位置偏移 - 半透明蒙层使用
position: relative会占用文档流空间,极端情况下可能挤压其他内部元素,且未设置border-radius,hover时圆角位置会漏出原背景图 - 图标定位使用
calc硬算偏移值,后续如果修改卡片尺寸,需要同步调整计算参数,维护成本较高
优化后的伪元素实现方案
先给父容器加相对定位作为内部绝对定位的基准,调整伪元素定位逻辑,新增过渡效果让hover交互更丝滑,优化后代码如下:
const CardImage = styled.div` position: relative; background-image: url(${(props) => props.cardImage || DefaultImage}); background-repeat: no-repeat; background-size: cover; border-radius: 15px; height: 270px; margin-bottom: 25px; width: 270px; &:before, &:after { opacity: 0; transition: opacity 0.2s ease; } &:hover:before, &:hover:after { opacity: 1; } &:after { content: url(${ViewIcon}); position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } &:before { position: absolute; content:''; top: 0; left: 0; height: 100%; width: 100%; border-radius: 15px; background-color: rgba(1,153,174,0.5); } `;
无需伪元素的替代实现方案
这类hover叠加效果有多种实现方式,除伪元素外还有两种常用方案:
- 嵌套子元素实现
在CardImage内部新增两个子元素,分别对应半透明蒙层和查看图标,默认隐藏,hover时控制显示。优势是如果需要给蒙层/图标绑定点击等JS事件,真实DOM元素比伪元素更易操作,不需要额外做事件委托。 - 多重背景实现
直接通过hover时修改background属性叠加效果,代码更简洁,适合不需要交互的纯展示场景:
const CardImage = styled.div` background: url(${(props) => props.cardImage || DefaultImage}) center/cover no-repeat; border-radius: 15px; height: 270px; margin-bottom: 25px; width: 270px; transition: background 0.2s ease; &:hover { background: rgba(1,153,174,0.5) url(${ViewIcon}) center/48px no-repeat, url(${(props) => props.cardImage || DefaultImage}) center/cover no-repeat; } `;
内容的提问来源于stack exchange,提问作者Johnatan De Leon
相关产品推荐
相关产品推荐

