✎ 修改左侧代码,右侧实时更新
🧪纯 CSS 流光按钮,悬停有光效,可直接复制
晚上改一个活动页,最容易卡住的不是大功能,反而是这种小按钮。
产品说:“这个按钮能不能亮一点?鼠标放上去有点感觉,点了之后也给个反馈。”
这段代码干的就是这件事:做一个带渐变流光效果的按钮,鼠标悬停时背景动一下,点击后文字变成“点击成功”。
把它想成商场门口的霓虹招牌。平时它就亮着,路人一靠近,灯带从左往右扫一下;真的进店了,门口牌子立刻换成“欢迎光临”。
HTML 很简单,只有一个按钮:
html<!-- 一个按钮,class="glow" 是给 CSS 和 JS 找它用的名字 -->
<button class="glow">✨ Hover / Click me</button>这里的 class="glow" 很关键。
它像给按钮贴了一个标签。
CSS 看到这个标签,就知道“我要给它加样式”。
JS 看到这个标签,就知道“点击事件要绑到它身上”。
再看 CSS:
css/* 页面本身:把按钮放到屏幕正中间 */
body {
margin: 0; /* 去掉浏览器默认外边距,不然页面边缘会有一圈空白 */
height: 100vh; /* 高度占满整个浏览器窗口 */
display: grid; /* 用 grid 布局 */
place-items: center; /* 水平、垂直都居中 */
background: #0f172a; /* 深蓝黑背景,让按钮的粉色渐变更明显 */
}
/* 按钮本体 */
.glow {
padding: 16px 40px; /* 按钮内部留白,让它看起来不挤 */
border: 0; /* 去掉默认边框 */
border-radius: 14px; /* 圆角,按钮更柔和 */
font-size: 18px; /* 字体大小 */
font-weight: 700; /* 字体加粗 */
color: #fff; /* 文字白色 */
cursor: pointer; /* 鼠标移上去变成小手,告诉用户它能点 */
/* 核心:渐变背景,从粉到深粉再回到粉 */
background: linear-gradient(90deg, #f472b6, #db2777, #f472b6);
/* 背景宽度放大到按钮的 2 倍,后面才能“滑动” */
background-size: 200% 100%;
/* 告诉浏览器:背景位置和按钮位移变化时,别突然变,慢慢过渡 */
transition: background-position .5s, transform .2s;
}
/* 鼠标移上去时 */
.glow:hover {
background-position: 100% 0; /* 把背景往右推,形成渐变流动感 */
transform: translateY(-3px); /* 按钮往上浮一点,像被托起来 */
}这段 CSS 的灵魂在这两句:
cssbackground-size: 200% 100%;
background-position: 100% 0;普通背景就像一张刚好铺满按钮的海报。
你怎么移动它,都看不出明显变化。
所以这里先把背景做成“两张按钮那么宽”的长海报:
text按钮可见区域 ┌──────────────┐ │ 粉 → 深粉 │ └──────────────┘ 真实背景其实更宽 ┌──────────────┬──────────────┐ │ 粉 → 深粉 → 粉 │ 粉 → 深粉 → 粉 │ └──────────────┴──────────────┘
鼠标放上去后,不是按钮本身变色,而是这张“长海报”往旁边挪了一下。
你看到的效果就是:按钮里的颜色像流过去了。
最后是 JS:
js// 找到页面上 class 为 glow 的按钮
document.querySelector('.glow').addEventListener('click', function () {
// 点击后,把按钮里的文字换掉
this.textContent = '🎉 点击成功!';
});这段 JS 就像给按钮安排了一个“按门铃”的动作。
用户点一下按钮,浏览器触发 click。function(){ ... } 里面的 this,指的就是被点击的这个按钮。
所以 this.textContent = '🎉 点击成功!' 的意思是:把按钮上的字换成新的。
整个流程走起来是这样:
text用户看到按钮 │ ├─ 鼠标移上去 │ │ │ ▼ │ 触发 .glow:hover │ │ │ ├─ 背景位置移动 │ └─ 按钮上浮 3px │ └─ 点击按钮 │ ▼ 触发 click 事件 │ ▼ JS 改 textContent │ ▼ 文案变成“🎉 点击成功!”
这个按钮好看的点,不是颜色多,而是变化有缓冲。
如果没有这句:
csstransition: background-position .5s, transform .2s;鼠标一放上去,背景会“啪”一下跳到新位置,按钮也会“啪”一下抬上去。
能用,但很生硬。
transition 做的事有点像电梯。
你从 1 楼到 3 楼,不是瞬间闪现,而是慢慢上去。
浏览器也是这样:它知道 background-position 要变,transform 要变,于是帮你把中间过程补出来。
这里两个时间不一样,也有讲究:
cssbackground-position .5s
transform .2s背景流动慢一点,像灯光扫过去。
按钮上浮快一点,像手指刚碰到就立刻有反应。
还有一个细节,按钮上浮用的是:
csstransform: translateY(-3px);而不是改:
csstop: -3px;
margin-top: -3px;原因很实际。transform 更适合做动画,浏览器处理起来更轻。
你可以理解为:它只是把按钮“画面上挪一下”,不太会影响旁边元素排队站位。
原版适合演示,短、直观。
但真放到项目里,我会补几个小东西:
一是加 type="button",避免按钮放进表单里时默认触发表单提交。
二是加键盘焦点样式,不然只用键盘操作的人看不出自己选中了哪个按钮。
三是照顾一下“减少动态效果”的系统设置,有些用户不喜欢动画太晃。
HTML 可以这样写:
html<button class="glow-btn" type="button" aria-live="polite">
✨ 点我试试
</button>CSS 版:
css:root {
--page-bg: #0f172a;
--pink-light: #f472b6;
--pink-dark: #db2777;
--text: #ffffff;
}
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background: var(--page-bg);
}
.glow-btn {
padding: 16px 40px;
border: 0;
border-radius: 14px;
font-size: 18px;
font-weight: 700;
color: var(--text);
cursor: pointer;
background: linear-gradient(
90deg,
var(--pink-light),
var(--pink-dark),
var(--pink-light)
);
background-size: 200% 100%;
transition:
background-position 0.5s ease,
transform 0.2s ease,
box-shadow 0.2s ease;
}
.glow-btn:hover {
background-position: 100% 0;
transform: translateY(-3px);
box-shadow: 0 12px 28px rgba(219, 39, 119, 0.35);
}
.glow-btn:active {
transform: translateY(-1px) scale(0.98);
}
.glow-btn:focus-visible {
outline: 3px solid rgba(244, 114, 182, 0.55);
outline-offset: 4px;
}
/* 如果用户系统设置了“减少动态效果”,这里就把动画关掉 */
@media (prefers-reduced-motion: reduce) {
.glow-btn {
transition: none;
}
.glow-btn:hover,
.glow-btn:active {
transform: none;
}
}JS 版:
jsconst button = document.querySelector('.glow-btn');
if (button) {
button.addEventListener('click', function () {
this.textContent = '🎉 点击成功!';
this.setAttribute('aria-label', '点击成功');
});
}这里比原版多了一个判断:
jsif (button) {
// ...
}原因也很朴素。
真实项目里,JS 文件可能被很多页面共用。
万一某个页面没有 .glow-btn,document.querySelector('.glow-btn') 就会拿到 null。
如果你直接 .addEventListener,页面会报错。
TS 版可以写得更明确一点:
tsconst button = document.querySelector<HTMLButtonElement>('.glow-btn');
if (!button) {
throw new Error('页面上没有找到 .glow-btn 按钮');
}
button.addEventListener('click', () => {
button.textContent = '🎉 点击成功!';
button.setAttribute('aria-label', '点击成功');
});TypeScript 这里的好处是,它知道 button 是一个 HTMLButtonElement。
也就是说,编辑器能更准确地提示你这个按钮能用哪些属性和方法。
如果你拼错了方法名,它也更容易提前提醒。
这个按钮效果挺讨喜,但不是所有按钮都该这么亮。
如果是活动页、登录页主按钮、支付页的关键操作,它很合适。
用户需要被引导,按钮需要从页面里跳出来。
但如果是后台管理系统里一排“编辑、删除、导出、同步”按钮,每个都做渐变流光,就会很吵。
页面像夜市招牌一样闪,用户反而不知道该点哪个。
还有一种情况也别硬上:按钮是危险操作,比如“删除账号”“清空数据”。
这种按钮更需要明确、克制、可识别。
花里胡哨的动画会削弱严肃感。
简单说:
text适合: - 活动页主按钮 - 营销落地页 CTA - 登录 / 注册的重点按钮 - 空状态里的引导按钮 不太适合: - 后台系统的一堆工具按钮 - 危险操作按钮 - 表格里的小按钮 - 需要极度克制的业务页面
这个小效果的核心就一句话:
用一张更宽的渐变背景,鼠标悬停时移动背景位置,再配合 transition 做出流动感。
你现在项目里的主按钮是偏克制,还是偏视觉吸引?如果你愿意折腾一点,可以把这个按钮换成你们品牌色试试,通常只改渐变里的 2 到 3 个颜色,就能马上变成自己的风格。