☰
基于layui的后台登录页响应式动画模板:从布局到性能优化全攻略
2026/10/16 0:10:47 网站建设 项目流程

简介:这是一份基于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依赖
Vue+Element表达式渲染、组件化需要构建链路,登录页用不上前后端分离的新项目

我测试下来,对这个登录页模板来说,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 class="login-wrapper"> <div class="login-aside"> <canvas id="bgCanvas"></canvas> <div class="brand-content"> <div class="brand-logo">LOGO</div> <h1>某某管理系统</h1> <p>让数据透出价值</p> </div> </div> <div class="login-main"> <div class="login-form-card"> <h2>欢迎登录</h2> <p class="login-tip">请输入您的账号信息</p> <form class="layui-form" id="loginForm" lay-filter="loginForm"> <div class="layui-form-item"> <div class="layui-input-wrap"> <input type="text" name="username" lay-verify="required" placeholder="请输入用户名" autocomplete="username" class="layui-input" /> <i class="layui-icon layui-icon-username"></i> </div> </div> <div class="layui-form-item"> <div class="layui-input-wrap"> <input type="password" name="password" lay-verify="required|pass" placeholder="请输入密码" autocomplete="current-password" class="layui-input" /> <i class="layui-icon layui-icon-password"></i> </div> </div> <div class="login-options"> <input type="checkbox" name="remember" title="记住我" lay-skin="primary" checked /> <a href="javascript:;" class="login-forgot">忘记密码?</a> </div> <button type="submit" class="layui-btn layui-btn-fluid login-btn" lay-submit lay-filter="loginSubmit">登 录</button> </form> <div class="login-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 class="layui-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 ~ 1023px@media (max-width: 1023px)左侧品牌区压缩,表单区适当加宽
<768px@media (max-width: 767px)隐藏左侧品牌区,表单区全屏

具体CSS:

@media (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的设置。如果width=device-width没写对,手机端会按980px的默认视口渲染,整个页面被缩得很小。一定要在head里写:

<meta name="viewport" content="width=device-width, initial-scale=1.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-skin="primary",渲染后会在旁边生成一个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.js

login.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变量

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询