
1. 先把“13个HTML登录页”拆开风格清单与统一骨架1.1 为什么我建议先定风格再写代码拿到“13个拿来就能用的HTML登录页”这种题目很多人的第一反应是打开编辑器就敲form然后一行行往里堆样式结果写到第4个页面时发现前3个的输入框高度不一样、按钮圆角不一致、焦点样式各写一套改一个细节要翻13份文件。我在给自己攒素材库的时候吃过这个亏后来总结出一条很朴素的规则——先把“风格”抽象成变量再动结构。风格本质上是三组可枚举的参数背景层纯色、渐变、图片、模糊、网格、噪点、卡片层透明、半透明、实心、无卡片、强调色与圆角。把这三组拆成CSS自定义属性之后13个页面其实共用一套骨架只是变量值不同。这样做的好处很直接后期要统一调整主色或者给全部页面加一个深色模式开关只需要动一处。另一个必须提前想清楚的点是“拿来就能用”这五个字。它意味着文件必须自带完整依赖闭环——不引用外部CDN、不依赖构建工具、双击HTML就能在浏览器里跑起来。所以我在搭骨架时就刻意避开需要编译的方案全部用原生HTML加CSS加少量原生JavaScript完成表单提交走一个可替换的接口占位。注意所谓“拿来就能用”不等于“拿来就能上线”。演示页面里的接口地址、二维码状态模拟、错误提示文案都必须替换成自己项目的真实内容否则上线第一天就会出问题。1.2 13种风格的定位与适用场景对照风格没有好坏只有匹配不匹配。同一个毛玻璃卡片放在面向设计师的产品里是加分项放在面向财务人员的后台系统里就显得轻浮。下面这张表是我自己在使用的分类方式把13个页面按“视觉重心”和“技术难点”标了出来方便你按需取用。序号风格命名视觉重心关键技术点适用场景实现难度1暗黑科技网格背景网格加光斑重复渐变、径向渐变叠加开发者工具、云服务控制台中2霓虹描边按钮与输入框描边多层阴影、过渡动画游戏社区、创意产品低3毛玻璃卡片背景模糊backdrop-filter加降级图片背景类产品中4扫码登录二维码与状态区状态机、定时轮询移动端配套的网页端高5极简线框留白与细线边框、间距节奏企业内网、文档站低6左右分屏插画与表单对比弹性布局、断点切换品牌官网低7悬浮卡片层叠投影多层阴影、位移动画通用SaaS低8沉浸全屏背景视频或大图对象适配、遮罩层内容型产品中9终端命令行等宽字体与光标伪元素动画、字体栈极客向产品中10单色大字字号对比流体字号clamp()品牌感强的落地页低11分步表单步骤指示状态切换、焦点管理注册与登录合并流程高12抽屉滑入入场动效transform与缓动曲线弹窗式登录中13渐变描边卡片边框渐变mask或伪元素遮罩活动页、营销页中这张表最有用的一列其实是“实现难度”。列表里标注高难度的三个难点都不在视觉而在状态管理和可访问性——扫码要处理过期、轮询要能停、分步表单要管焦点。视觉部分靠CSS就能解决状态部分必须老老实实写逻辑。1.3 13个页面共用的DOM骨架不管外观怎么变登录表单的语义结构是固定的一个form、一个标题、若干带label的输入项、一个提交按钮、一块辅助链接区。我把它固化成下面这段结构13个页面全部在此基础上替换class名。form classlogin-form novalidate h1 classlogin-title欢迎回来/h1 p classlogin-sub登录后继续你上次的进度/p div classfield label foraccount账号/label input idaccount nameusername typetext autocompleteusername required placeholder邮箱或用户名 p classfield-error rolealert hidden/p /div div classfield label forpwd密码/label input idpwd namepassword typepassword autocompletecurrent-password required placeholder请输入密码 button typebutton classpwd-toggle aria-label显示密码显示/button /div button typesubmit classbtn-primary登录/button /form这里有三处细节值得单独说明。第一novalidate写在表单上把校验时机收回到自己手里否则浏览器会在点击提交时弹出默认气泡样式无法统一。第二autocomplete必须写对浏览器密码管理器靠它识别字段写成off或者乱填会让用户在手机上反复手输密码。第三错误提示用rolealert加hidden属性切换读屏软件才能在错误出现时主动播报。关于按钮的type很多人习惯省略结果在分步表单里点“显示密码”直接把表单提交了。所有非提交按钮一律显式写typebutton这是个五分钟能养成的习惯能省掉大量调试时间。2. 科技感登录页网格、光斑与动效的克制2.1 科技感的三个视觉支柱“科技感”这个词很虚落到CSS上其实就三件事深色底、规则几何纹理、局部光。深色底提供对比几何纹理网格、点阵、斜线暗示秩序和精密局部光制造纵深。三样凑齐氛围就有了缺一样或者用量过头就会滑向“网吧大屏”的观感。我做第一版的时候犯过典型错误网格线用了0.5的透明度光斑开了三个还加了一层扫描线动画结果整页像在放电输入框里的文字被背景吃掉对比度根本过不了。后来把网格透明度压到0.06光斑只留一个扫描线直接删掉反而高级了。原理上讲人眼对深色背景上的高对比元素会格外敏感背景里的每一分亮度都在跟正文争夺注意力。所以科技感页面的背景亮度必须远低于正文亮度中间隔着至少两个数量级的明度差。2.2 网格背景与光斑的可复用写法网格不需要图片两层线性渐变就够了一层画竖线一层画横线用background-size控制格子间距。光斑用径向渐变从中心色到透明。两者的层叠顺序要注意网格在上还是光斑在上观感差别很大网格在上会显得更“硬”光斑在上更柔和。:root { --bg: #080b12; --grid: rgba(120, 180, 255, 0.06); --glow: rgba(64, 140, 255, 0.28); --text: #e8eef8; } body.tech { min-height: 100dvh; display: grid; place-items: center; color: var(--text); background-color: var(--bg); background-image: radial-gradient(circle at 50% 18%, var(--glow), transparent 42%), linear-gradient(var(--grid) 1px, transparent 1px), linear-gradient(90deg, var(--grid) 1px, transparent 1px); background-size: 100% 100%, 44px 44px, 44px 44px; }这里min-height用的是100dvh而不是100vh。移动端浏览器地址栏收放时100vh会按最大高度算导致页面底部被裁掉一截登录按钮正好卡在屏幕外。dvh是动态视口单位跟着可视区域变化目前在主流浏览器上都支持配合100vh做降级更稳。光斑的位置我用circle at 50% 18%让光源落在标题上方偏后的位置模拟“屏幕背后有一盏灯”。如果把光斑放在正中卡片会显得被压住视觉上很闷。注意background-image里多层叠加时写在前面的层在上面。光斑写在最前面是有意为之让它盖住网格边缘过渡更自然。2.3 动效要做减法也要留后门科技感页面最容易被滥用的就是动效。漂浮、旋转、呼吸、粒子——单看每个都好看叠在一个登录页上就是灾难。我的经验是登录页的动效只服务于“反馈”不服务于“表演”。输入框聚焦时描边亮起、按钮悬停时微微上移、提交时按钮出现进度条这三处足够。真正的坑在性能上。用box-shadow动画会让浏览器不断重绘在低端安卓机上直接掉帧。要动就让transform和opacity动这两个属性可以由合成层独立处理代价极小。下面这段是我常用的按钮悬停效果只改transform和阴影的静态值。.btn-primary { border: 0; border-radius: 10px; padding: 12px 20px; font: 600 15px/1.4 system-ui, -apple-system, Segoe UI, sans-serif; color: #fff; background: linear-gradient(135deg, #3b82f6, #6366f1); box-shadow: 0 8px 24px rgba(59, 130, 246, 0.35); transition: transform 160ms ease, box-shadow 160ms ease; will-change: transform; } .btn-primary:hover { transform: translateY(-1px); } .btn-primary:active { transform: translateY(0); box-shadow: 0 4px 12px rgba(59,130,246,.3); } .btn-primary[disabled] { opacity: .6; cursor: not-allowed; transform: none; }will-change: transform这里要谨慎它会把元素永久提升为合成层占显存。只给真正会动的元素加别图省事写在*上——我在一个列表页这么干过滚动直接卡成幻灯片。还有一个必须留的后门prefers-reduced-motion。有些用户因为身体原因会关闭系统动效登录页的所有过渡都应该尊重这个设置。media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }3. 毛玻璃登录页backdrop-filter 的正确打开方式3.1 毛玻璃容易翻车的三个原因毛玻璃Glassmorphism是这13个页面里被问得最多的一个也是最容易做砸的一个。翻车原因通常有三类第一类背景没有东西可模糊。backdrop-filter模糊的是元素背后已经绘制的内容如果卡片背后是纯色模糊前后完全一样看着就像一张普通半透明卡。想让效果出来背后必须有图片、渐变或者纹理。第二类把模糊加错了层级。有人给整个容器加filter: blur()结果文字一起糊了。backdrop-filter只影响背景filter影响元素本体和子元素这两个别混。第三类兼容性和性能没兜底。部分环境不支持该属性不支持时卡片会变成完全透明或者完全实心两种都很尴尬。另外大面积的实时模糊对GPU有压力在低端设备上滚动会明显掉帧。3.2 一层玻璃卡片的完整写法我的做法是把“卡片外观”拆成三层底色层半透明、模糊层backdrop-filter、描边层1px 高光边框。三层各司其职任何一层出问题都不至于整体崩塌。.glass-card { position: relative; width: min(420px, calc(100vw - 32px)); padding: 32px 28px; border-radius: 18px; background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.18); box-shadow: 0 24px 60px rgba(0, 0, 0, 0.36); color: #f5f8ff; } supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) { .glass-card { -webkit-backdrop-filter: blur(18px) saturate(160%); backdrop-filter: blur(18px) saturate(160%); background: rgba(255, 255, 255, 0.10); } } /* 不支持时的兜底加深底色保证文字可读 */ supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .glass-card { background: rgba(18, 22, 34, 0.86); } }supports的写法要注意-webkit-前缀在一部分环境里仍然是必需的两个都列上再做or判断覆盖面最广。兜底方案我选择加深不透明度宁可失去通透感也不能让文字在复杂背景上看不清。width: min(420px, calc(100vw - 32px))这个写法比媒体查询更省事小屏自动收缩并保留 16px 边距一行顶三行。3.3 模糊半径、饱和度与描边的配比经验参数没有标准答案但有可复现的推导过程。模糊半径和卡片尺寸强相关卡片宽 400px 左右时blur落在 14px 到 22px 之间观感最好卡片越大半径要跟着涨否则背景细节透过来太清楚玻璃感就没了。饱和度那 160% 不是随手写的。模糊过程会把颜色平均化视觉上偏灰适度提高饱和度能把背景颜色的鲜活度拉回来。但别超过 200%否则背景里的橙色会被推到刺眼的程度。描边的不透明度也有讲究。低于 0.1 看不见高于 0.3 就成了白框。我一般在 0.16 到 0.22 之间取值再配合一条从左上到右下的渐变边框玻璃的“厚度感”就出来了。注意毛玻璃卡片里的输入框不要再加半透明背景两层透明叠加会让文字对比度骤降。输入框用接近实心的深色或浅色底跟卡片形成明确层次。如果背景用的是图片记得给图片层加一层暗色遮罩把最亮区域的亮度压下来否则卡片里的浅色文字在亮斑上会彻底消失。这个遮罩用伪元素加linear-gradient实现最简单也不影响图片本身的替换。4. 扫码登录好看的皮囊下是状态机4.1 扫码登录的四个状态扫码登录的视觉很简单一个二维码加一行小字。但它背后的状态流转比账号密码登录复杂得多我把页面层面需要处理的状态归纳成四个待扫描二维码展示中倒计时进行中已扫描用户用移动端确认了页面提示“请在手机上确认”已确认登录成功跳转或写入凭证已过期二维码失效需要展示刷新遮罩这四个状态必须一一映射到DOM上的类名或者>div classqr-box>const qrBox document.querySelector(.qr-box); const tip document.querySelector(.qr-tip); const TTL 120; // 二维码有效期秒 let remain TTL; let pollTimer null; let tickTimer null; function setState(state) { qrBox.dataset.state state; const map { waiting: 请使用移动端扫描二维码, scanned: 扫描成功请在移动端确认, confirmed: 登录成功正在跳转, expired: 二维码已失效 }; tip.textContent map[state] || ; } function stopAll() { clearInterval(pollTimer); clearInterval(tickTimer); pollTimer tickTimer null; } function startCountdown() { remain TTL; clearInterval(tickTimer); tickTimer setInterval(() { remain - 1; if (remain 0) { stopAll(); setState(expired); } }, 1000); } function startPolling() { // 演示用真实项目中这里替换为向服务端查询扫码结果 let step 0; pollTimer setInterval(() { step 1; if (step 2) setState(scanned); if (step 3) { stopAll(); setState(confirmed); } }, 2000); }这段代码里最值得看的是stopAll()。定时器泄漏是扫码页面最常见的隐性bug——用户切换到了账号密码登录二维码的轮询还在后台跑页面看起来没事请求却一直在发。所有跳出扫码页面的路径切换标签、刷新二维码、路由离开都必须调用一次清理函数。TTL设成 120 秒是行业里比较常见的值。太短用户来不及扫太长会给服务端带来无谓的状态维持成本。倒计时到最后 10 秒时可以把提示文字变色给用户一个心理预期。4.3 轮询还是长连接怎么选小规模场景用定时轮询完全够用实现简单服务端无状态断线也不会留下悬挂连接。间隔我一般取 1500ms 到 2500ms太密集会给服务端造成不必要的压力太稀疏用户确认后要等很久页面才有反应。用户量上来之后轮询的开销会变成线性增长这时候换成服务端推送更合适。但这属于后端选型对页面本身的影响很小——把startPolling里的逻辑替换成订阅回调即可状态映射那部分代码一行都不用改。这也是我坚持把状态切换收敛到一个setState函数里的原因换通信方式时视图层零改动。还有一个细节页面切到后台标签时应该暂停轮询。用document.visibilityState判断隐藏时停掉定时器回到前台再恢复。这个优化在移动端尤其明显能省下不少电量。5. 表单交互与校验让这13个页面真正能填5.1 原生校验能扛多少边界在哪HTML 原生校验属性required、typeemail、pattern、minlength覆盖面其实比想象中大。账号必填、邮箱格式、密码最短长度这三类完全可以用原生属性解决不用写一行JS。问题是默认的提示气泡样式无法定制位置也不受控在不同浏览器里长得完全不一样。我的折中方案是校验规则写在HTML属性上展示交给自定义提示。表单加novalidate关掉原生气泡提交时手动调用form.checkValidity()再用input.validity对象判断具体是哪条规则没过映射成自己的文案。const form document.querySelector(.login-form); form.addEventListener(submit, (e) { e.preventDefault(); if (!form.checkValidity()) { const firstInvalid form.querySelector(:invalid); showError(firstInvalid, pickMessage(firstInvalid)); firstInvalid.focus(); return; } submitLogin(new FormData(form)); }); function pickMessage(el) { const v el.validity; if (v.valueMissing) return 这一项不能为空; if (v.typeMismatch el.type email) return 邮箱格式看起来不对; if (v.tooShort) return 至少需要 ${el.minLength} 个字符; return 请检查这一项; }form.querySelector(:invalid)拿到第一个不合法的元素并让它获得焦点这一步很关键。长表单里如果不聚焦用户不知道错在哪对使用键盘的读者来说焦点留在原地等于什么都没发生。5.2 错误提示的出现时机比文案更重要新手常犯的错是边输边报错——用户刚敲第一个字符下面立刻红字“密码至少8位”。这种体验很差因为它把“还没输完”当成了“输错了”。我的规则是第一次校验发生在失焦时之后才转为实时校验。用blur触发首次检查检查过一次之后给字段打上标记后续input事件里再实时更新。这样既不会打断输入又能让用户及时看到修正结果。form.querySelectorAll(input).forEach((input) { input.addEventListener(blur, () { input.dataset.touched 1; validateOne(input); }); input.addEventListener(input, () { if (input.dataset.touched 1) validateOne(input); }); });错误文案也别写“输入有误”这种废话。用户在登录页最想知道的是“我该改什么”所以文案要具体到动作邮箱格式不对、密码长度不足、账号不存在。最后这条要注意安全边界登录失败时统一提示“账号或密码不正确”不要暴露账号是否存在。5.3 密码可见性、回车提交与自动填充密码可见性切换按钮的坑集中在可访问性上。按钮要有aria-label切换时要同步更新标签文字同时把input.type在password和text之间切换。切换回密码态后光标位置最好保持在末尾否则用户接着输入会跳到开头。回车提交不需要单独监听keydown。只要按钮是typesubmit且位于form内在输入框里按回车浏览器会自动触发表单的submit事件。手写keydown监听反而容易在输入法组合状态下误触发——中文输入时按回车是确认候选词不是提交表单。自动填充这块autocomplete写对之后浏览器会自己填但有一个副作用部分浏览器会给自动填充的输入框加上淡黄色背景跟深色主题严重冲突。解决办法是用一层内阴影覆盖。input:-webkit-autofill, input:-webkit-autofill:hover, input:-webkit-autofill:focus { -webkit-text-fill-color: var(--text); -webkit-box-shadow: 0 0 0 1000px rgba(255,255,255,0.06) inset; transition: background-color 9999s ease-out; }那个超长的transition是个老技巧用极长的过渡时间阻止背景色被浏览器改回来。看着怪但确实有效。6. 响应式与可访问性最影响口碑的部分6.1 三档断点足够不要贪多13个页面里有几个我一开始写了六七个断点后来发现维护成本高得离谱而且很多断点的差异肉眼根本看不出来。现在统一收敛到三档手机小于640px、平板与小平板横向640px到1024px、桌面大于1024px。手机档的核心任务是减少横向占用保证纵向可滚动。卡片宽度用calc(100vw - 32px)内边距从32px降到20px标题字号降一档。左右分屏那个页面在手机档要改成上下排列插画区直接隐藏——留着也看不清还占掉了首屏。平板档主要是处理“卡片居中但背景撑满”的关系桌面档才是加装饰的时候。这个顺序很重要先保证小屏能用再考虑大屏好看。断点宽度卡片处理布局变化手机 640px宽度自适应内边距收窄分屏转纵向插画隐藏平板640–1024px固定宽度居中分屏按 1:1 或 1:1.2 分配桌面 1024px固定宽度居中分屏可加装饰层6.2 键盘流程与焦点样式我给自己定了一条硬标准不用鼠标只用Tab和回车必须能完成整个登录流程。这条标准筛出了大量问题比如自定义的“显示密码”按钮用了div根本收不到焦点比如扫码卡片切换后焦点丢了按Tab直接从页头跳到页尾。div冒充按钮是重灾区。真要用非按钮元素就得补rolebutton、tabindex0还要监听空格键和回车键。既然这么麻烦不如直接用button浏览器把该做的都做了。焦点样式也不能用outline: none一删了之。默认的焦点环在某些深色背景上确实不明显正确做法是替换而不是删除。:focus-visible { outline: 2px solid #7aa7ff; outline-offset: 2px; border-radius: 6px; }用:focus-visible而不是:focus鼠标点击时不会出现焦点环键盘操作时才显示兼顾美观和可访问性。6.3 对比度与深色模式的冲突处理正文文字和背景的对比度我按 4.5:1 作为底线。深色背景上的浅灰文字最容易不达标尤其是那种#888配#111的组合看着有质感实际读起来费劲。用浏览器的开发者工具检查一下对比度数值很快就能判断。深色模式这块我的建议是把颜色全部抽成自定义属性然后用prefers-color-scheme覆盖变量值而不是给每个页面单独写一套深色样式。:root { --bg: #f6f8fc; --card: #ffffff; --text: #17202e; --muted: #5b6779; } media (prefers-color-scheme: dark) { :root { --bg: #0b0f17; --card: #151b26; --text: #e8eef8; --muted: #95a2b8; } }--muted这个变量专门给次要文字用深色模式下的值要重新算过不能直接反色。反色之后饱和度会失真看着发灰发脏。注意13个页面里如果有几个是“固定深色”风格比如暗黑科技和终端命令行不要硬套prefers-color-scheme。这类页面的品牌调性就建立在深色上跟着系统切换反而破坏设计意图。给它们单独标记跳过主题切换逻辑。7. 常见问题与排查技巧实录7.1 高频问题速查表下面这些问题几乎每一个都来自真实调试过程有些折腾了我大半个下午。按“现象查原因”的方式整理遇到问题直接对照。现象可能原因排查与解决毛玻璃没效果背后是纯色无内容可模糊检查父级背景加图片或渐变卡片里文字看不清两层透明叠加对比度不足输入框改实心底或加深卡片底色移动端底部按钮被遮用了100vh改100dvh兼容写法两者都留毛玻璃滚动卡顿大面积实时模糊缩小模糊区域或用supports降级点了按钮表单直接提交非提交按钮没写typebutton全部显式声明类型二维码过期后还在请求定时器没清理所有离开路径调用清理函数自动填充后输入框变黄浏览器默认样式用内阴影覆盖-webkit-autofill输入框聚焦时页面放大字号小于16px手机档输入框字号不低于16px回车提交在中文输入时误触发监听了keydown改用表单submit事件深色模式下文字发灰变量值直接反色重新计算次要文字色值表里第九条值得多说一句。中文输入法在组合状态下按回车是上屏候选词如果代码监听了输入框的keydown并判断key Enter用户每选一次词就会触发一次提交看起来像“输入法把表单提交了”。换成表单默认的提交行为浏览器的输入法组合事件处理会帮你挡掉这种情况。7.2 我在实际调试中踩过的几个坑第一个坑是背景图的亮度不可控。沉浸式全屏背景那个页面我一开始直接用了张风景图本地测试时卡片在暗部文字清清楚楚换了一张图之后浅色文字正好压在雪山上完全看不清。后来加了一层固定遮罩把图片整体亮度压到60%以下问题才彻底解决。这个经验后来被我固化成一条规则凡是背景图必配遮罩层别指望挑图来解决问题因为图片随时会被换掉。第二个坑是动效与布局抖动。抽屉滑入那个页面卡片从右侧滑入的同时高度在变化导致页面短暂出现滚动条滑完又消失观感很差。原因是用了margin做位移触发重排。改成transform: translateX()之后位移在合成层完成不再影响布局。判断标准很简单能让元素位移的优先transform别碰top/left/margin。第三个坑是二维码图片的清晰度。演示页面里我随手放了个 200×200 的图在高分屏上被拉伸后边缘模糊。二维码对清晰度要求很高模糊会导致扫不出来。解决方式是把图片尺寸做到实际显示尺寸的两倍或者干脆用 SVG 再配合image-rendering: pixelated保证边缘锐利。这个细节在演示页面里容易被忽略一旦上线反馈会很难看。第四个坑是多页面共用一个样式文件时的选择器冲突。13个页面我最初想省事全塞进一个CSS里用.page-1、.page-2前缀隔离。写着写着就出问题了.field在毛玻璃页面里需要半透明白边在极简线框页面里需要细灰线前缀写得不够细就会互相污染。后来改成每个页面一个独立文件公共部分抽成base.css问题消失。这种“为了省一个文件而引入全局污染”的做法代价远高于多写一个link。第五个坑是提交按钮重复点击。网络慢的时候用户会连点几次服务端收到多条请求。前端最简单的处理是提交瞬间禁用按钮请求结束再恢复同时给按钮一个加载态。async function submitLogin(data) { const btn form.querySelector(.btn-primary); const raw btn.textContent; btn.disabled true; btn.textContent 登录中...; try { await fetch(/api/login, { method: POST, body: data }); } catch (err) { showGlobalError(网络不太稳定请稍后再试); } finally { btn.disabled false; btn.textContent raw; } }finally里恢复状态这一步不能漏。如果放在try里请求一失败按钮就永远灰着用户只能刷新页面。最后分享一个我在整理这套页面时养成的习惯每做完一个页面用手机实际打开一次把系统字体调到最大再打开一次。13个页面里有将近一半的问题是在这两次“真实环境”检查中才暴露的——字号放大后标题溢出卡片、说明文字被截断、按钮文字换行。桌面浏览器把窗口拉窄并不能完全模拟这些情况。这套东西积累下来之后后面再遇到新的登录页需求基本就是从这13个里挑一个最接近的改改颜色和文案半小时能交付。反倒是那些一眼看上去最花哨的页面改动起来最费劲因为视觉层级耦合太深。所以选风格的时候我的建议是先想想三个月后要谁来维护它。