最近在写代码的时候,需要实现一个带窗户的楼宇小图标。因为图标本身挺简单的,就想着自己用 CSS 手搓一个。按常规思路,楼房的主体用一个块元素,里面的窗户用几个 span 或者 div 实现,然后绝对定位一下。
但是感觉为了一个小图标,就增加了几个没有意义的DOM节点,不够优雅,并且DOM树很臃肿,也影响重排重绘。于是我想到了用CSS的 box-shadow 来实现。
核心思路
box-shadow 通常都被用来做阴影渲染,但其实有个玩法:当 blur (模糊半径)和 spread(扩张半径)都设置为 0 的时候,阴影就会变成和原元素1:1等大的克隆体。然后我们再通过设置X轴和Y轴的偏移量进行布局,就可以实现我们想要的效果。
代码实现
HTML,创建一个父标签(楼房主体)即可
<div class="building-icon"></div>CSS:用为元素 ::before 画出第一个窗户,然后用 box-shadow 复制出另外三个
.building-icon{
width: 18px;
height: 22px;
background: #4a90d9;
border-radius: 4px 4px 0 0;
position: relative;
&::before {
content: '';
position: absolute;
width: 4px;
height: 4px;
top: 6px;
left: 4px;
border-radius: 1px;
background: rgba(255, 255, 255, .6);
box-shadow:
6px 0 0 rgba(255, 255, 255, .6),
0 6px 0 rgba(255, 255, 255, .6),
6px 6px 0 rgba(255, 255, 255, .6);
}
}效果如图:

总结
优点:
DOM 结构简单:不会产生额外的 DOM 元素,让 HTML 结构保持干净。
性能更好:减少了重排重绘。
box-shadow本身不占文档流,也不影响实际布局,纯粹是视觉上的克隆。
缺点:
只适合简单元素:这种写法本质上是在玩坐标系,如果复杂图案,代码可读性会很差。
不适合复杂交互:复杂的图案不入SVG或切图高效,且也无法单独绑定事件。