ARTICLE DETAIL

资讯详情

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

HTML+CSS+JavaScript复刻QQ登录窗口:前端基础实战项目

HTML+CSS+JavaScript复刻QQ登录窗口:前端基础实战项目 简介这是一份面向Web前端初学者与进阶练习者的实战素材围绕HTML、CSS与JavaScript三件套完整还原QQ登录窗口的视觉与交互效果适合想通过仿站项目巩固布局、样式与表单逻辑的人群。压缩包共11个文件约55KB包含1个HTML页面、1个CSS样式表、1个JavaScript脚本以及6张PNG与2张GIF图片素材分别承担页面结构、视觉美化、交互逻辑与图标背景等职责结构紧凑、开箱即用。目前已有859人学习下载具备一定的参考热度。资源重点覆盖表单验证、模拟登录反馈、记住我本地存储、回车键触发登录与自动聚焦等交互细节同时涉及flex或grid响应式布局、输入框聚焦过渡动画、QQ品牌图标引入及媒体查询适配等样式技巧可帮助读者理解从骨架搭建到细节打磨的完整流程并在此基础上自行扩展错误处理与无障碍访问等进阶能力。1. 用 HTMLCSSJavaScript 复刻 QQ 登录窗口一个练手项目为什么值得认真做很多人第一次接触前端都是从「抄一个登录框」开始的。但抄和复刻是两回事。把 QQ 登录窗口用 HTMLCSSJavaScript 从零写出来看起来只是画个框、放两个输入框、加个按钮真正动手才会发现里面全是细节窗口的圆角阴影、头像的呼吸光圈、输入框聚焦时的边框渐变、密码框的小眼睛切换、拖拽窗口、关闭按钮的悬停反馈还有那个经典的「记住密码」勾选框。这些东西单拎出来都不难凑在一起就是一套完整的前端基础语法实战。这个项目适合两类人一类是刚学完 HTML 标签大全和 CSS 样式引入方式、想找个能跑起来的东西练手的新手另一类是做了几年业务、想回头把 CSS 3D 旋转、涟漪光圈扩散、鼠标移入事件这些基础再夯实一遍的老手。它不需要编译环境不需要打包工具一个.html文件加浏览器就能跑是检验「html➕css➕js 基础语法」掌握程度最直接的方式。下面我按实际动手顺序把这个窗口从骨架到交互拆一遍。2. 先搭骨架再谈样式QQ 登录窗口的 HTML 结构怎么切2.1 为什么结构层要一次切到位新手最容易犯的错是边写 CSS 边加 div最后结构乱成一团改一个间距要动三个地方。QQ 登录窗口的结构其实很固定我一般会先把它拆成四块外层窗口容器、顶部头像区、中部表单区、底部操作区。这四块在视觉上是独立的在代码里也应该是对应的独立节点。结构切分的原则是「一个视觉区块对应一个语义容器」。头像区里有头像图片和光圈光圈是装饰元素用伪元素或者独立 div 都行表单区里有账号输入、密码输入、记住密码勾选、登录按钮底部操作区放「忘记密码」和「注册账号」这类链接。切完之后CSS 只需要针对每个容器写样式不会互相干扰。!DOCTYPE html html langzh-cn head meta charsetutf-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleQQ 登录窗口/title link relstylesheet hrefqq-login.css /head body !-- 整个登录窗口后续拖拽也挂在这个节点上 -- div classlogin-window idloginWindow !-- 顶部头像区光圈用伪元素做 -- div classavatar-area div classavatar-ring/div img classavatar srcavatar.png alt用户头像 /div !-- 表单区所有输入和按钮都在这里 -- form classlogin-form idloginForm autocompleteoff div classinput-item input typetext idaccount placeholderQQ号码/手机/邮箱 required /div div classinput-item input typepassword idpassword placeholder密码 required !-- 小眼睛按钮切换密码可见性 -- span classtoggle-pwd idtogglePwd rolebutton aria-label显示密码/span /div label classremember input typecheckbox idremember 记住密码 /label button typesubmit classlogin-btn idloginBtn登 录/button /form !-- 底部操作区 -- div classfooter-links a href#忘记密码/a a href#注册账号/a /div /div /body /html这段结构里有几个点值得说明。autocompleteoff是为了避免浏览器自动填充把演示效果打乱实际项目里按需求决定。密码框旁边的小眼睛用span而不是button是因为它嵌在表单里用button会触发默认提交行为得额外typebutton用span加rolebutton更省事。头像光圈单独用一个div是为了后面做涟漪扩散动画时能独立控制它的缩放和透明度不跟头像图片的样式耦合。2.2 结构层的三个边界坑第一个坑是表单嵌套。有人会把整个窗口包在form里包括头像和底部链接结果点「忘记密码」链接也会触发表单提交。正确做法是只把输入框和登录按钮放进form其他内容放在form外面。第二个坑是id和class混用。结构层里我同时用了class和idclass负责样式id负责 JavaScript 抓取。不要用id写样式否则后面复用组件时会打架。第三个坑是图片路径。本地练手时头像图片放同目录用相对路径avatar.png就行。如果图片加载失败浏览器会显示裂图影响观感所以最好给img加一个onerror兜底或者直接用 CSS 画一个纯色圆形占位。3. CSS 把窗口画出来圆角、阴影、光圈和输入框聚焦态3.1 窗口本体的圆角和阴影参数怎么调QQ 登录窗口的视觉质感八成来自圆角和阴影。圆角用border-radius阴影用box-shadow。这两个属性看起来简单参数调不好就会显得廉价。我一般会先用一个偏大的圆角值定基调再微调阴影的模糊半径和扩散半径。/* 窗口本体圆角 多层阴影营造悬浮感 */ .login-window { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 380px; padding: 40px 30px 20px; background: #fff; border-radius: 12px; /* 第一层阴影贴近窗口第二层扩散更远模拟真实光照 */ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 12px 32px rgba(0, 0, 0, 0.12); user-select: none; }border-radius: 12px是 QQ 窗口比较接近的值再大就偏圆润再小就偏硬朗。box-shadow用了两层第一层0 2px 8px负责窗口边缘的细微过渡第二层0 12px 32px负责整体悬浮感。两层阴影的透明度都控制在 0.15 以下超过就会显得脏。user-select: none是为了后面做拖拽时鼠标拖动不会选中文字。3.2 头像光圈用伪元素做涟漪扩散头像周围那圈会呼吸的光圈是 QQ 登录窗口的标志性细节。实现方式是用伪元素画一个比头像大的圆然后让它做缩放和透明度循环动画。这里会用到 CSS 动画的keyframes核心是控制transform: scale()和opacity。.avatar-area { position: relative; width: 80px; height: 80px; margin: 0 auto 24px; } .avatar { width: 80px; height: 80px; border-radius: 50%; position: relative; z-index: 2; } /* 光圈绝对定位盖在头像下方做扩散动画 */ .avatar-ring { position: absolute; top: 50%; left: 50%; width: 80px; height: 80px; margin: -40px 0 0 -40px; border-radius: 50%; background: rgba(18, 150, 219, 0.35); z-index: 1; animation: ringPulse 2s ease-out infinite; } keyframes ringPulse { 0% { transform: scale(1); opacity: 0.8; } 100% { transform: scale(1.6); opacity: 0; } }光圈动画的关键在ease-out和infinite。ease-out让扩散先快后慢看起来更自然infinite让它循环。scale(1.6)是扩散的终点倍数超过 1.8 就会显得太散。opacity从 0.8 到 0配合缩放形成「涟漪光圈扩散」的效果。注意光圈的颜色用了rgba透明度单独控制不要用opacity属性直接调否则会影响子元素。3.3 输入框聚焦态边框渐变和过渡输入框的聚焦效果是用户感知最强的交互反馈。QQ 窗口的做法是聚焦时边框变蓝、加一点外发光。用:focus伪类配合transition就能做出来。.input-item { position: relative; margin-bottom: 16px; } .input-item input { width: 100%; height: 44px; padding: 0 40px 0 14px; border: 1px solid #d9d9d9; border-radius: 6px; font-size: 14px; outline: none; box-sizing: border-box; transition: border-color 0.2s, box-shadow 0.2s; } .input-item input:focus { border-color: #1296db; box-shadow: 0 0 0 3px rgba(18, 150, 219, 0.15); }transition只写了border-color和box-shadow不要写all否则输入框尺寸变化时会有多余动画。box-shadow用0 0 0 3px做外发光比outline更可控。padding-right: 40px是给密码框的小眼睛留位置账号框其实不需要但统一写上去也无妨。3.4 小眼睛和记住密码的样式细节小眼睛用背景图或者纯 CSS 画都行我一般用background-image加background-size控制。记住密码的勾选框原生checkbox太丑通常用appearance: none重置后自己画。.toggle-pwd { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); width: 20px; height: 20px; cursor: pointer; background: url(eye.svg) no-repeat center / contain; opacity: 0.5; transition: opacity 0.2s; } .toggle-pwd:hover { opacity: 1; } .remember { display: flex; align-items: center; font-size: 13px; color: #666; margin-bottom: 20px; cursor: pointer; } .remember input[typecheckbox] { appearance: none; width: 14px; height: 14px; border: 1px solid #d9d9d9; border-radius: 3px; margin-right: 6px; position: relative; cursor: pointer; } .remember input[typecheckbox]:checked { background: #1296db; border-color: #1296db; } .remember input[typecheckbox]:checked::after { content: ; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }勾选框的勾用::after画两条边再旋转 45 度这是最省事的纯 CSS 方案。appearance: none在部分老浏览器上要加-webkit-前缀但现代浏览器直接写就行。4. JavaScript 让窗口活起来密码切换、拖拽和表单校验4.1 密码可见性切换的两种实现密码框的小眼睛点击后要切换type属性从password变成text同时图标要换。这里有两种做法一种是改input.type另一种是改input.style.webkitTextSecurity。前者兼容性好后者在移动端更稳。我一般用前者。const togglePwd document.getElementById(togglePwd); const passwordInput document.getElementById(password); togglePwd.addEventListener(click, function () { // 判断当前类型切换并同步图标状态 const isPassword passwordInput.type password; passwordInput.type isPassword ? text : password; // 通过 class 控制图标样式避免直接改 background this.classList.toggle(is-visible, isPassword); this.setAttribute(aria-label, isPassword ? 隐藏密码 : 显示密码); });这段逻辑里isPassword变量记录了切换前的状态切换后用它来决定图标 class。aria-label是给屏幕阅读器用的做无障碍时不能省。注意不要用innerHTML去换图标那样会丢失事件监听。4.2 窗口拖拽mousedown、mousemove、mouseup 三件套拖拽是登录窗口的加分项。核心是记录鼠标按下时的偏移量移动时更新窗口的left和top。这里有个细节窗口本身用了transform: translate(-50%, -50%)居中拖拽时要先把transform去掉改用left和top定位否则坐标会算错。const loginWindow document.getElementById(loginWindow); let isDragging false; let offsetX 0; let offsetY 0; loginWindow.addEventListener(mousedown, function (e) { // 只允许点击窗口空白处拖拽点输入框和按钮不触发 if (e.target.tagName INPUT || e.target.tagName BUTTON) return; isDragging true; // 计算鼠标相对窗口左上角的偏移 const rect loginWindow.getBoundingClientRect(); offsetX e.clientX - rect.left; offsetY e.clientY - rect.top; // 去掉居中 transform改用 left/top 定位 loginWindow.style.transform none; loginWindow.style.left rect.left px; loginWindow.style.top rect.top px; loginWindow.style.cursor move; }); document.addEventListener(mousemove, function (e) { if (!isDragging) return; loginWindow.style.left (e.clientX - offsetX) px; loginWindow.style.top (e.clientY - offsetY) px; }); document.addEventListener(mouseup, function () { isDragging false; loginWindow.style.cursor default; });getBoundingClientRect()拿到的是窗口相对视口的位置e.clientX减去rect.left就是鼠标在窗口内的偏移。移动时用e.clientX - offsetX反推窗口的新位置。mousemove和mouseup挂在document上而不是窗口上是因为鼠标移出窗口后事件还会继续触发挂在窗口上会丢事件。4.3 表单校验别让空账号提交表单提交前要做基础校验账号和密码不能为空账号格式可以简单判断。这里用submit事件而不是click因为回车提交也要能拦住。const loginForm document.getElementById(loginForm); const accountInput document.getElementById(account); loginForm.addEventListener(submit, function (e) { e.preventDefault(); // 阻止默认提交演示用 const account accountInput.value.trim(); const password passwordInput.value.trim(); if (!account) { alert(请输入账号); accountInput.focus(); return; } if (!password) { alert(请输入密码); passwordInput.focus(); return; } // 简单格式校验QQ 号纯数字手机 11 位邮箱含 const isQQ /^\d{5,11}$/.test(account); const isPhone /^1\d{10}$/.test(account); const isEmail /^[^\s][^\s]\.[^\s]$/.test(account); if (!isQQ !isPhone !isEmail) { alert(账号格式不正确); return; } console.log(提交成功, { account, password }); });e.preventDefault()在演示里必须加否则表单会刷新页面。正则校验里QQ 号限制 5 到 11 位数字手机号用1\d{10}邮箱用最简的和.判断。实际项目里邮箱校验要更严格但练手够用。5. 避坑与排查复刻登录窗口时最容易翻车的 5 个地方5.1 输入框聚焦时窗口跟着抖动现象点输入框整个窗口轻微位移。原因输入框:focus时加了box-shadow如果窗口用了transform: translate(-50%, -50%)居中阴影会改变元素渲染尺寸触发重排。解决把窗口的居中改成left/top加margin负值或者给窗口加will-change: transform提升为合成层。我一般直接用left: 50%; top: 50%; margin-left: -190px; margin-top: -150px;这种固定尺寸居中彻底避开。5.2 拖拽后窗口跳回原位现象拖完窗口松开鼠标窗口弹回中间。原因mousedown里改了left/top但 CSS 里还有transform: translate(-50%, -50%)没清掉两个定位叠加导致坐标错乱。解决在mousedown里先把transform设为none再用getBoundingClientRect()拿当前位置赋给left/top。顺序不能反先拿位置再清transform否则拿到的位置是错的。5.3 密码小眼睛点击后图标不切换现象点了小眼睛密码明文显示了但图标没变。原因图标用的是background-image切换时只改了input.type没改span的 class。解决在点击回调里用classList.toggle切换一个is-visible类CSS 里写.toggle-pwd.is-visible { background-image: url(eye-off.svg); }。不要用style.backgroundImage直接改那样不好维护。5.4 光圈动画在低端机上卡顿现象头像光圈扩散动画掉帧。原因box-shadow动画和transform动画同时跑box-shadow会触发重绘。解决光圈只用transform: scale()和opacity这两个属性走 GPU 合成不触发重绘。如果还是卡给光圈加will-change: transform, opacity但不要滥用用完记得在动画结束后移除。5.5 表单回车提交绕过校验现象点登录按钮能拦住空账号但按回车直接提交了。原因校验只绑在按钮的click上没绑表单的submit。解决校验逻辑统一写在form的submit事件里按钮用typesubmit这样点击和回车都会走同一条路径。如果按钮是typebutton回车不会触发但点击也不会触发submit得手动调。6. 进阶技巧用 CSS 3D 旋转给窗口加一个入场动画基础版做完之后可以试试给窗口加一个 3D 入场效果。这里会用到transform: rotateY()和perspective。很多人搞不清rotateY(60deg) translateZ(300px)出来是什么样子简单说rotateY是绕 Y 轴旋转正角度让元素右侧向后转translateZ是沿 Z 轴平移正值朝向观察者。两个叠加元素会先转再往前推视觉上像从侧面翻出来。.login-window { /* 父级加透视子级 3D 变换才有立体感 */ perspective: 1000px; } .login-window .window-inner { transform-origin: left center; animation: windowEnter 0.6s cubic-bezier(0.22, 1, 0.36, 1) both; } keyframes windowEnter { 0% { transform: rotateY(60deg) translateZ(300px); opacity: 0; } 100% { transform: rotateY(0deg) translateZ(0); opacity: 1; } }perspective: 1000px加在父级决定 3D 效果的强度值越小透视越夸张。transform-origin: left center让旋转围绕左边缘看起来像门从左边打开。cubic-bezier(0.22, 1, 0.36, 1)是一个先快后慢的缓动曲线比ease-out更有弹性。both让动画结束后保持终态避免闪回。判断 3D 旋转正负有个核心规则右手定则。拇指指向轴的正方向四指弯曲方向就是正旋转方向。Y 轴正方向朝上所以rotateY正角度是逆时针从上方看。记不住就记「正角度往屏幕里转负角度往屏幕外转」多试几次就有感觉了。这个入场动画有个坑如果窗口本身有box-shadow3D 变换时阴影会跟着变形看起来像被压扁。解决办法是把阴影加在内层容器上外层只做 3D 变换。另外动画期间不要同时做拖拽否则transform会被覆盖拖拽逻辑要等动画结束再绑定或者用animationend事件监听。我自己做这个项目时最深的教训是别一上来就写 JavaScript。先把 HTML 结构切干净再用 CSS 把静态效果调到满意最后才加交互。顺序反了后面改样式会牵一发动全身。还有密码框的小眼睛图标一定要用独立元素不要用background直接写在input上否则切换时得改input的样式很容易把输入框本身的背景搞乱。希望帮到你。本文还有配套的精品资源点击获取
返回列表