ARTICLE DETAIL

建站实战干货

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

医院叫号大屏HTML5自适应方案:从rem适配到无人值守部署

2026/9/16 19:31:34 拓冰建站 浏览量
医院叫号大屏HTML5自适应方案:从rem适配到无人值守部署 简介面向医院门诊、候诊区等场景的HTML5自适应叫号大屏模板源码包含完整前端页面提供滚动叫号提示、弹框当前叫号信息、各科室排号候检列表展示等功能支持后续功能扩展与风格调整适合需要快速搭建叫号展示界面的开发人员或医院信息化项目参考。整套资源共22个文件以png图片、css样式、js脚本和html页面为主另有txt说明与db数据文件压缩包仅315KB结构精简、无需复杂环境直接打开index.html即可预览效果。当前已有260人学习使用。资源内预置了多样化的界面风格素材并包含顶部、中部背景及信息图标等切图逻辑与样式分离便于二次定制从科室分类、当前叫号到候检叫号的完整信息层级均有示例可直接套用或在此基础上扩展数据接口快速落地到实际叫号屏项目中。1. 医院叫号屏最值钱的不是HTML5是自适应那几行代码医院门诊大厅那几块挂墙上的叫号大屏跟普通网页是两回事。它不给你鼠标滚轮不给你刷新按钮甚至不允许出现滚动条。患者站在三米外要看清当前叫号护士在分诊台扫一眼要确认哪个诊室在过号维护人员拿手机拍张照就能判断哪块屏在报错。这三类需求叠加在一起决定了HTML5医院叫号大屏模板真正的技术核心不是列表渲染而是一套能在不同分辨率、不同缩放比例、不同字号设置下保持布局完整和信息层级的自适应方案。同时系统需要长期无人值守运行浏览器自身的缩放、系统的文本缩放、甚至 Windows 的显示比例设置都可能把精心设计的界面打乱。这也是为什么“自适应”三个字在这个模板里不是加分项而是保命项。本文顺着标题里的“HTML5”“自适应”“叫号”三个关键词拆开讲从方案选型到数据接入再到部署排错给出可以直接抄走的实现思路。有 5 年以上经验的人可以重点看后两章关于状态切换和自检标记的设计那部分通常只有真在大屏项目里滚过一遍才会去考虑。2. 叫号大屏的自适应方案选型rem 不是唯一答案vw 加缩放控制才是2.1 为什么媒体查询撑不起大屏自适应大屏自适应的第一反应往往是写媒体查询断点。但仔细想一下媒体查询是为“同一套内容在不同设备上重新排版”设计的而叫号大屏的核心诉求是“同一套内容在任意分辨率下保持同一种视觉比例”。医院采购的液晶屏可能是 1080p、2K、4K甚至竖屏加异形拼接宽高比从 16:9 到 32:9 都有。如果用断点思维每遇到一种分辨率就要调一次样式而且没办法覆盖未来新采购的型号。更关键的是媒体查询无法解决“浏览器缩放”和“系统文本缩放”这两个真实场景。护士误触 Ctrl滚轮把页面放大到 125%媒体查询完全不感知布局当场崩掉。医院叫号大屏的正确自适应思路应该是“等比例缩放”把设计稿定死在一个基准分辨率上运行时用脚本计算当前视口与基准值的比值统一缩放根节点的字号或者整体 transform。这样无论屏幕怎么变界面永远按设计稿的视觉比例呈现。这个思路业界叫 rem 适配或 scale 适配具体选哪个要看项目边界。2.2 rem、vw、transform scale 三种方案的对比与取舍单论实现方式有三个方案。rem 用根字号做单位配合动态修改 documentElement.style.fontSizevw 直接把尺寸写成视口单位的表达式transform scale 则是把整块画布渲染在固定宽高容器里再等比缩放。三者的差异放在表里更清楚方案实现成本字体清晰度地图/Canvas 兼容适用场景rem 动态 fontSize低字体可随根字号缩放清晰度高尺寸单位需换算纯 HTML/CSS 的大屏推荐全 vw/vh 单位最低纯 CSS字体按视口缩放小屏会糊同上快速原型不推荐上生产transform scale中整体缩放但位图会模糊Canvas 跟随缩放坐标需校正带复杂 Canvas/WebGL 的可视化大屏三种方案在叫号大屏项目里真正生产级的是 rem 动态 fontSize。原因是叫号屏有大量文字患者姓名、诊室号、排队序号、公告内容文本清晰度直接决定可用性。transform scale 在 4K 屏上放大三倍之后文字边缘的渲染质量不如 rem 方案下浏览器原生重排的文字。vw 单位的问题是计算复杂尤其是字体大小和间距混用时表达式写起来很痛苦比如font-size: calc(16px 0.5vw)这种代码在维护阶段谁看谁头疼。2.3 基准分辨率与根字号的设计医院叫号大屏的设计稿一般按 1920×1080 出图。基准字号设为 100px 的好处是计算方便设计稿中量到一个元素宽度是 320px直接写width: 3.2rem。实际运行时用当前视口宽度除以 1920 得到比例因子再乘 100px得到当前环境下的根字号。但这里有个经验问题需要处理大屏通常不是整屏内容而是分区布局医院叫号屏顶部是标题栏中间是主叫号区侧边是排队列表。如果按整屏宽度等比缩放遇到超宽屏比如 32:9 拼接屏时两侧内容会被拉得过于开阔间距失衡。我一般会在基准匹配时取宽高比的修正系数让缩放比例偏向保守。跑通这个逻辑需要这样一段脚本(function (doc, win) { const designWidth 1920; // 设计稿基准宽度 const designHeight 1080; // 设计稿基准高度 const baseFontSize 100; // 基准根字号 1rem 100px const designRatio designWidth / designHeight; function setRootFontSize() { const clientWidth doc.documentElement.clientWidth; const clientHeight doc.documentElement.clientHeight; const currentRatio clientWidth / clientHeight; let scaleRatio clientWidth / designWidth; // 超宽屏防拉伸以高度为基准反向约束 if (currentRatio designRatio * 1.15) { scaleRatio (clientHeight * designRatio) / designWidth; } doc.documentElement.style.fontSize (baseFontSize * scaleRatio) px; } win.addEventListener(resize, setRootFontSize); win.addEventListener(orientationchange, setRootFontSize); setRootFontSize(); })(document, window);这段脚本干了两件事默认按宽度比例计算缩放当视口宽高比明显超过设计稿比例超宽屏时改用高度反推宽度避免左右区被拉空。同时监听 resize 和方向变化插拔 HDMI 信号或切换分辨率时能自动校正。需要注意一个边界场景如果医院接的屏幕点不亮或者输入源切换导致短暂黑屏浏览器可能拿到 0 宽高脚本里最好加个最小值保护比如Math.max(clientWidth, 1)防止计算出 NaN 的根字号把整个布局弄崩。2.4 防止浏览器缩放破坏布局的兜底策略脚本算好了根字号但用户或护士台误操作把浏览器缩放了根字号会被浏览器二次放大。要兜住这层得在入口页面检测并重置缩放级别。常见做法是利用window.outerWidth与window.innerWidth的差值判断浏览器是否处于非 100% 缩放下如果差值异常则用document.body.style.zoom反向修正。需要注意body.style.zoom不是标准属性但 Chromium 内核全面支持医院叫号大屏一般用专用终端跑 Chrome 或 Edge所以可用性没有问题。function guardBrowserZoom() { const outer window.outerWidth; const inner window.innerWidth; if (outer 0 inner 0) { const ratio outer / inner; // 正常无缩放时 ratio 约等于 1无边框模式或固定值 if (ratio 1.05 || ratio 0.95) { document.body.style.zoom 1 / ratio; } } } window.addEventListener(resize, throttle(guardBrowserZoom, 300));这段代码要配合防抖使用否则调分辨率时高频触发会闪屏。另外大屏的浏览器一定要开 kiosk 模式隐藏地址栏和标签栏不然患者能看到地址栏里的报错信息那个画面不太体面。3. 从模板到可用系统医院叫号大屏的数据接入与状态切换3.1 叫号大屏的信息层级决定了布局结构而不是反过来拿到一块 1920×1080 的屏不先看数据直接开切布局是新手常见的做法。医院叫号大屏的数据模型必须先梳理清楚。一层的普通门诊叫号核心信息是当前呼叫的患者号、患者姓名部分隐藏、要去哪个诊室、排队剩余人数、过号提示。挂在大厅的叫号屏通常还会混入科室公告、出诊医生排班表、楼层指引。这些信息的权重差异极大正在呼叫的号码要给最大视觉面积排队列表其次公告和指引属于边缘信息。所以布局结构应该是上下分区加左右分区混合的形态。顶部约 15% 高度放当前时间和多科室信息轮播条左侧约 60% 宽度是主叫号去大字显示“请 A032 号张三到 3 号诊室”右侧是排队列表按诊室分组底部约 8% 高度是公告跑马灯。自适应脚本按基准分辨率计算根字号后这套布局里的所有尺寸全用 rem 写就能做到在不同屏幕上等比例呈现。CSS Grid 是组织这种混合分区最合适的工具代码结构清晰维护也方便。.call-screen { display: grid; grid-template-rows: 15% 1fr 8%; grid-template-columns: 62% 1fr; grid-template-areas: header header main queue ticker ticker; width: 100%; height: 100vh; overflow: hidden; background: #0a1628; } .call-header { grid-area: header; } .call-main { grid-area: main; } .call-queue { grid-area: queue; } .call-ticker { grid-area: ticker; }这套 grid 的关键点是高度用了100vh而非100%。大屏页面不能用滚动条高度锁死在视口高度上内部各区自己的内容溢出时应在区块内滚动而不是撑破整体布局。1fr是剩余空间分配自适应时无需手动计算主区和侧栏的高度差。需要留意100vh在移动端浏览器的地址栏收起展开时会有跳动但叫号大屏跑在固定分辨率显示器上不受这个影响。3.2 WebSocket 推送还是轮询连接管理才是大屏的隐形杀手叫号大屏的数据更新频率非常快一个号码被呼叫、过号、重呼10 秒内状态就可能变三次。轮询在这种场景下既浪费带宽又制造延迟WebSocket 是叫号屏与后端通信的合理选择。但 WebSocket 在长期无人值守的终端上有两个必须面对的坑一是服务端重启后客户端连接断开且不会自动重连二是网络抖动或交换机端口策略导致半开连接连接看似在实际已经死了。模板里必须内置心跳检测与自动重连机制不然屏挂一晚第二天就变成彻头彻尾的“静态模板”。class CallSocket { constructor(url, { heartbeatInterval 30000, reconnectDelay 5000 } {}) { this.url url; this.heartbeatInterval heartbeatInterval; this.reconnectDelay reconnectDelay; this.ws null; this.timer null; this.manualClose false; } connect() { this.manualClose false; this.ws new WebSocket(this.url); this.ws.onopen () { // 启动心跳防止半开连接 this.timer setInterval(() { if (this.ws.readyState WebSocket.OPEN) { this.ws.send(JSON.stringify({ type: ping, ts: Date.now() })); } }, this.heartbeatInterval); }; this.ws.onclose () { clearInterval(this.timer); if (!this.manualClose) { setTimeout(() this.connect(), this.reconnectDelay); } }; this.ws.onerror () this.ws.close(); } close() { this.manualClose true; clearInterval(this.timer); this.ws this.ws.close(); } }心跳的间隔和后端的空闲超时时间要配套常见配置是服务端 60 秒无消息断开客户端心跳 30 秒一次。重连延迟建议做指数退避5 秒、10 秒、20 秒递增上限 60 秒避免医院多台大屏同时断网恢复后集中重连把服务端打崩。这里的代码里manualClose的语义很关键它区分了“前端主动关闭”和“异常断开”避免页面卸载时触发不必要的重连也避免close()方法被调用后 socket 还在后台反复尝试。3.3 状态模板切换从待诊到过号的视觉编码叫号屏上每个号码都有多种状态待诊、已呼叫、就诊中、过号、已完成。如果所有状态都长一个样患者和护士都分不清。模板中应该为每种状态定义独立的视觉编码主要靠颜色和文字标识两个维度区分。当前呼叫的号码用大号高亮色加底框过号号码用红色并追加“过号请重新报到”的提示但提示的表达要考虑不同医院的习惯比如有些医院写“过号请至分诊台”具体文案做配置项。const STATUS_CONFIG { waiting: { label: 待诊, className: status-waiting, sort: 1 }, calling: { label: 呼叫, className: status-calling, sort: 0 }, doing: { label: 就诊中, className: status-doing, sort: 0 }, overdue: { label: 过号, className: status-overdue, sort: 2 }, done: { label: 已完成, className: status-done, sort: 3 } }; function renderPatientItem(item) { const status STATUS_CONFIG[item.status] || STATUS_CONFIG.waiting; const li document.createElement(li); li.className patient-item ${status.className}; li.innerHTML span classpatient-number${item.number}/span span classpatient-name${maskName(item.name)}/span span classpatient-status${status.label}/span; return li; }STATUS_CONFIG对象把状态配置集中在一个数据结构里后续加“复诊”“优先”等状态时只改配置不碰渲染逻辑。sort字段控制排队列表里的排序权重当前呼叫和就诊中的排最前待诊其次过号与已完成沉底。患者的姓名要做隐私脱敏常见做法是保留姓名用星号替代如“张*”。过号患者的处理有一个容易被忽略的细节医院叫号系统的业务规则要求过号患者不能直接从队列删除而是延迟若干分钟后再呼叫一次或转移到人工队列。模板里要做倒计时展示比如“过号请 3 分钟内到分诊台”倒计时结束仍未就诊才标记为“作废”。这背后涉及叫号系统的业务状态机前端模板只需要接收并展示这组状态不要自己在模板里维护最终状态逻辑否则容易出现大屏显示作废但护士站系统里患者还在等待的严重不一致问题。前端要做的只是“忠实渲染服务端下发的状态”状态机相关逻辑在服务端统一判断。4. 部署大屏前要处理的三个坑和一套设备自检标记技巧4.1 安全区域与屏幕过扫描设置里不调边缘永远缺一块医院很多显示大屏是通过 HDMI 接的商用电视或专业显示器这类设备存在过扫描问题。边缘像素会被裁掉一圈幅度在 3%~5% 左右。调用号屏布局时四个边缘一定要留安全边距。设计稿里常见做法是把安全边距设为说设计稿宽度的 3%对应到模板代码中主容器不贴边用padding: 3.5% 3%之类的方式把内容收到安全区内部。同时电视端的“HDMI 全像素”模式要在部署时设置好不同品牌入口不同但原理一致关闭过扫描让画面点对点输出。模板里可以额外加一个调试开关长按屏幕右上角逐个点亮边框方便部署时肉眼确认边缘是否完整。4.2 无人值守下的看门狗自恢复机制比任何代码健壮性都有效大屏终端被设计为 7×24 小时运行Chrome 渲染进程崩溃、显卡驱动重置、内存泄漏撑爆浏览器这些事情在医院环境下并不罕见。模板源码里必须附带一个看门狗页面单独监听主渲染进程的健康状态。常见做法是主页面每隔 10 秒向看门狗页面发送一个postMessage看门狗在 30 秒内没有收到任何消息就调用location.reload()强制刷新主页面。这个比任何内存泄漏排查都直接也比只靠window.onerror更可靠因为渲染进程崩溃时onerror根本不会触发。// 主页面侧 let beatCount 0; setInterval(() { beatCount; const watchdog window.open(, watchdog); if (watchdog) { watchdog.postMessage({ type: heartbeat, beat: beatCount }, *); } }, 10000); // 看门狗页面侧 let lastBeat 0; window.addEventListener(message, (event) { if (event.data event.data.type heartbeat) { lastBeat Date.now(); } }); setInterval(() { if (Date.now() - lastBeat 30000) { const main window.opener; if (main) { main.location.reload(); } } }, 5000);这段代码有一个极端场景需要处理如果看门狗页面本身所在的窗口也被浏览器回收了那就彻底玩完。所以生产部署时应该同时启用系统层面的看门狗比如 Windows 计划任务定时检查浏览器进程是否存在或者用现成的开源监控脚本。模板源码层面能做的也就是这层双保险中的第一道。4.3 一套可以站在 50 米外判断设备状态的 UI 自检标记医院信息科的人不可能每天走到每块屏前面去检查。叫号屏模板可以在角落放一组极简的状态着色标记正常运行的屏角落显示一个冷色调的色块比如深蓝底白字在正常距离外几乎不可见不会干扰患者看叫号信息但若系统报错、断连、渲染异常模板把这几个地方变为暖色调比如橙红色底并闪烁信息科的人站在大厅入口扫一眼就能知道哪块屏出问题了。具体的实现可以放在模板的init.js里给document.title追加状态字串方便远程运维时通过浏览器标题栏判断。同时在前端模板中暴露一个window.__SCREEN_STATUS__全局对象把所有关键指标实时写入连接状态、最后更新时刻、当前渲染的队列长度。截图监控系统或第三方运维平台通过 CDPChrome DevTools Protocol读取这个对象即可不需要后端配合。window.__SCREEN_STATUS__ { wsConnected: false, lastUpdateTime: null, queueLength: 0, currentCallNumber: }; // WebSocket onopen / onmessage / onclose 中相应更新此对象 function paintSelfCheckIndicator() { const indicator document.getElementById(self-check-indicator); if (!indicator) return; const status window.__SCREEN_STATUS__; const healthy status.wsConnected status.lastUpdateTime (Date.now() - status.lastUpdateTime 60000); indicator.className healthy ? check-normal : check-error; }这里的健康状态做了 60 秒的超时容忍因为叫号屏在夜间可能没有新数据推送完全不更新不代表异常。但 WebSocket 连接断开则必现异常所以要区分“连接正常但数据少”和“连接断开会展示的内容是旧的”两种状态。模板的右下角加一个 12px 大小的圆点足够了颜色编码用正常深绿与异常闪烁红色可以自定义为机构的主色系。部署时把这套自检标记的说明打印成 A4 纸贴在配电箱旁边比任何培训都管用。这个设计虽然小却是大屏项目里最体现工程细节的一环。本文还有配套的精品资源点击获取