ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【每天一个CSS | Day08】整排按钮被鼠标吸走的磁吸导航

【每天一个CSS | Day08】整排按钮被鼠标吸走的磁吸导航 写在前面视觉系周昨天收官从今天起进入交互系周。前七天做的都是“看着好看”的效果——光、像素、立体、插画。它们有一个共同点你不碰它它就在那里自顾自地演。从今天开始我们要做“会回应你”的效果。第一篇是最经典的交互感之一磁吸导航。鼠标悬停任意一颗按钮它带3D倾角弹起、点亮其余四颗一起缩小、降饱和“让位”——整条导航像被鼠标“吸”住。听起来需要实时鼠标坐标计算是JS的活儿。但今天要用纯CSS做出90%的观感。核心只有一条兄弟选择器 一组CSS变量。一、先看效果深色房间里一条胶囊导航五颗按钮鼠标扫过时被指到的按钮带3D倾角向上弹起、背景变亮、文字变白、底部多一道光晕其余四颗一起缩小、降饱和度、变暗——像往后退了一步按钮的倾角是按位置预设的最左边那颗往右倾14°最右边那颗往左倾14°中间那颗只往前压视觉上就像每颗按钮都被“吸”向指针所在的位置鼠标还没碰到整排已经在动。怎么跑起来新建一个demo.html把下面第二节的完整代码粘进去双击用浏览器打开截图党提示效果最佳时刻是鼠标悬停在第二颗按钮上——一颗凸起、四颗让位的瞬间。建议按F11全屏后截图或者录4秒GIF让鼠标从左到右缓缓扫过整排观感更完整。二、完整代码复制即用!DOCTYPEhtmlhtmllangzh-CNheadmetacharsetUTF-8metanameviewportcontentwidthdevice-width, initial-scale1.0titleDay 08 · 磁吸导航整排按钮被鼠标吸走/titlestyle*{margin:0;padding:0;box-sizing:border-box;}html, body{height:100%;}body{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:60px;overflow:hidden;background:#0d1117;font-family:PingFang SC,sans-serif;}.head{text-align:center;color:#e6edf3;}.head h1{font-size:22px;letter-spacing:.3em;font-weight:600;}.head p{margin-top:10px;font:400 11px/1SF Mono,Consolas,monospace;letter-spacing:.3em;color:#5b6878;}/* —— 磁吸导航容器给透视按钮各自带预设倾角 —— */.nav{display:flex;gap:8px;padding:12px;border-radius:20px;background:#141a22;border:1px solidrgba(255,255,255,.06);perspective:600px;}.btn{display:flex;align-items:center;gap:10px;padding:16px 22px;border:1px solidrgba(255,255,255,.05);border-radius:14px;cursor:pointer;background:#1b232e;color:#9fb0c3;font-size:13px;letter-spacing:.14em;transition:transform .28scubic-bezier(.34,1.56,.64,1),background .28s,color .28s,box-shadow .28s,opacity .28s,filter .28s;}.btn i{width:8px;height:8px;border-radius:50%;background:var(--c,#7ab8ff);}.btn:hover{transform:perspective(400px)rotateX(var(--rx,0deg))rotateY(var(--ry,0deg))translateY(-8px)scale(1.12);background:#243044;color:#fff;box-shadow:0 18px 30pxrgba(0,0,0,.5),0 0 24pxrgba(122,184,255,.12);}/* —— 磁吸感的核心hover 一颗其余整体「让位」—— */.nav:hover .btn:not(:hover){transform:scale(.88);opacity:.55;filter:saturate(.5)brightness(.8);}.b1{--c:#7fe3d2;--ry:14deg;--rx:-4deg;}.b2{--c:#b9a7ff;--ry:7deg;--rx:-9deg;}.b3{--c:#ffc2cf;--ry:0deg;--rx:-13deg;}.b4{--c:#ffd479;--ry:-7deg;--rx:-9deg;}.b5{--c:#7ab8ff;--ry:-14deg;--rx:-4deg;}.hint{font:400 10px/1SF Mono,Consolas,monospace;letter-spacing:.3em;color:#3d4a5a;}.tag{position:fixed;right:18px;bottom:14px;font:400 10px/1SF Mono,Consolas,monospace;letter-spacing:.28em;color:rgba(159,176,195,.3);}/style/headbodydivclassheadh1MAGNETIC NAV/h1pHOVER A BUTTON · THE ROW FOLLOWS/p/divdivclassnavbuttonclassbtn b1i/iHOME/buttonbuttonclassbtn b2i/iWORK/buttonbuttonclassbtn b3i/iLAB/buttonbuttonclassbtn b4i/iBLOG/buttonbuttonclassbtn b5i/iINFO/button/divdivclasshintZERO JS · PURE CSS MAGNETISM/divdivclasstag每天一个惊艳 CSS · DAY 08/div/body/html三、三个核心技法拆解代码不长但三个点层层递进——每一个单独拿出来都能用在别的地方。技法1让位——一条兄弟选择器制造「整体被吸走」磁吸感的真正来源不是hover的那颗按钮而是其余按钮的集体反应。如果只有被 hover 的那颗弹起其余四颗纹丝不动观感是“普通按钮hover效果”。真正让它变成“磁吸”的是这一行.nav:hover .btn:not(:hover){transform:scale(.88);opacity:.55;filter:saturate(.5)brightness(.8);}逐层读一遍部分意思.nav:hover鼠标在这条导航的任意位置包括按钮之间的间隙.btn:not(:hover)其中没被指到的按钮合起来“容器被hover但自己不是主角”的所有按钮为什么要加.nav:hover这一层这是这条选择器唯一容易写错的地方/* ❌ 少了容器约束所有没被 hover 的按钮永远缩小 */.btn:not(:hover){transform:scale(.88);}/* ✅ 有容器约束只有“导航被 hover 时”才触发让位 */.nav:hover .btn:not(:hover){transform:scale(.88);}少了.nav:hover前缀页面一打开所有没被鼠标指到的按钮就会全部缩小。观感立刻毁掉——你想要的“整排被吸走”变成了“页面默认就是一堆缩小的按钮”。这条选择器是纯CSS交互的通用利器画廊hover悬停一张其余半透明卡片墙悬停一张其余往后退标签云悬停一枚其余变淡Tab 栏悬停一个其余降级一个模式套到哪里都成立。技法2按位置预设倾角模拟「朝鼠标倾斜」真正的“朝鼠标方向倾斜”需要实时获取鼠标坐标那是JS的活儿。但我们退一步想按钮在整排里的位置是固定的。最左边的按钮鼠标肯定从右边靠近它最右边的按钮鼠标肯定从左边靠近它中间的按钮鼠标从正前方靠近它所以给每颗按钮预设一组倾角就够了.b1{--ry:14deg;--rx:-4deg;}/* 最左向右倾微微前压 */.b2{--ry:7deg;--rx:-9deg;}/* 次左向右倾 */.b3{--ry:0deg;--rx:-13deg;}/* 中间只前压不左右倾 */.b4{--ry:-7deg;--rx:-9deg;}/* 次右向左倾 */.b5{--ry:-14deg;--rx:-4deg;}/* 最右向左倾 */hover 时统一启用.btn:hover{transform:perspective(400px)rotateX(var(--rx,0deg))rotateY(var(--ry,0deg))translateY(-8px)scale(1.12);}为什么用CSS变量因为同样的transform公式不同的按钮用不同的数值。如果不用变量每颗按钮都要写一遍完整的transform——5颗按钮就是5份重复代码改一个参数要改5处。用变量之后公式写一次.btn:hover里数值分别给.b1~.b5里改一颗只改一行这是CSS变量最典型的用法把“公式”和“参数”解耦。观感验证把鼠标从左往右缓缓扫过你会发现每颗按钮都像“朝着鼠标的方向微微转了一下”。和真·实时计算几乎没差成本为零。技法 3弹性缓动 磁铁的「回弹」transition的缓动函数用这条transition:transform .28scubic-bezier(.34,1.56,.64,1),background .28s,color .28s,box-shadow .28s,opacity .28s,filter .28s;重点是那串cubic-bezier(.34, 1.56, .64, 1)。cubic-bezier(x1, y1, x2, y2)里的第二个参数y1 1.56超过了1——这代表“动画会冲过目标位置再弹回来”。普通ease曲线只会平滑地滑到终点像橡皮筋慢慢收紧过冲曲线会先冲过头、再回弹像真的被吸铁吸过去、碰一下、顿住。磁吸的“吸”劲儿一半来自位移动画另一半就来自这个过冲。为什么是.28s太短 0.15s→ 感觉像“啪”地闪现没有“吸”的过程太长 0.5s→ 鼠标已经移开了按钮还在慢慢弹反馈迟钝.28s是“有过程但不拖沓”的甜点位和人手移动的自然节奏契合。注意过冲缓动不能用在位移过大的场景。/* ❌ 位移太大 过冲 弹得很夸张、像故障 */transform:translateY(-30px)scale(1.5);/* ✅ 磁吸的位移控制在 10px 内最自然 */transform:translateY(-8px)scale(1.12);位移越大过冲幅度按比例放大。translateY(-8px)配过冲正好换成-30px就会弹出“果冻感”。四、踩坑位我全踩过你直接避①:not(:hover)忘了限定在容器hover之下/* ❌ 页面一打开所有没被指到的按钮全部缩小 */.btn:not(:hover){transform:scale(.88);}/* ✅ 必须写全「容器 hover 自己不是主角」 */.nav:hover .btn:not(:hover){transform:scale(.88);}**这是这条选择器唯一容易写错的地方。**少了.nav:hover前缀效果就从“整排被吸走”变成“默认就是一堆缩小的按钮”。记住口诀先声明“场景”容器被hover再声明“角色”自己不是主角。②perspective放在按钮自己身上/* ❌ 每颗按钮自转自看5 颗各自透视、没有统一灭点 */.btn:hover{transform:perspective(400px)rotateY(...);}/* ✅ 透视给容器按钮只写旋转 */.nav{perspective:600px;}.btn:hover{transform:rotateX(...)rotateY(...)translateY(-8px)scale(1.12);}perspective写在容器上所有子元素共享同一个“消失点”——就像整个场景在镜头前而不是每颗按钮自己拿一台相机。如果写在按钮上每颗按钮的透视都是“自己相对自己”的——左边那颗和右边那颗的倾角看起来一样磁吸的“朝不同方向倾”就消失了。但要注意我这里在.btn:hover里还写了一次perspective(400px)。这是“内联透视”写法——为了和rotateX/rotateY一起组成一个独立的3D上下文效果更可控。两种写法都能用但不要混容器给perspective是一种风格元素内部perspective()函数是另一种风格。③transition只写transform/* ❌ 只有位移是平滑的颜色和阴影突变 */.btn{transition:transform .28s;}/* ✅ 所有参与变化的属性都列进 transition */.btn{transition:transform .28scubic-bezier(.34,1.56,.64,1),background .28s,color .28s,box-shadow .28s,opacity .28s,filter .28s;}磁吸按钮hover时同时变了6个属性transform、background、color、box-shadow、opacity、filter。只有transform走transition其余五样瞬间切换——瞬间切换的属性和平滑过渡的属性混在一起“吸”的错觉就露馅了按钮是飘上去了但背景“啪”地一闪很出戏。通用心法*一个元素hover时改了几个属性transition里就写几个属性。*宁可多写不可漏写。④ 过冲缓动用在位移过大的场景/* ❌ 位移-30px 过冲曲线 弹得很夸张、像果冻 */transform:translateY(-30px)scale(1.4);/* ✅ 位移控制在10px内 */transform:translateY(-8px)scale(1.12);过冲幅度和位移幅度成正比。位移越大回弹越夸张。磁吸这种需要“克制高级感”的效果位移10px以内最自然。如果确实需要大位移就把过冲缓动换成普通ease-out或者把cubic-bezier的第二个参数调到1.2左右轻微过冲。五、变式挑战10–30分钟动手才有收获任务升级成真·逐像素磁吸。现在这版是“预设倾角”——每颗按钮的倾角是写死的。进阶版让鼠标在按钮内部移动时倾角实时变化。指针移到左上角按钮往左上倾移到右下角往右下倾。需要6行JS本专栏第一次真正的“半开戒”document.querySelectorAll(.btn).forEach(btn{btn.addEventListener(pointermove,e{constrbtn.getBoundingClientRect();btn.style.setProperty(--ry,((e.clientX-r.left)/r.width-.5)*24deg);btn.style.setProperty(--rx,((.5-(e.clientY-r.top)/r.height)*18)deg);});btn.addEventListener(pointerleave,(){btn.style.setProperty(--ry,0deg);btn.style.setProperty(--rx,0deg);});});注意CSS一行都不用改。transform里用的还是var(--ry)和var(--rx)只是这两个变量的值从“预设”变成了“实时计算”。这就是CSS变量做交互接口的好处CSS负责“怎么用”transform公式、transition曲线JS负责“给什么值”鼠标坐标换算两者解耦各司其职做完你会惊讶加了JS之后那6行代码竟然这么短——因为CSS已经把90%的活儿干完了。其他变式方向选做换成卡片墙把5颗按钮换成5张产品卡hover时主角放大、其余后退就是一个磁吸画廊加“高光扫过”hover时在被指到的按钮上叠一层斜向白色渐变::before做“光扫过去”的质感反向磁吸让非hover的按钮朝主角方向移动translateX而不是缩小——“吸附”的物理感更直白六、小结今天这一篇里藏着5个通用技能点技能适用场景.parent:hover .child:not(:hover)让位模式画廊、卡片墙、Tab栏、标签云CSS变量做“公式 参数”解耦所有“同款式、不同数值”的组件按位置预设参数模拟实时计算所有“接近鼠标即响应”的效果cubic-bezier的y 1过冲缓动所有“吸住”“弹回”“果冻”质感容器统一perspective所有多元素3D场景最值得记住的两条①.parent:hover .child:not(:hover)是纯CSS交互的通用骨架。这条选择器让“某个元素被指到 → 其余元素让位”变得一行可达。它不挑元素类型从按钮到卡片到标签套到哪都成立。② CSS变量不只用来“存颜色”更用来“传参数”。今天用它存倾角Day03用它存楼高、色相Day04用它存月相延迟。它是CSS里唯一能把“公式”和“数值”分开写的工具——学会它重复代码就能直接砍掉一半。如果这一篇对你有帮助三连支持一下这个专栏 点赞 更新加速收藏 随时复制代码评论 你想看什么效果我排进日程。本专栏所有demo复制即用随便商用。目标更新不断更。
返回列表