在Codepen上看到的,稍微改了一下,效果可以看本站aside的card或nav。
实现思路
主要思路是利用多层叠加,共四层
1 2 3 4 5 6 7 8
| <div class="liquidGlass-wrapper"> <div class="liquidGlass-effect"></div> <div class="liquidGlass-tint"></div> <div class="liquidGlass-shine"></div> <div class="liquidGlass-box"> </div> </div>
|
liquidGlass-wrapper
容器壳
1 2 3 4 5 6 7 8
| .liquidGlass-wrapper { box-shadow: 0 6px 6px rgba(0, 0, 0, 0.2), 0 0 20px rgba(0, 0, 0, 0.1) !important; transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 2.2) !important; background: none !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; border-style: none !important; }
|
- 作用:最外层容器,负责整体阴影和动画过渡。
- 关键点:
background: none 和 backdrop-filter: none 是为了不让它自己产生模糊,把模糊交给内部 .liquidGlass-effect。
- 阴影模拟玻璃的立体感。
transition 让 hover 时的圆角和 padding 变化更流畅。
liquidGlass-effect
核心“液态”模糊层
1 2 3 4 5 6 7 8 9 10
| .liquidGlass-effect { position: absolute; z-index: 0; inset: 0;
backdrop-filter: blur(3px); filter: url(#glass-distortion); overflow: hidden; isolation: isolate; }
|
backdrop-filter: blur(3px)
对背景内容(如网页其他部分)做模糊处理 → 这是“毛玻璃”的基础。
filter: url(#glass-distortion)⭐ 这是“液态”感的关键!它引用了一个 SVG 滤镜(#glass-distortion),通常定义在页面 <svg> 中,用于对图像施加扭曲、波纹、液态流动等效果。
isolation: isolate 确保该层创建新的层叠上下文,避免滤镜影响其他元素。
glass-distortion
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| <svg style="display: none"> <filter id="glass-distortion" x="0%" y="0%" width="100%" height="100%" filterUnits="objectBoundingBox" > <feTurbulence type="fractalNoise" baseFrequency="0.01 0.01" numOctaves="1" seed="5" result="turbulence" />
<feComponentTransfer in="turbulence" result="mapped"> <feFuncR type="gamma" amplitude="1" exponent="10" offset="0.5" /> <feFuncG type="gamma" amplitude="0" exponent="1" offset="0" /> <feFuncB type="gamma" amplitude="0" exponent="1" offset="0.5" /> </feComponentTransfer>
<feGaussianBlur in="turbulence" stdDeviation="3" result="softMap" />
<feSpecularLighting in="softMap" surfaceScale="5" specularConstant="1" specularExponent="100" lighting-color="white" result="specLight" > <fePointLight x="-200" y="-200" z="300" /> </feSpecularLighting>
<feComposite in="specLight" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litImage" />
<feDisplacementMap in="SourceGraphic" in2="softMap" scale="150" xChannelSelector="R" yChannelSelector="G" /> </filter> </svg>
|
liquidGlass-tint
色调蒙层
1 2 3 4 5 6
| .liquidGlass-tint { z-index: 1; position: absolute; inset: 0; background: rgba(255, 255, 255, 0.25); }
|
- 在模糊层之上叠加一层半透明白色(也可改为浅蓝、浅灰等)。
- 模拟真实玻璃的“反光底色”,让文字/内容更易读。
z-index: 1 确保它在 effect 之上、shine 之下。
liquidGlass-shine
高光层
1 2 3 4 5 6 7 8 9 10
| .liquidGlass-shine { position: absolute; inset: 0; z-index: 2;
overflow: hidden;
box-shadow: inset 2px 2px 1px 0 rgba(255, 255, 255, 0.5), inset -1px -1px 1px 1px rgba(255, 255, 255, 0.5); }
|
- 使用 内阴影(inset box-shadow) 模拟玻璃边缘的高光和微反光。
- 上右亮(+2px 白光),下左稍暗(-1px 白光)→ 营造光照方向感。
z-index: 2 放在最上层(但低于内容)。
liquidGlass-box
内容层
1 2 3 4 5 6 7
| .liquidGlass-box { z-index: 3; position: relative; box-shadow: none !important; }
|
- 真正放内容的地方(如头像、文字)。
z-index: 3 确保内容在所有玻璃效果层之上,清晰可见。
position: relative 使其脱离普通流,但仍在 wrapper 内。
交互效果(Hover 动态)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
.liquidGlass-wrapper, .liquidGlass-wrapper > div:not(.liquidGlass-box) { padding: 0.4rem !important; border-radius: var(--glass-border-radius) !important; }
.liquidGlass-wrapper:hover { padding: 0.6rem !important; border-radius: calc(var(--glass-border-radius) + 1em) !important; }
.liquidGlass-wrapper > div:not(.liquidGlass-box):hover { border-radius: calc(var(--glass-border-radius) + 1em) !important; }
|
- 悬停时:
- 圆角变大(
+1em)→ 模拟“液体膨胀”或“柔软变形”;
- 内边距增大 → 整体“呼吸感”;
- 所有非内容层同步圆角变化,保持视觉一致。
应用到butterfly的例子
下面以card_author为例,即显示作者信息的卡片。
card_author.pug
修改themes\butterfly\layout\includes\widget\card_author.pug
1 2 3 4 5 6 7 8 9 10 11 12 13
| if theme.aside.card_author.enable .card-widget.card-info.text-center.liquidGlass-wrapper .liquidGlass-effect .liquidGlass-tint .liquidGlass-shine .liquidGlass-box div.card-info-avatar .avatar-img img( src=url_for(theme.avatar.img) onerror="this.onerror=null;this.src='" + url_for(theme.error_img.flink) + "'" alt="avatar" )
|
liquid_glass.css
创建自定义css文件themes\butterfly\source\css\liquid_glass.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| :root { --glass-border-radius: 1.2rem; }
.liquidGlass-wrapper { box-shadow: 0 6px 6px rgba(0, 0, 0, 0.2), 0 0 20px rgba(0, 0, 0, 0.1) !important; transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 2.2) !important; background: none !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; border-style: none !important; }
.liquidGlass-effect { position: absolute; z-index: 0; inset: 0;
backdrop-filter: blur(3px); filter: url(#glass-distortion); overflow: hidden; isolation: isolate; }
.liquidGlass-tint { z-index: 1; position: absolute; inset: 0; background: rgba(255, 255, 255, 0.25); }
.liquidGlass-shine { position: absolute; inset: 0; z-index: 2;
overflow: hidden;
box-shadow: inset 2px 2px 1px 0 rgba(255, 255, 255, 0.5), inset -1px -1px 1px 1px rgba(255, 255, 255, 0.5); }
.liquidGlass-box { z-index: 3; position: relative; box-shadow: none !important; }
.liquidGlass-wrapper, .liquidGlass-wrapper > div:not(.liquidGlass-box) { padding: 0.4rem !important; border-radius: var(--glass-border-radius) !important; }
.liquidGlass-wrapper:hover { padding: 0.6rem !important; border-radius: calc(var(--glass-border-radius) + 1em) !important; }
.liquidGlass-wrapper > div:not(.liquidGlass-box):hover { border-radius: calc(var(--glass-border-radius) + 1em) !important; }
|
inject
主题的_config.yaml的inject中引入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| inject: head: - <link rel="stylesheet" href="/css/liquid_glass.css"> bottom: - | <svg style="display: none"> <filter id="glass-distortion" x="0%" y="0%" width="100%" height="100%" filterUnits="objectBoundingBox" > <feTurbulence type="fractalNoise" baseFrequency="0.01 0.01" numOctaves="1" seed="5" result="turbulence" /> <!-- Seeds: 14, 17, -->
<feComponentTransfer in="turbulence" result="mapped"> <feFuncR type="gamma" amplitude="1" exponent="10" offset="0.5" /> <feFuncG type="gamma" amplitude="0" exponent="1" offset="0" /> <feFuncB type="gamma" amplitude="0" exponent="1" offset="0.5" /> </feComponentTransfer>
<feGaussianBlur in="turbulence" stdDeviation="3" result="softMap" />
<feSpecularLighting in="softMap" surfaceScale="5" specularConstant="1" specularExponent="100" lighting-color="white" result="specLight" > <fePointLight x="-200" y="-200" z="300" /> </feSpecularLighting>
<feComposite in="specLight" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litImage" />
<feDisplacementMap in="SourceGraphic" in2="softMap" scale="150" xChannelSelector="R" yChannelSelector="G" /> </filter> </svg>
|
参考