核心内容摘要
97人人做人人乐:从网络社区到文化符号的传奇
白前端必学用CSS hover实现左右开门特效附详细拆解小白前端必学用CSS hover实现左右开门特效附详细拆解刚入门前端那会儿我像个土包子进城看到人家网站上鼠标轻轻一划——“唰”两扇门往两边一开里面露出个立即购买按钮我当场就跪了。
这啥啊这是变形金刚吗当时我心里想这得用多复杂的JavaScript才能实现啊说不定还要上WebGL后来翻源码一看好家伙就几行CSS我当时那个世界观崩塌的感觉就跟发现魔术原来是块布后面藏了个人似的。
所以今天咱不搞那些虚的就手把手把这层窗户纸捅破。
你会发现这玩意儿看似高大上实际上…确实也挺简单的但里面坑不少我踩过的屎今天全给你们标记出来你们绕着走就行。
先搭个架子别想太多HTML结构这块我知道你们学校老师或者什么最佳实践文章告诉你要语义化要用article、section、header这些标签语义化确实重要但那是对内容而言。
做特效的时候你硬要套语义化标签就像给挖掘机贴隐形车衣——没必要真的。
最实在的结构就长这样divclassdoor-containerdivclassdoor-left/divdivclassdoor-right/divdivclassdoor-contenth2惊喜/h2button点我领红包/button/div/div看见没一个爹door-container带仨儿子左右俩门板中间藏内容。
你别跟我抬杠说哎呀这是不是应该用dialog标签啊用div咋了IE都死了你还怕啥当然你要是非要显得专业点也可以这么写articleclassdoor-containerdivclassdoor-leftrolepresentation/divdivclassdoor-rightrolepresentation/divsectionclassdoor-contenth2惊喜/h2button点我领红包/button/section/article加几个role属性假装考虑一下无障碍心里安慰一下行够意思了。
但说实话面试的时候你把这段代码拿出来说我用纯CSS实现了双向门扇动画面试官眼睛会亮的谁管你用div还是article。
这里有个小细节左右门板的顺序其实有讲究。
我习惯把door-left放前面door-right放后面因为后面要写position: absolute层叠顺序是后来居上当然你也可以用z-index控制但少写个属性不香吗不过如果你要在门上加一些前后遮挡的效果可能还是得用z-index这个后面再说。
CSS这三大金刚少一个都翻车现在到了核心环节。
很多教程上来就给你扔代码也不解释为啥这么写搞得人云里雾里。
今天咱把transform、transition、overflow这哥仨掰开揉碎讲。
首先是transform这玩意儿就是动画的 engine。
你要让左门往左飞右门往右飞靠的是translateX。
但注意啊这里有个超级容易搞混的点百分比是相对于谁是相对于门板自身的宽度不是你爹的宽度也不是屏幕宽度。
.door-container{position:relative;width:300px;height:400px;overflow:hidden;/* 关键拆迁现场遮羞布 */}.door-left, .door-right{position:absolute;top:0;width:50%;height:100%;background:linear-gradient(90deg,#8B4513,#A0522D);/* 假装是木门 */transition:transform
6scubic-bezier(
4,0,
2,
;/* 丝滑的秘密 */}.door-left{left:0;transform-origin:left;/* 这行先记着后面3D效果要用 */}.door-right{right:0;transform-origin:right;}/* 重点来了hover父容器不是hover门 */.door-container:hover .door-left{transform:translateX(-100%);}.door-container:hover .door-right{transform:translateX(100%);}看见overflow: hidden没这玩意儿就是防止门飞出去之后还能看见。
我第一次写的时候忘了加这个结果鼠标移上去两块门板飞到屏幕外面去了跟被炸弹炸飞了一样那场面堪称拆迁现场直播。
加上overflow: hidden之后超出容器的部分就被裁掉了看起来就像真的往墙里面缩进去了。
transition这里我用的
6s这个时间得慢慢调。
太快了吧像抽搐用户还没反应过来呢门开了又关太慢了吧像你家网速卡了用户等不及直接AltF4了。
4s到
8s之间是比较安全的区间具体看感觉。
那个cubic-bezier是我后加的先不管后面讲缓动函数的时候再吹。
hover的坑90%的人都踩过现在我必须严肃地警告你们一个坑这个坑我踩过我同事踩过我面试的候选人也踩过堪称CSS门的百慕大三角。
很多人直觉上会这么写/* 千万别这么写 */.door-left:hover{transform:translateX(-100%);}看起来逻辑很通顺对吧鼠标 hover 左门左门打开。
但是你试试鼠标稍微移快点或者门刚开始动鼠标就离开门板区域了——啪门关了然后再开再关抽搐效果达成。
用户体验稀碎。
正确的姿势必须是 hover 父容器也就是那个door-container。
因为门板在移动的时候鼠标相对于门板的位置在变但相对于父容器的位置是稳定的只要你鼠标还在那个区域晃悠。
/* 正确的打开方式 */.door-container:hover .door-left{transform:translateX(-100%);}.door-container:hover .door-right{transform:translateX(100%);}这里用到了 CSS 选择器的嵌套关系表示当父容器被 hover 时里面的子元素应用什么样式。
这个逻辑要想清楚不然你调试半天发现门不听话还以为是浏览器 bug 呢。
还有一个更隐蔽的坑如果你的门里面有点击按钮你要考虑门打开之后鼠标移开门关了但用户想点按钮怎么办这时候你可能需要改一下逻辑或者把按钮放在父容器 hover 状态下也能保持门打开… 算了这个属于进阶需求先把基础搞定再说。
方向别搞反了不然门会打架translateX的正负号我第一次写的时候搞反了左门写100%右门写-100%结果鼠标一上去两扇门哐当一声撞在一起然后因为都挤在中间谁也不让谁那画面跟俩胖子抢地铁座位似的。
坐标系要搞清楚translateX(-100%)是往左走translateX(100%)是往右走。
左门在左边要打开就得往左缩所以是负的右门在右边打开往右缩所以是正的。
但是等等如果你的左门不是left: 0而是right: 50%定位的那方向可能就不一样了。
不过我们一般都用left和right直接定位到两边所以记住左门负右门正。
/* 来个带视觉差的版本右门稍微慢点 */.door-container:hover .door-left{transform:translateX(-100%);transition-delay:0s;/* 左门先动 */}.door-container:hover .door-right{transform:translateX(100%);transition-delay:
1s;/* 右门慢半拍 */}看见transition-delay没这就是节奏感。
就像你走路左右脚不是同时落地的有个时间差。
右门慢
1秒打开看起来就像左门带着右门走或者像那种豪华车的电吸门有个先后顺序。
性能优化别用 left 和 top这是新手村大忌我见过有人这么写动画/* 这是错误示范千万别学 */.door-left{left:0;transition:left
6s;/* 大No特No */}.door-container:hover .door-left{left:-50%;/* 用left改位置 */}这么写功能上也能跑但是性能炸裂。
left、top、width、height这些属性一变浏览器要重新计算布局reflow然后重绘repaint像我这老年机配置风扇直接起飞页面卡成PPT。
transform和opacity这俩属性是浏览器亲儿子它们的变化不会触发重排直接走 GPU 加速丝滑得能拍德芙广告。
所以动画只用这俩属性记住没还有一个will-change属性这叫预先告诉浏览器我要变了.door-left, .door-right{will-change:transform;}加上这个浏览器会提前给这俩元素分配 GPU 资源动画开始前就做好准备响应更快。
但是别滥用你给整个页面都加will-change浏览器会疯的内存直接爆掉。
只在确实要动画的元素上加而且动画结束后最好移除虽然这点在hover场景下不太好操作知道有这么回事就行。
兼容性IE 已经进博物馆了说到兼容性我以前做项目还要考虑 IE9那个痛苦啊CSS3 动画得用 jQuery 模拟一坨 polyfill 代码性能稀烂。
现在好了IE 都入土为安了Edge 都换 Chromium 内核了transform和transition的兼容性可以说是全民普及。
Chrome、Firefox、Safari、Edge不管是桌面端还是移动端都支持得贼好。
你要是真碰到那种必须用 IE 的客户… 我建议你劝他换电脑真的为了世界和平。
或者你就给他做个降级方案IE 下直接显示内容不玩开门特效了反正 IE 用户估计也没见过世面不觉得缺少了什么。
移动端要注意一点有些老版本的 Android WebView 可能对transform的 3D 变形的支持有问题但我们这是 2D 的translateX放心用。
另外 iOS Safari 的hover效果有点迷因为那是触屏设备没有鼠标指针悬停的概念所以移动端这个效果基本没用得用click或者touch事件来触发。
不过我们今天只聊桌面端的 hover 效果。
调试技巧F12 是你的显微镜写动画的时候最烦的就是鼠标移来移去测试。
其实 Chrome DevTools 有个神器你可以手动给元素强制加上:hover状态。
操作步骤F12 打开控制台点左上角那个鼠标箭头图标元素选择器选中你的door-container然后在 Styles 面板右边有个:hov按钮点它勾选:hover这样元素就会保持 hover 状态你可以慢慢调 CSS看效果。
调transition-duration的时候我建议你从
3s开始慢慢往上加。
3s感觉像闪电侠开门1s像树懒开门找到那个刚刚好的点。
我一般都是
5s到
6s看起来比较优雅。
还有那个缓动函数cubic-bezier默认是ease你可以试试cubic-bezier(
68, -
55,
27,
1.
这叫回弹效果门开到最后会稍微回弹一下像有弹簧一样显得特别 Q 弹。
还有cubic-bezier(
25,
1,
25,
1.
这种开门速度先快后慢像高档车的电动门。
/* 回弹效果像果冻 */.door-left, .door-right{transition:transform
6scubic-bezier(
68,-
55,
27,
1.
;}/* 或者这种优雅慢停 */.door-container.elegant .door-left, .door-container.elegant .door-right{transition:transform
8scubic-bezier(
25,
1,
25,
;}加料让它更带感基础版本搞定之后咱们开始加戏。
首先门后面应该有内容啊不然开完是个空白用户一脸懵逼。
divclassdoor-containerdivclassdoor-left/divdivclassdoor-right/divdivclassdoor-contentimgsrcgift.jpgalt礼物!-- 假装有图 --h3恭喜你/h3button领取奖励/button/div/div.door-content{position:absolute;top:0;left:0;width:100%;height:100%;display:flex;flex-direction:column;justify-content:center;align-items:center;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);z-index:-1;/* 躲在门后面 */}/* 门上加个阴影增加立体感 */.door-left{left:0;background:linear-gradient(90deg,#8B4513 0%,#A0522D 100%);box-shadow:5px 0 15pxrgba(0,0,0,
0.
;/* 右侧阴影 */}.door-right{right:0;background:linear-gradient(90deg,#A0522D 0%,#8B4513 100%);box-shadow:-5px 0 15pxrgba(0,0,0,
0.
;/* 左侧阴影 */}看见z-index: -1没这会把内容层藏到门板后面。
box-shadow给门板加阴影看起来就像真的有两块厚木板一样。
再来个骚操作开门后自动聚焦按钮。
这需要一点 JS但用户体验直接起飞divclassdoor-containeridmagicDoordivclassdoor-left/divdivclassdoor-right/divdivclassdoor-contentbuttonidsurpriseBtn点我有惊喜/button/div/divscriptconstdoordocument.getElementById(magicDoor);constbtndocument.getElementById(surpriseBtn);door.addEventListener(mouseenter,(){setTimeout((){btn.focus();// 甚至可以加点音效// new Audio(door-creak.mp
.play().catch(e console.log(音效被拦截了));},
;// 等门开一半再聚焦});door.addEventListener(mouseleave,(){btn.blur();// 鼠标走了失去焦点});/script这段代码的意思就是鼠标移上去等门开了300ms 后自动把焦点移到按钮上键盘用户可以直接回车点击鼠标用户也能看到按钮有个聚焦状态比如一圈蓝边或者发光效果。
这叫细节你简历上写注重用户体验这就是证据。
还有更高级的3D 开门效果像真的门绕着门轴转一样。
这需要rotateY.door-container-3d{perspective:1000px;/* 3D 视角深度 */}.door-left-3d{left:0;transform-origin:left center;/* 旋转轴在左边 */transition:transform
8s ease;}.door-right-3d{right:0;transform-origin:right center;/* 旋转轴在右边 */transition:transform
8s ease;}.door-container-3d:hover .door-left-3d{transform:rotateY(-110deg);/* 往左后方转 */}.door-container-3d:hover .door-right-3d{transform:rotateY(110deg);/* 往右后方转 */}perspective属性必须在父容器上加给子元素创造 3D 空间。
transform-origin设置旋转的轴心左门绕左边转右门绕右边转rotateY是绕 Y 轴旋转Y 轴是垂直的所以是左右转。
110deg比90deg多一点这样能看到门的厚度侧面更像真门。
举一反三这套组合拳能打遍天下你今天学会了左右开门明天遇到上下卷帘门怎么办斜着切开的怎么办圆形展开的怎么办其实底层逻辑都是一套遮罩 位移。
上下版本.door-top{top:0;transform:translateY(-100%);}.door-bottom{bottom:0;transform:translateY(100%);}斜切版本用skew或者rotate.door-container:hover .door-left-skew{transform:translateX(-100%)skewY(10deg);}圆形展开用clip-path或者border-radius动画.door-content-circle{clip-path:circle(0% at 50% 50%);transition:clip-path
6s ease;}.door-container:hover .door-content-circle{clip-path:circle(150% at 50% 50%);}看见没都是先藏起来overflow: hidden或者clip-path然后动起来transform最后别露馅确保动画元素在容器内或者背景色盖住。
吃透这套逻辑特效库都不用装自己手写更轻量想怎么改怎么改。
最后提醒特效是佐料不是主食我得跟你们掏心窝子说几句。
这个效果确实酷但千万别在生产环境给每个按钮都加这个。
想象一下用户鼠标在页面上划拉一下开了十扇门以为你网页中病毒了或者这是什么恐怖游戏。
特效是为了突出重点内容的比如某个重要的 CTACall To Action或者隐藏优惠券或者惊喜礼物。
而且要考虑可访问性a11y。
键盘用户没法 hover你得确保他们能用 Tab 键聚焦到容器时也能触发动画或者直接用 JS 监听focus事件。
动画prefers-reduced-motion也得考虑有些用户开了系统设置减少动画你得尊重人家media(prefers-reduced-motion:reduce){.door-left, .door-right{transition:none;/* 直接瞬间打开或者干脆显示内容 */transform:none;opacity:0;/* 或者透明度变化比移动温和 */}}还有别在移动端强行用 hover 效果那地方只有触摸没有悬停。
你可以用:active或者 JS 的touchstart来模拟但体验不一样慎重。
结语写代码这事儿吧有时候就隔着一层窗户纸。
今天咱们把这层纸捅破了你会发现左右开门不过就是两个 div 往两边跑。
但魔鬼在细节里——hover 时机对不对、性能优没优化、有没有考虑特殊用户、动画节奏舒不舒服这些才是区分能跑和好用的关键。
下次面试官问你做过什么有趣的交互你就可以把这个效果拿出来从 HTML 结构讲到性能优化从兼容性聊到可访问性顺便吐槽一下你第一次把门方向搞反的尴尬经历。
这比背八股文有意思多了真的。
代码拿去用坑我替你们踩过了。
要是你还搞出了什么更骚的变种比如带物理引擎的、能根据鼠标速度调整开门速度的… 发给我看看我也学习学习。
毕竟前端这行活到老学到老明天可能就有新属性出来让这效果更简单呢。
欢迎来到我的博客很高兴能够在这里和您见面希望您在这里可以感受到一份轻松愉快的氛围不仅可以获得有趣的内容和知识也可以畅所欲言、分享您的想法和见解。
推荐DTcode7的博客首页。
一个做过前端开发的产品经理经历过睿智产品的折磨导致脱发之后励志要翻身农奴把歌唱一边打入敌人内部一边持续提升自己为我们广大开发同胞谋福祉坚决抵制睿智产品折磨我们码农兄弟专栏系列点击解锁学习路线(点击解锁知识定位《微信小程序相关博客》持续更新中~结合微信官方原生框架、uniapp等小程序框架记录请求、封装、tabbar、UI组件的学习记录和使用技巧等《AIGC相关博客》持续更新中~AIGC、AI生产力工具的介绍例如stable diffusion这种的AI绘画工具安装、使用、技巧等
总结《HTML网站开发相关》《前端基础入门三大核心之html相关博客》前端基础入门三大核心之html板块的内容入坑前端或者辅助学习的必看知识《前端基础入门三大核心之JS相关博客》前端JS是JavaScript语言在网页开发中的应用负责实现交互效果和动态内容。
它与HTML和CSS并称前端三剑客共同构建用户界面。
通过操作DOM元素、响应事件、发起网络请求等JS使页面能够响应用户行为实现数据动态展示和页面流畅跳转是现代Web开发的核心《前端基础入门三大核心之CSS相关博客》介绍前端开发中遇到的CSS疑问和各种奇妙的CSS语法同时收集精美的CSS效果代码用来丰富你的web网页《canvas绘图相关博客》Canvas是HTML5中用于绘制图形的元素通过JavaScript及其提供的绘图API开发者可以在网页上绘制出各种复杂的图形、动画和图像效果。
Canvas提供了高度的灵活性和控制力使得前端绘图技术更加丰富和多样化《Vue实战相关博客》持续更新中~详细
总结了常用UI库elementUI的使用技巧以及Vue的学习之旅《python相关博客》持续更新中~Python简洁易学的编程语言强大到足以应对各种应用场景是编程新手的理想选择也是专业人士的得力工具《sql数据库相关博客》持续更新中~SQL数据库高效管理数据的利器学会SQL轻松驾驭结构化数据解锁数据分析与挖掘的无限可能《算法系列相关博客》持续更新中~算法与数据结构学习
总结通过JS来编写处理复杂有趣的算法问题提升你的技术思维《IT信息技术相关博客》持续更新中~作为信息化人员所需要掌握的底层技术涉及软件开发、网络建设、系统维护等领域的知识《信息化人员基础技能知识相关博客》无论你是开发、产品、实施、经理只要是从事信息化相关行业的人员都应该掌握这些信息化的基础知识可以不精通但是一定要了解避免日常工作中贻笑大方《信息化技能面试宝典相关博客》涉及信息化相关工作基础知识和面试技巧提升自我能力与面试通过率扩展知识面《前端开发习惯与小技巧相关博客》持续更新中~罗列常用的开发工具使用技巧,如 Vscode快捷键操作、Git、CMD、游览器控制台等《photoshop相关博客》持续更新中~基础的PS学习记录含括PPI与DPI、物理像素dp、逻辑像素dip、矢量图和位图以及帧动画等的学习
总结日常开发办公生产【实用工具】分享相关博客》持续更新中~分享介绍各种开发中、工作中、个人生产以及学习上的工具丰富阅历给大家提供处理事情的更多角度学习了解更多的便利工具如Fiddler抓包、办公快捷键、虚拟机VMware等工具吾辈才疏学浅摹写之作恐有瑕疵。
望诸君海涵赐教。
望轻喷嘤嘤嘤非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。
愿斯文对汝有所裨益纵其简陋未及渊博亦足以略尽绵薄之力。
倘若尚存阙漏敬请不吝斧正俾便精进