站住!送你一个漂亮的毛玻璃渐变背景
大家好呀,我是 HOHO。
不知道你之前有没有接触过这种需求,实现一个下面这样的背景:
一层毛玻璃,然后后面有一些渐变的色块动来动去。这种效果大家应该都比较熟悉,之前有段时间 Apple 很热衷于使用类似的特效,说实话确实挺好看。我们一般管这种效果叫做 blurry gradient、或者模糊渐变、磨砂渐变、毛玻璃渐变。
本来以为一个背景而已,有什么难度,没成想一路走来还真踩到了不少的坑。本着我摔了一身泥不能让大家再摔一次的原则。我把这种效果封装成了一个 React 组件 react-blurry-gradient,大家可以直接拿来用,省的再抄代码浪费脑细胞。
在讲组件之前,我先来介绍一下都踩了哪些坑,如果你急用的话,前面直接无视就行。OK 话不多说,我们现在开始。
心路历程
1、shader gradient
其实一开始和 UI 沟通的时候,这个效果并不是典型的模糊渐变。而是一个 Shader,你可以在 这个网站 看到类似的效果,这个 Shader Gradient 还有对应的 Figma 插件。
这个效果其实实现起来不难,因为它提供了对应的 react 插件 ruucm/shadergradient: Create beautiful moving gradients on Framer, Figma and React。只需要把 UI 给的参数填进去就可以了。
但是事情并没有想象的那么简单,单纯的复刻效果倒没什么问题,问题出在这玩意居然自带一个十分离谱的入场特效:
可以看到,这个效果初始化的时候会有个旋转缩放的“入场动画”,让人忍俊不禁。不仅如此,这个背景还非常离谱的是可以拖动和缩放的:
这两个问题在组件的文档里并没有任何说明,我猜测这个效果组件是基于 threejs 实现的,出现这两个问题应该是 threejs 的一些默认设置没有关闭导致的。
不过这些也不是什么大问题,我们可以通过控制入场透明度和添加蒙层来解决。真正阻止我继续使用的是性能问题。因为这个项目要支持 H5 端,而老板的破水果手机打开这个效果都要燃起来了。没办法只能作罢。
2、css-doodle
听说这个效果差点让老板换手机之后,UI 挠了挠头,说要不我给你点颜色,你干脆写个毛玻璃渐变得了。我觉得他说的有道理,随手一搜,这不就来了:妙用滤镜构建高级感拉满的磨砂玻璃渐变背景。
css-doodle 我之前研究过,虽然不太喜欢这种写法风格,但是谁能拒绝直接抄的代码呢?三下五除二就搞成了 React 版本:
import 'css-doodle';
import styles from './index.module.less';
const DOODLE_RULES = `
:doodle {
@grid: 1x8 / 100vmin;
width: 100vw;
height: 100vh;
}
@place-cell: center;
width: @rand(40vw, 80vw);
height: @rand(40vh, 80vh);
transform: translate(@rand(-50%, 50%), @rand(-60%, 60%)) scale(@rand(.8, 1.8)) skew(@rand(45deg));
clip-path: polygon(
@r(0, 30%) @r(0, 50%),
@r(30%, 60%) @r(0%, 30%),
@r(60%, 100%) @r(0%, 50%),
@r(60%, 100%) @r(50%, 100%),
@r(30%, 60%) @r(60%, 100%),
@r(0, 30%) @r(60%, 100%)
);
background: @pick(#FBF1F7, #B27CEE, #E280AE, #c469ee, #a443ee, #e261bb, #e488ee);
opacity: @rand(.3, .8);
position: relative;
top: @rand(-80%, 80%);
left: @rand(-80%, 80%);
animation: pos-change @rand(4.1s, 10.1s) infinite 0s linear alternate;
@keyframes pos-change {
100% {
left: 0;
top: 0;
transform: translate(@rand(-50%, 50%), @rand(-60%, 60%)) scale(@rand(.8, 1.8)) skew(@rand(45deg))
}
}`;
export const Bg = () => {
return (
<div className={styles.loginBg}>
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
{/* @ts-ignore */}
<css-doodle>{DOODLE_RULES}</css-doodle>
</div>
);
};
index.module.less
.loginBg {
position: absolute;
margin: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
background-color: #fff;
z-index: -1;
&::after {
content: '';
position: absolute;
top: -200%;
left: -200%;
right: -200%;
bottom: -200%;
backdrop-filter: blur(200px);
z-index: 1;
}
}
windows 上打开正常,但是 Safari 打开之后发现毛玻璃效果直接消失了,就像下面这样:
这给我整不会了,按理说 Safari 是支持 backdrop-filter
的。是 css-doodle 在 safari 上有什么兼容性问题?还是 react 和 css-doodle 的集成上出了什么毛病?我没深入了解,再加上本来不小的包体积,于是 css-doodle 方案也被我放弃了。
看看新组件 react-blurry-gradient
OK,踩了一圈子坑,下面该请出本文的主角 react-blurry-gradient 了,我们直接看效果:
如果 GIF 比较模糊的话可以试一下这个 codesandbox 在线 demo。
用法也很简单,安装,然后引入组件和对应的 css 文件即可:
npm install react-blurry-gradient
import { BlurryGradient } from 'react-blurry-gradient';
import 'react-blurry-gradient/style.css';
const colors = ['#bfdbfe', '#60a5fa', '#2563eb', '#c7d2fe', '#818cf8', '#4f46e5'];
export default function App() {
return (
<div style={{ width: '100vw', height: '100vh' }}>
<BlurryGradient colors={colors} />
</div>
);
}
组件会自动的从你指定的颜色列表中随机挑选颜色来生成渐变和动效。
如果你颜色也不想找,没问题,组件还内置了一套渐变颜色组,直接用就行了(目前包含红黄蓝绿紫五套):
import { BlurryGradient, COLORS } from 'react-blurry-gradient';
import 'react-blurry-gradient/style.css';
export default function App() {
return (
<div style={{ width: '100vw', height: '100vh' }}>
<BlurryGradient colors={COLORS.BLUE} />
</div>
);
}
这些颜色就是单纯的字符串数组,所以你可以把这些颜色兑在一起来实现撞色的效果:
<BlurryGradient colors={[...COLORS.BLUE, ...COLORS.RED]} />
如果你想设置背景色,没问题,react-blurry-gradient
本身就是透明的,也就是说你背景用什么都可以,直接设置给父元素就行了:
export default function App() {
return (
<div style={{ backgroundColor: COLORS.BLUE[0], width: '100vw', height: '100vh' }}>
<BlurryGradient colors={COLORS.BLUE} />
</div>
);
}
预设的 COLORS 第一个元素都是颜色最淡的,你可以直接拿来当作背景。
把这个背景色设置给 BlurryGradient
组件的 style 也可以,不过这样会在边缘形成一圈扩散的效果,而设置给父元素的话背景色就会更均一。
另外毛玻璃的模糊效果也是可以调整的,只需要设置 blur
参数即可,比如你可以调低一点,我觉得也挺好看的:
<BlurryGradient colors={[...COLORS.BLUE, ...COLORS.RED]} blur='20px' />
除此之外还有很多额外参数,例如可以通过 itemNumber
来控制生成色块的数量。可以通过 itemTop
、itemLeft
来控制色块随机生成的位置范围。更多的属性可以在 react-blurry-gradient 配置参数 找到。
如果你不希望随机生成,想精确控制每个色块的颜色、尺寸、位置和运动轨迹,没问题,BlurryGradient
组件的 items
参数允许你指定每个色块的详细配置。参数说明可以看 这里。但是要注意,启用了 items
之后,colors
的配置就会被忽视了。
零依赖 & 极小体积
这个组件从一开始就以够轻量为宗旨,所以你可以看到它没有依赖任何第三方包,只要你项目里有 React,那它就能用:
而包本身也足够的清爽,不会往你电脑里拉屎:
组件所有的代码加起来只有 4Kb 不到。
当然,如果你真的不想因为这种小事再引一个包,没问题,都帮你收拾好了,把 这个文件夹 直接复制到你的项目里就能用,给个 star 意思一下就行~
来源:juejin.cn/post/7446018863504506907