ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于layui的后台登录页响应式动画模板:从布局到性能优化全攻略

2026/8/31 15:50:42 拓冰建站 浏览量
基于layui的后台登录页响应式动画模板:从布局到性能优化全攻略 简介这是一份基于Layui前端框架打造的用户登录界面响应式动画模板面向Web开发初学者与中小型项目开发者解决登录页在多端设备上视觉统一、交互生动、代码可复用等实际问题。资源包共46个文件涵盖20个JavaScript脚本含jQuery、mockjax、Particleground等增强交互与动效的依赖、11个CSS样式文件含响应式布局、动画过渡、Layui定制主题、8张PNG/GIF/JPG图片资源如用户图标、锁形控件、星空背景等及SVG矢量元素整体压缩后仅290KB轻量易集成。已有1354人学习下载模板结构清晰HTML入口页完整调用Layui组件CSS分层管理基础样式与动画规则JS模块化处理表单验证、提示框动态弹出与粒子背景渲染。读者可直接部署运行快速掌握Layui表单封装、媒体查询适配、layer提示动画及轻量级视觉动效实现方案。 做了几年后台管理系统我越来越觉得登录页是个被低估的地方。用户打开系统的第一眼看到的就是它但绝大多数后台的登录页都是拿layui默认样式直接糊一个表单只有输入框加按钮半点设计感都没有。这篇文章我把自己沉淀的一套基于layui的用户登录界面响应式动画模板完整拆开讲一遍从页面结构、响应式适配、动画实现到实际踩坑适合正在用layui做后台、又不想在登录页上太寒碜的朋友。先说明一下这套模板不是那种花里胡哨的展示页面它要解决的问题很具体用纯layui jQuery CSS3实现一个开箱即用的登录页PC、平板、手机三个端都能正常用有适度的动画但不影响加载速度模板化的方式是改配置而不是改代码。1. 为什么单开一个登录页模板需求梳理与选型1.1 登录页在后台系统里的定位后台管理系统里登录页的优先级往往排在最后因为业务功能做不完谁有空管登录页。但实际情况是登录页决定了用户对这个系统的第一印象甚至决定了客户对你们团队专业度的判断。我见过不少系统功能做得不错登录页却停留在2010年的水平——纯白背景、居中的表单、一个蓝色按钮没有任何品牌信息。所以我做后台项目时通常会把登录页当成一个独立的小项目来对待。它不需要后端联调不需要复杂业务纯粹是前端的表达但恰恰因为简单反而值得打磨。我的目标很明确让登录页看起来像一个正经产品而不是一个内部工具。1.2 为什么选layui而不是Vue或Bootstrap这个模板是基于layui的理由很直接。很多后台系统本身就是用layui搭建的引入的依赖已经是现成的再单独为登录页上Vue或者React等于为一个表单页引入一整套路由、构建工具和node_modules成本和复杂度都上去了。layui自带了一套很舒服的CSS组件和JavaScript模块机制表单、按钮、提示层这些登录页必需的元素都有现成的只需要做定制而不是从零发明。而且layui的栅格在表单这一块虽然不常用但它的弹层和表单验证做得挺顺手适合后台场景。对比一下方案优点缺点适合场景layui依赖少、上手快、模块化、中文文档整体风格偏后台个性化需要覆盖已有layui后台项目Bootstrap组件丰富、生态大、响应式成熟样式偏通用要写大量覆盖新项目且无layui依赖VueElement表达式渲染、组件化需要构建链路登录页用不上前后端分离的新项目我测试下来对这个登录页模板来说layui是投入产出比最高的方案。1.3 拆解响应式动画模板三个关键词响应式三个字并不是让页面变窄就行而是要保证在1080P桌面屏、iPad横竖屏、手机竖屏三种典型场景下布局不散、按钮不挤、字体可读。这套模板没有用layui的栅格去做登录页而是用flex布局自定义容器原因后面会说。动画部分我控制在一个克制的范围内背景粒子缓慢移动表单进入时有轻微的位移动画输入框聚焦时有个下划线过渡按钮点击时有一个loading态。这些动画加起来不到2秒不会让人觉得在等待但质感提升非常明显。模板的意思是你拿到这份代码后不需要改结构逻辑只需要改一个配置对象和几个CSS变量就能把它换成自己系统的登录页。这个设计思路我会在最后一章详细展开。2. 页面结构搭建让布局先立住2.1 整体布局左品牌区 右表单区的思路桌面端常见的登录页布局有两种一种是所有内容居中的单一卡片另一种是左品牌区右表单区的分栏布局。我选了后者理由是分栏布局更容易做出高级感左边放品牌宣传、标语、动态背景右边放登录表单信息层次清晰也给动画留下了施展空间。布局的骨架用flex实现.login-wrapper { display: flex; min-height: 100vh; background: #fff; } .login-aside { flex: 1.6; position: relative; overflow: hidden; background: linear-gradient(135deg, #1e9fff 0%, #16b777 100%); display: flex; align-items: center; justify-content: center; } .login-main { flex: 1; display: flex; align-items: center; justify-content: center; padding: 40px; }注意min-height: 100vh而不是height: 100vh这是给移动端预留的一个坑位后面会细说。左边overflow: hidden是因为粒子动画canvas要覆盖整个品牌区不能让粒子溢出到表单区。2.2 基础HTML骨架与登录表单HTML结构分为外层容器、左侧品牌区、右侧登录区三块。左侧品牌区里面放一个品牌标题、一句副标题和canvas容器右侧放layui表单。div classlogin-wrapper div classlogin-aside canvas idbgCanvas/canvas div classbrand-content div classbrand-logoLOGO/div h1某某管理系统/h1 p让数据透出价值/p /div /div div classlogin-main div classlogin-form-card h2欢迎登录/h2 p classlogin-tip请输入您的账号信息/p form classlayui-form idloginForm lay-filterloginForm div classlayui-form-item div classlayui-input-wrap input typetext nameusername lay-verifyrequired placeholder请输入用户名 autocompleteusername classlayui-input / i classlayui-icon layui-icon-username/i /div /div div classlayui-form-item div classlayui-input-wrap input typepassword namepassword lay-verifyrequired|pass placeholder请输入密码 autocompletecurrent-password classlayui-input / i classlayui-icon layui-icon-password/i /div /div div classlogin-options input typecheckbox nameremember title记住我 lay-skinprimary checked / a hrefjavascript:; classlogin-forgot忘记密码/a /div button typesubmit classlayui-btn layui-btn-fluid login-btn lay-submit lay-filterloginSubmit登 录/button /form div classlogin-footer © 2024 某某科技 版权所有 /div /div /div /div我故意保留了layui的图标前缀因为最新版的layui依然用layui-icon-username这类图标名比手写SVG省事。左侧的canvas要放在品牌内容前面这样后面给品牌内容加z-index层级时不会被canvas盖住。2.3 layui表单模块的初始化与验证登录页的JS部分并不复杂用layui的form模块做表单渲染和验证用jQuery处理一些交互。核心初始化如下layui.use([form, layer], function () { var form layui.form; var layer layui.layer; // 自定义密码校验规则 form.verify({ pass: [/^\S{6,20}$/, 密码必须为6到20位非空白字符] }); // 登录提交 form.on(submit(loginSubmit), function (data) { var field data.field; var btn $(this); btn.addClass(layui-btn-disabled).attr(disabled, true); var originHtml btn.html(); btn.html(i classlayui-icon layui-icon-loading layui-anim-spin/i 登录中...); // 这里替换成真实接口请求 setTimeout(function () { btn.removeAttr(disabled).removeClass(layui-btn-disabled).html(originHtml); // 实际项目里根据返回结果跳转或提示 layer.msg(登录成功, { icon: 1 }); }, 2000); return false; // 阻止浏览器原生表单提交 }); });这里有个细节lay-submit监听器里return false是必须的否则表单会走原生的action提交页面会刷新。另外登录按钮的loading态不要随便用loading属性layui对按钮的disabled样式支持得更好。如果你不需要左侧品牌区直接把.login-aside那段删掉并把.login-main的flex: 1改成width: 100%布局就会变成居中的卡片模式这个模板的灵活性在这里。3. 响应式适配从桌面到手机的不变形方案3.1 栅格与flex换行的取舍layui自带栅格系统layui-row加layui-col-md6这些类名很多人会疑问为什么登录页不用它。原因很简单登录页不是数据密集型页面不需要12列栅格来编排内容用flex能更精确地控制两侧比例而且少了一层行列嵌套后面对移动端做隐藏和重排也更容易。栅格系统的标准用法是给内容区做卡片列表、表单行列对齐但登录页的两个大区块是左右分栏而不是多列并排这种情况flex的定义更直观。这个结论我在多个项目里验证过没有翻过车。3.2 三个断点的布局切换策略我按常见的三档断点来控制布局断点写法布局表现≥1024px默认样式左侧品牌区 右侧表单区768px ~ 1023pxmedia (max-width: 1023px)左侧品牌区压缩表单区适当加宽768pxmedia (max-width: 767px)隐藏左侧品牌区表单区全屏具体CSSmedia (max-width: 1023px) { .login-aside { flex: 1.2; } .login-main { flex: 1.4; padding: 30px; } } media (max-width: 767px) { .login-wrapper { flex-direction: column; background: #f7f8fa; } .login-aside { display: none; } .login-main { width: 100%; padding: 20px; min-height: 100vh; background: url(mobile-bg.jpg) no-repeat center / cover; } .login-form-card { width: 100%; max-width: 380px; padding: 32px 24px; background: rgba(255, 255, 255, 0.95); border-radius: 12px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08); } }移动端隐藏左侧品牌区后表单卡片加了一个半透明背景不然纯白表单区在手机上会很空。同时我把卡片加了圆角和阴影让它在浅灰背景上脱离出来。3.3 移动端适配中的细节处理移动端有几个容易忽视的细节值得专门提一下。第一个是viewport的设置。如果widthdevice-width没写对手机端会按980px的默认视口渲染整个页面被缩得很小。一定要在head里写meta nameviewport contentwidthdevice-width, initial-scale1.0第二个是表单控件在iOS上的默认样式。iOS Safari会给input加圆角和内阴影需要重置input, button { -webkit-appearance: none; appearance: none; border-radius: 0; }layui自己的input样式覆盖了一部分但保险起见还是显式声明比较好不然有些安卓浏览器也会显示怪异的样式。第三个是软键盘弹出时100vh的容器会被挤压。这个问题在iOS上尤其明显我后面会专门讲怎么处理。4. 动画实现从背景粒子到表单微交互4.1 背景Canvas粒子动画背景动画我用的是Canvas粒子连线效果粒子缓慢漂移当两个粒子距离小于一定阈值时画一条半透明线段形成网状的动态背景。这种效果在技术社区里很常见但它放在登录页左边确实能撑起品牌区的视觉重心。核心代码长这样var canvas document.getElementById(bgCanvas); var ctx canvas.getContext(2d); var particles []; var canvasW, canvasH; var config { count: 80, linkDistance: 140, speed: 0.3 }; function resizeCanvas() { canvasW canvas.width canvas.offsetWidth; canvasH canvas.height canvas.offsetHeight; } function createParticle() { return { x: Math.random() * canvasW, y: Math.random() * canvasH, vx: (Math.random() - 0.5) * config.speed, vy: (Math.random() - 0.5) * config.speed, r: Math.random() * 2 0.5 }; } function initParticles() { particles []; for (var i 0; i config.count; i) { particles.push(createParticle()); } } function draw() { ctx.clearRect(0, 0, canvasW, canvasH); // 画粒子点 for (var i 0; i particles.length; i) { var p particles[i]; p.x p.vx; p.y p.vy; if (p.x 0 || p.x canvasW) p.vx * -1; if (p.y 0 || p.y canvasH) p.vy * -1; ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); ctx.fillStyle rgba(255,255,255,0.7); ctx.fill(); } // 画连线 for (var m 0; m particles.length; m) { for (var n m 1; n particles.length; n) { var a particles[m], b particles[n]; var dx a.x - b.x; var dy a.y - b.y; var dist Math.sqrt(dx * dx dy * dy); if (dist config.linkDistance) { var alpha (1 - dist / config.linkDistance) * 0.5; ctx.strokeStyle rgba(255,255,255, alpha ); ctx.lineWidth 1; ctx.beginPath(); ctx.moveTo(a.x, a.y); ctx.lineTo(b.x, b.y); ctx.stroke(); } } } requestAnimationFrame(draw); } window.addEventListener(resize, function () { resizeCanvas(); initParticles(); }); resizeCanvas(); initParticles(); draw();粒子数量我测过80个在普通笔记本和手机上都很稳放到200个也不卡但没必要。真正影响性能的是粒子两两检测的O(n²)复杂度所以数量控制在合理范围比任何优化技巧都管用。如果你想减少运算量可以把小屏幕上的粒子数量降到40。背景是渐变加粒子颜色用白色透明度这样才能和主色调兼容。如果以后换主题色粒子不需要改。4.2 表单入场动画与时间序列表单卡片进场时我用了一个轻微的位移加淡入。关键点在于动画要和其他元素的时间错开品牌区先出表单区稍微延迟一点这样视觉上会有层次。.login-aside .brand-content { animation: fadeInLeft 0.6s ease-out both; } .login-form-card { animation: fadeInUp 0.6s ease-out 0.2s both; } keyframes fadeInLeft { from { opacity: 0; transform: translateX(-30px); } to { opacity: 1; transform: translateX(0); } } keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }both填充模式的意思是动画结束后保持最后一帧的状态避免闪烁。延迟0.2秒就是为了让两个动画有一种衔接感而不是同一时间出现。表单内部的元素也可以做细分动画比如标题先出现、输入框再出现、按钮最后出现但我不建议每个元素单独加动画会很碎。控制在两个大的层级就够了登录页要的是干净利落。4.3 输入框、按钮的微交互状态微交互方面我最满意的是输入框聚焦时的下划线过渡。layui的input自带focus边框变色但风格偏硬我把它改成了渐入的下划线效果.login-form-card .layui-input { border-width: 0 0 1px 0; background: transparent; border-radius: 0; padding-left: 0; transition: border-color 0.3s; } .login-form-card .layui-form-item { position: relative; } .login-form-card .layui-form-item::after { content: ; position: absolute; left: 0; bottom: 0; width: 0; height: 2px; background: #1e9fff; transition: width 0.3s ease; } .login-form-card .layui-form-item:focus-within::after { width: 100%; }这里用:focus-within可以用CSS实现不用额外监听JS事件。它的兼容性在现在的浏览器里已经足够好不需要担心。按钮的hover、active状态我也做了处理。layui默认按钮hover会变深色但登录页的按钮我希望它有一点微小的位移和阴影反馈.login-btn { height: 46px; font-size: 16px; border-radius: 6px; transition: transform 0.15s ease, box-shadow 0.15s ease; } .login-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(30, 159, 255, 0.35); } .login-btn:active { transform: translateY(0); box-shadow: none; }这种反馈让按钮看起来有按下的感觉成本极低但体验提升明显。4.4 动画的优雅降级动画不能成为性能负担。我准备了两个降级方案。第一个是prefers-reduced-motion媒体查询如果操作系统开启了减少动态效果就关闭动画media (prefers-reduced-motion: reduce) { .login-aside .brand-content, .login-form-card { animation: none; } .login-btn { transition: none; } }第二个是小屏幕设备直接把粒子动画关掉。移动端品牌区本来就隐藏了canvas不渲染所以这个降级其实针对的是小尺寸平板上还显示左侧品牌区的情况var reduceMotion window.matchMedia((prefers-reduced-motion: reduce)).matches; if (reduceMotion || canvas.offsetWidth 200) { // 只画一帧静态背景不启动动画 drawStatic(); return; }有一说一登录页动画在绝大多数设备上都不会卡但如果不加降级碰到那些老爷机就会从提升质感变成拖累体验。5. 踩坑记录一次真实的调试过程5.1 输入框自动填充导致的样式污染这个坑应该所有前端都遇到过。浏览器自动填充用户名和密码时会强制给input加一层黄色的背景而且你很难用普通的CSS选择器去覆盖尤其在Chrome上。我实际排查的过程是这样的页面在本地测试一切正常一放到测试环境用Chrome登录过一次后重新打开页面用户名和密码框就变成了淡黄色还带一个蓝色边框和整个页面的设计很不搭。网上常见的方案是给input加-webkit-box-shadow: inset 0 0 0 1000px #fff来盖住背景我试了确实有效但后来发现一个问题如果输入框本身是透明背景我这套模板的下划线风格强制改成白色反而引入一个白色色块更难看。我的最终方案是不追求完全去掉自动填充的默认行为而是把自动填充的颜色也纳入样式设计。在CSS里显式声明.login-form-card .layui-input:-webkit-autofill { -webkit-box-shadow: inset 0 0 0 1000px #f7f8fa !important; -webkit-text-fill-color: #333 !important; transition: background-color 9999s ease-in-out 0s; }背景色取页面的浅灰底色这样自动填充后看起来和正常输入状态非常接近不会突兀。5.2 iOS下100vh的视口跳动移动端Safari对100vh的处理和桌面端不一样它会忽略地址栏和底部工具栏的实际高度导致页面底部被截断或者滚动时跳动。这个问题在我用min-height: 100vh做wrapper时也出现过表现为iOS上输入框聚焦调起软键盘后页面底部被顶出一截。排查到最后问题不在软键盘而在100vh本身。iOS Safari的视口高度在地址栏展开和收起时是动态变化的100vh却始终以最大的视口高度计算所以页面会出现底部留白或者跳动。解决方案有两种任选一种或者组合都行/* 方案一用更小的视口单位 */ .login-wrapper { min-height: 100vh; min-height: 100dvh; } /* 方案二退回到固定定位布局 */ .login-wrapper { position: fixed; top: 0; right: 0; bottom: 0; left: 0; }100dvh是dynamic viewport height专门为解决这个问题设计的支持的浏览器已经很多但考虑到兼容性我用的是先写100vh再覆盖为100dvh的渐进增强写法。如果项目特别保守直接方案二也稳妥。5.3 layui复选框渲染和按钮loading的状态来回layui的checkbox用的是原生input加lay-skinprimary渲染后会在旁边生成一个i.layui-icon作为勾选图标。在表单里放记住我时初始加载动画期间复选框的图标可能还没渲染出来视觉上会闪一下。我调试后发现这是因为layui表单页里的复选框必须等form.render()之后才会出现图标。如果页面加载时动画还没执行完图标渲染就会晚一步视觉上就会从空白框变成勾选框。解决办法是让form.render()提前到页面可交互之前执行并且这个调用要在layui.use回调里layui.use([form], function () { form.render(); // ... });实际上layui自动渲染已经会处理但如果你修改过表单结构记得重新调用form.render(null, loginForm)来指定渲染filter为loginForm的区块不然可能会渲染出重复的图标。按钮loading态的一个细节是我见过有人用btn.attr(disabled, true)禁用按钮但layui的样式没有disabled属性对应的类导致按钮还能点。正确做法是同时加layui-btn-disabled类或者直接利用layui的layui-btn-disabled类名。我在模板里写的是两者都加这样点击事件和样式双重锁死。5.4 canvas动画在低端机上的性能控制粒子animation我一开始用了每帧都去绘制所有的粒子和连线在开发机上完全没问题。后来拿到一台老的安卓测试机打开登录页左侧品牌区有明显掉帧风扇都开始转。排查后发现两个问题一是canvas没有做resize防抖窗口一调整就连续触发initParticles()造成短暂的高频计算二是粒子连线的距离检测在任何设备上都跑满性能浪费在那些距离很远的粒子上。我的处理是在resize事件里加上防抖同时根据屏幕宽度动态调整粒子数量var resizeTimer; window.addEventListener(resize, function () { clearTimeout(resizeTimer); resizeTimer setTimeout(function () { resizeCanvas(); initParticles(); }, 200); }); function initParticles() { var scale canvasW 768 ? 0.5 : 1; var count Math.floor(config.count * scale); particles []; for (var i 0; i count; i) { particles.push(createParticle()); } }另外画连线时可以先做一个简单的距离判断如果dx或者dy的绝对值已经大于阈值就直接跳过连线的计算这样能省下一半的运算量。这个属于老生常谈的优化但放在登录页这种低频页面里够用了。6. 把模板变成配置定制与扩展6.1 模板目录与文件职责这套模板的目录结构很简单没有采用构建工具因为登录页是静态页面直接拿来就能跑login-template/ ├── index.html ├── assets/ │ ├── css/ │ │ ├── login.css │ │ └── login-particles.js │ ├── js/ │ │ ├── login.js │ │ └── login-config.js │ └── img/ │ └── mobile-bg.jpg └── layui/ ├── css/ │ └── layui.css └── layui.jslogin.css放登录页私有样式login-config.js放可配置项login.js放逻辑。layui目录保持官方原有结构方便后续升级。实际使用的时候只要把layui目录换成你自己项目里的或者直接在已有后台系统的静态资源目录里引用layui就可以只拷贝index.html和assets两部分。这样对已有项目非常友好。6.2 全局主题色配置这套模板的主题色我用CSS变量管理放在:root里:root { --brand-color: #1e9fff; --brand-color-dark: #0078d7; --brand-gradient-start: #1e9fff; --brand-gradient-end: #16b777; --form-bg: #ffffff; --text-color: #333333; }后续引用处统一使用var比如左侧品牌区背景.login-aside { background: linear-gradient(135deg, var(--brand-gradient-start) 0%, var(--brand-gradient-end) 100%); }这样换主题色只需要改:root里的几个值不用在CSS里满处找色值。CSS变量本文还有配套的精品资源点击获取