
H5 和微信小程序这几年几乎成了前端开发绕不开的两个词。我刚入行那会儿大家对H5的定义还在移动端网页和响应式布局上打转这两年再聊几乎每个项目都要纠结一句这东西是做小程序还是做 H5尤其是手里握着预算和排期的产品经常被技术团队反问一句然后陷入哪个更便宜哪个上线快哪个用户更容易用的灵魂拷问。这篇文章不打算按教科书的方式给你罗列H5 是网页、小程序是应用这种正确的废话。我想从实际开发的角度把这两种载体拆开来对比一遍讲清楚它们背后的运行环境、开发体验、性能边界、上线流程到底差在哪以及在什么场景下你应该死磕 H5什么场景下必须上小程序。如果你是前端工程师、技术负责人或者正在给甲方做技术选型这篇应该能帮你少走不少弯路。1. 运行模型不同的根一个活在浏览器一个活在独立容器很多人分不清 H5 和小程序的本质是因为从肉眼上看两者都是在手机里打开一个界面流程也差不多。但它们底层的运行逻辑几乎完全不一样这一点决定了后面所有差异。1.1 浏览器环境H5 的宿主是 WebViewH5 页面跑在 WebView 里面而 WebView 本质上就是一个嵌在 App 或者系统组件里的浏览器内核。所以你写的 HTML、CSS、JavaScript最终都是靠浏览器内核解析和渲染。这意味着你能用的 API 基本取决于 WebView 内核版本而不是你的代码本身iOS 上系统统一用 WKWebViewAndroid 上不同厂商、不同 App 嵌入的 WebView 可能千差万别页面代码存在服务器上用户每次打开都要从网络拉取资源。我举个例子你就明白了。同样的一个position: fixed底部按钮在 iOS 的 WKWebView 里偶尔会跟随键盘弹跳在 Android 的老 WebView 里又可能会出现被软键盘顶起却不归位的问题。这不是你代码写得不对是渲染容器本身行为就不一致。1.2 小程序容器双线程没有 DOM小程序不是跑在普通 WebView 里的页面它跑在微信或者其他宿主 App自带的渲染容器里。这个容器做了一件很特别的事逻辑层和渲染层完全分离。逻辑层运行 JavaScript负责数据处理、网络请求、业务逻辑渲染层运行 WXML WXSS负责界面显示两层之间通过 Native 的桥接机制进行通信而不是像传统 HTML 页面那样由 JS 直接操作 DOM。这带来一个直接结果小程序里没有document、没有window你不能像写 H5 那样随手document.getElementById去改节点。所有界面变化都必须通过修改数据、由框架内部触发视图层更新。这也是为什么最初从 H5 转小程序的人会觉得浑身难受——不是写不了是思维模型得换。一个小细节可以帮你感知差异小程序包的体积限制非常严格主包一般不超过 2MB超过就要做分包。这个限制直接从物理层面逼着你优化代码体积。H5 项目你打个几 MB 的 JS 包问题不大顶多首屏慢一点小程序你不管包体积直接塞不进微信的容器里。1.3 理解了这个根子后面的差异都能推导出来一旦你理解两者的运行模型很多为什么就都解释通了为什么小程序页面切换比 H5 顺滑因为小程序的部分页面资源随包加载页面切换走的是原生渲染而不是 WebView 重新加载为什么小程序里做动画比 H5 更吃性能因为每一次数据变化都要走逻辑层到渲染层的桥接通信频繁 setData 会大量消耗性能为什么 H5 可以随时发布、随时更新因为它的资源在服务端用户刷新就拿到新代码而小程序要过审核发布机制。所以选型的时候第一个要考虑的问题不是谁好听谁热门而是你的产品需要哪一种运行模型。如果你需要频繁热更新、快速试验、不被平台审核卡脖子H5 天然有优势如果你需要稳定流畅的交互、稳定的接口能力、以及微信生态内的入口小程序是绕不开的选择。2. 技术栈与跨端框架的真实差异一套代码到底能不能通吃H5 和小程序在技术栈上表面上都是JavaScript 那一套但真正写起来会发现差距非常明显。这些年社区里出现了很多跨端框架比如 Taro、uni-app它们的口号都是一套代码多端运行实际效果怎么样我详细说说。2.1 原生 H5 的技术栈选择很自由我目前做 H5 主力是 Vue3 Vite偶尔也会用 React。H5 的技术选型基本是开放的框架随便选Vue、React、Svelte 都可以样式方案随便上CSS、SCSS、Tailwind、CSS Modules 全看你偏好状态管理、路由、UI 组件库都是成熟的生态体系部署只要你有服务器Nginx 配一下就能上线。自由带来的是效率也带来责任。比如路由刷新后 404、页面缓存清除、iOS 滚动卡顿这些小问题都需要你自己踩坑解决。不过对于一个正经的前端团队来说这些问题基本都能靠工程经验兜住。2.2 小程序原生开发受限也够用微信小程序的原生语法是 WXML、WXSS、JavaScript/TypeScript。模板语法和 Vue 有点相似但写起来会有很多平台特有的概念比如setData更新页面数据的唯一入口直接影响性能wx.request/wx.login网络请求和登录都走微信 APIapp.json/page.json全局和页面级配置导航栏、窗口样式都是 JSON 配置化组件间通信用properties和自定义事件而不是前端熟悉的 props / emit 那套虽然现在有些类型定义和 Vue 很像但底层思路不同。原生开发的另一个限制是 API 边界特别明确。微信小程序能调用什么、不能调用什么都清清楚楚地写在小程序开发文档里。比如你无法随意操纵 DOM、无法在逻辑层用window对象、无法绕过它的请求域名白名单随便发网络请求。所有请求域名必须在小程序后台配置为合法域名。这一点对很多从 Web 转过来的同学是一个极大的不适应点。在 H5 里你请求任意后端接口只要跨域就配个代理或让对方开 CORS在小程序里域名白名单、HTTPS 要求、业务域名校验一个都不能少。2.3 跨端框架的本质编译转换而非银弹如果你听说过用 Vue 写小程序这类说法通常指的就是 Taro 或 uni-app。这类框架做的事情是将你写的 Vue/React 代码通过编译期转换生成小程序原生代码。拿 Taro 3 举例它在运行时做了一层 React/Vue 语法到小程序原生组件的适配让你在组件里写useState、useEffect最终渲染成小程序的 WXML。uni-app 则是 Vue 语法编译到各家小程序平台。客观说跨端框架确实能帮团队用较少的成本覆盖多端比如 H5 微信小程序 App 三端复用。但你应该知道这套方案的代价跨端框架的调试链路更长出问题你得区分是框架层的问题还是原生层的问题部分小程序独有能力比如微信的wx.login、自定义分享、订阅消息跨端框架虽然封装了但封装不完全经常要写条件编译来处理不同端的差异性能上框架增加了一层运行时适配如果项目里大量 setData 或者复杂列表渲染很容易出现卡顿。我的经验是如果目标只有 H5别用跨端框架直接原生技术栈最舒服如果目标是小程序 App H5 多端覆盖跨端框架值得考虑但要有心理准备去做平台差异化适配。2.4 我给你的具体建议纯 H5 场景Vue3/React Vite 任意组件库复杂度低生态丰富微信小程序单端场景原生语法最稳性能可控官方特性跟随最快多端覆盖小程序 H5 Appuni-app 适合招人容易、上手快的团队Taro 适合 React 基础强的团队团队没有跨端需求却硬上跨端框架是我见过最亏的选型没有之一。3. 能力边界和性能体感小程序为什么重但顺滑过去有个流行说法H5 轻但是不如 App 顺畅小程序是介于两者之间的折中。这个说法不算错但不够精确。3.1 硬件能力 API小程序赢在能做手机上的很多硬件能力是 H5 很难触达的而小程序可以比较轻松地通过 JS Bridge 调用H5 里你想调用蓝牙、NFC、指纹识别这些能力基本是不可能的或者需要借助宿主 App 的壳自己写原生桥小程序微信生态内wx.vibrateShort震动、wx.scanCode扫码、wx.startLocation定位、wx.chooseImage选图、录音、支付、订阅消息这些能力是打包好的 API直接可调小程序的登录态天然依赖微信身份体系wx.logincode2Session用户不需要输手机号体验很顺H5 嵌在微信里虽然也能做微信授权登录但要走 OAuth 流程用户需要确认授权且部分能力如微信支付在 H5 里的实现成本明显更高。从做产品的角度看这个差距直接决定了功能的可行性。比如你做一个小程序商城可以用微信支付、订阅消息做订单提醒如果做 H5 商城微信里的支付方式是微信的 JSAPI 支付但需要额外授权绑定浏览器外打开的 H5 又得走 H5 支付费率、场景、交互限制都要重新考虑。3.2 性能模型为什么功能越重越要谨慎先给小白的解释H5 的页面打开需要下载资源 → 解析 → 渲染每一步都要时间网络差的时候尤其明显。小程序则因为资源包提前下载到本地渲染在原生层执行所以页面切换、列表滑动的物理手感会好很多。但这不代表小程序就没有性能问题。小程序最常见的性能瓶颈是 setData 频率和 payload 大小。做长列表或者直播弹幕这类高频率更新的场景如果你直接把大数组传给视图层微信的渲染线程可能直接卡死。我做过一个社区项目需求是聊天消息实时展示。最初我每次收到一条新消息就把整个消息数组 setData 过去结果 iOS 上非常卡。后来改成增量更新只把新增的那几条数据传给视图层配合scroll-view的定位才把体验救回来。同样的业务在 H5 里用虚拟滚动做长列表也可以很顺但实现复杂度完全不亚于小程序里绕 setData 的坑。另一个典型的性能案例是图片加载。H5 里做图片懒加载有很多方案loadinglazy、IntersectionObserver、各种库任你选小程序里则要考虑图片域名白名单、图片格式、CDN 链路、以及 iOS 上解码超大图可能导致的内存崩溃。很多小程序项目后来都会专门用云存储压缩图片格式就是因为移动端的视频和图片渲染比 PC Web 要敏感得多。所以小程序比 H5 流畅不是绝对的。它流畅在原生渲染和本地资源上但如果你代码里塞了一堆频繁更新的大数据它一样会卡而且排查起来比 H5 更麻烦。3.3 无法忽略的一层iOS 与 Android 的奇葩表现做移动端开发最怕的不是功能多而是端上的玄学表现。H5 和小程序也逃不开iOS 的 WKWebView 对 ES6 的支持通常是好的但某些低版本会有Date解析问题2024-09-12 12:08:50 和 2024/09/12 12:08:50 在 iOS 上解析结果不一样Android 的老 WebView 性能差异极大尤其是低端机 大图片 复杂 CSS 动画可能在 H5 里毫无征兆地白屏小程序在 iOS 和 Android 上同样有差异比较典型的是顶部导航栏高度、安全区适配、键盘弹起时页面挤压的表现。很多人从 H5 转小程序后在小程序里实现自定义导航栏时才第一次感受到为什么微信的胶囊按钮在不同机型上高度不一样这种问题。做这种移动端项目最有效的方案就是在开发阶段就做真机预览而不是用开发者工具模拟。微信开发者工具里看着很正常的页面在真机上可能因为默认字号、安全区、WebView 内核差异完全走样。4. 开发、调试与上线的双轨节奏效率差比你想象的大这章聊的是很多人选型时会忽略的软成本——开发流程和上线节奏。4.1 H5 的开发调试接近所见即所得H5 开发调试在浏览器里就能完成这是它最大的快乐源泉。浏览器开发者工具、热更新、断点调试一套流程非常成熟。编码阶段的体验是顺的上线也不是什么难事代码推到服务器刷新一下用户看到的就是新版本。哪怕出线上事故回滚也就是改一下 Nginx 配置或者重新发布静态资源。4.2 小程序的开发调试多一步真机预览小程序开发工具也很成熟但模式不同开发阶段有模拟器但很多真机问题模拟器上看不到需要点击预览生成二维码用真机扫码调试真机调试模式下会在手机上开启一个调试连接期间如果你的手机息屏、切后台、或者微信把连接关掉调试就会断小程序的远程调试、性能面板、体验评分都在开发者工具里但实操中一个页面空白的问题往往要结合真机扫码和 vConsole 日志排查。我个人的习惯是写小程序的时候在开发者工具里做功能开发每完成一个页面就用真机过一遍关键交互。特别是涉及权限授权、键盘弹出、滚动穿透、安全区适配这些场景模拟器和真机的表现差得非常多。4.3 上线审核与备案小程序的隐性成本H5 发版上传 → 发布基本没有中间审核。小程序发布上传代码包 → 提交审核 → 微信团队人工/机器审核 → 审核通过后发布如果业务涉及特殊类目电商、医疗、金融还要上传对应资质证书。一般的审核周期在半天到几天不等如果是首次提交经常还会遇到需要补充说明类目选择不清隐私政策缺失这些问题被驳回。还有一点现在特别重要小程序在上线前要做 ICP 备案平台在后台会给出备案入口。我第一次给客户做小程序时帮他填备案信息客户问备案备注信息怎么填我一开始也懵。后来梳理清楚后发现备案备注其实是用来简要说明小程序的服务内容的建议用一句话说清楚业务类型比如本小程序用于提供校园二手物品交易信息发布与查询服务。不要写无测试这类空泛表述审核容易被打回来也不要写得太技术比如前后端数据交互这种服务性质的描述才是审核想看的。这个节奏差异对业务的影响很大。如果你的产品需要频繁调整玩法、做 A/B 测试、快速上线功能H5 明显占优如果你的业务量级大、功能复杂、需要稳定入口小程序多走的审核流程可以换取更规则化的生态和支付能力值得投入。4.4 一个容易被低估的点用户入口小程序最舒服的地方在于微信内的入口非常多分享卡片、扫码、搜索、下拉任务栏、公众号菜单用户点开即可用不需要额外的退出动作。H5 的入口则往往受限于你放在哪里在公众号菜单里用户点开后是微信内置浏览器加载 H5在 App 里通过 webview 打开依赖 App 本身在浏览器里打开你的网址需要用户主动输入或扫码链路更长。但这个优势在特定场景下会反转。比如你的用户根本不在微信生态里你的产品是 PC 端的主站配套移动端那 H5 反而更合适因为它可以被搜索引擎收录、可以被分享到任意平台、不依赖任何宿主。微信小程序过了初期流量红利期后自然获客的难度明显上升现在做小程序更考验精细化运营能力不能只靠微信里能搜到了。5. 按场景选型的判断框架什么项目该选谁技术选型最怕一刀切。下面我按真实业务里常遇见的场景给一个比较直观的矩阵你可以直接对照自己手上的项目判断。场景/需求推荐选择核心原因移动端官网、活动页、品牌展示H5需要快速上线方便分享不依赖审核可被搜索引擎收录电商、支付、社交、工具类产品小程序支付闭环顺畅微信生态集成度高留存路径清晰已有 App 需要嵌 HTML 活动页H5内嵌 WebView 加载动态更新方便无需重复发包低频工具类如计算器、体检查询H5开发成本低无需小程序审核和资质中高频业务系统、多模块产品小程序持久入口清晰原生渲染体验稳定后续可迭代扩展需要地理位置、扫码、蓝牙等能力小程序原生 JavaScript Bridge 能力完备需要 SEO、搜索流量直接导入H5小程序基本不被非微信生态搜索引擎收录面向高校、社区、垂直用户群的轻应用小程序分享链路、运营工具、消息触达成熟5.1 电商类小程序近几年更吃香虽然 H5 电商可以通过微信内分享链路打开但用户下单需要跳转微信支付的流程交互成本偏高。小程序里wx.requestPayment直接拉起微信支付整个闭环在微信内完成不需要用户中途跳转浏览器。加上小程序购物车的记忆、订阅消息的订单提醒、分销体系的绑定用户体验明显更好。所以如果你的目标是长期运营的电商业务小程序优先。但也不是没有例外。抖音、百度、支付宝等生态里的 H5 活动页也经常承载秒杀、抽奖这类玩法一旦用户停留在那个 WebView 里它的支付流程可能是支付宝或者各家自己的支付通道那就跟着平台规则走。5.2 内容与品牌展示H5 依然有它的价值品牌官网、活动专题、产品介绍这类页面核心目标是传播和信息展示做小程序反而重了。H5 可以自定动画、配合视觉设计做出非常炫酷的交互而且可以直接分享链接给任意聊天、朋友圈、甚至放在二维码里。加上 SEO 可以带来主动搜索流量对品牌曝光是加分项。还有个常见场景是H5 搭台小程序唱戏——用 H5 做传播落地页拉新用户点击后跳转小程序完成深度服务。两种形态协同是目前很多团队都采用的组合打法。5.3 跨端产品先想清楚哪一端是主角如果你的产品同时需要 App、小程序、H5 三端第一个要确定的就是哪端是主线。多端项目一旦确定主线技术选型、接口设计、基础组件划分都要围绕主线做。我见过最痛苦的跨端项目是三端同步上线、需求又各不一样结果跨端框架的条件编译写得到处都是维护成本暴涨。我的建议是核心业务尽量先在主端跑通验证可行后再把能力复制到其他端。跨端框架是效率工具不应该当架构答案更不应该帮你掩盖产品定义不清的问题。6. 跨端项目里容易踩的坑和一些应急手法最后分享一点实打实的经验都是我从实际项目里踩出来的希望能帮你省点时间。6.1 微信内 H5 的登录授权链路比你想的长几乎没有哪个正经业务能绕开登录。H5 嵌在微信里获取用户信息一般流程是前端判断是否登录未登录则跳转微信 OAuth 授权链接获取 code将 code 传给后端后端调用微信接口换取 openid、session_key后端返回业务登录态 token前端存起来之后带着 token 请求业务接口。这个流程本身不难难在细节。比如 H5 分享到微信打开时如果用户取消过一次授权再次唤起授权会有交互限制再比如部分场景你需要先判断微信是否为企业内部部署的 WebView走不同的授权策略。这些边界情况最好在开发初期就找产品确认清楚不然上线后才发现某个入口的用户根本登录不了是最难受的事。6.2 安卓嵌套 H5 页面的缓存清理很多 App 内的 H5 页面都有缓存问题用户在嵌入了 H5 页面的安卓 App 里修改了个人资料页面刷新后还是旧数据。这个坑的本质是 WebView 缓存策略不是前端代码问题。但前端能做的有三件事设置合理的 HTTP 缓存头比如Cache-Control: no-cache或者对动态接口设置no-store给静态资源文件名加 Hash比如bundle.1a2b3c.js用户不会拉到旧文件在 H5 代码里增加主动清除缓存的操作例如在退出登录时调用特定 API但要结合宿主 WebView 的能力纯前端只能尽量控制静态资源。如果彻底一点可以考虑让 App 开发在 WebView 创建时把缓存模式设为LOAD_NO_CACHE但这属于 App 侧改动。多端联调时这个需求一定要提前同步给客户端开发不然前端做了全套努力App 侧一个缓存开关没开问题依旧。6.3 动态设置小程序页面标题别总想着改导航栏小程序里动态设置标题是个很常见的需求。新手容易上来就写wx.setNavigationBarTitle但需要注意它只能动态设置当前导航栏的文字且navigationStyle不能是custom否则原生导航栏根本不显示这个 API 就失效了。如果你用的是自定义导航栏很多定制化设计都会用动态标题要自己实现——监听页面参数、更新状态、修改自定义标题组件的 data。跨端框架里还要注意小程序端和 H5 端的文档 title 更新逻辑不同不能一套代码想当然通吃。6.4 H5 图片压缩别急着引大库H5 有没有前端压缩图片的方式是个高频问题。方案一直是有的canvas.toBlob()canvas.toDataURL(image/jpeg, quality)这就是最经典的做法。先把图片画到 canvas 上再按目标尺寸和压缩质量输出 Blob再替代原文件上传可以显著降低带宽压力和上传耗时。注意的点是 iOS 上图片 EXIF 方向可能会让 canvas 画出来的图旋转所以画之前要先读一下图片方向必要时用createImageBitmap或者库比如exif-js处理方向。另一个点是 canvas 有最大尺寸限制大图要先等比缩放到合理尺寸再画。6.5 前端安全提醒之前有朋友问H5 渗透思路一般是从哪个口子进的这个我不好展开讲但可以从前端防御的角度提两句H5 项目最常暴露的问题是接口鉴权不严、敏感信息写在前端代码里、用户输入没有做后端的二次校验。这些问题不管是在 H5 还是小程序里本质上都是后端接口设计和数据校验的问题前端的加密、混淆只能延缓不能根治。真正要对业务负责的团队后端接口要做权限校验、参数校验、限流前端不要把涉及核心权限的逻辑全写在用户可见的代码里。6.6 小程序的包体和首屏性能越早优化越好最后唠叨一下小程序的包体。微信小程序的体验评分里有明确要求主包建议控制在 2MB 以下超过这个值就要做分包加载。我见过一套小程序项目光图表库就塞了 800KB首屏加载转圈转得用户直接退出去。后来我们把图表库改为按需加载首屏数据改成接口分页列表页才变得正常。具体可以做的优化使用分包把非首屏页面拆到分包里用户进入对应模块时再加载图片资源尽量用 CDN 和合适的压缩格式别把大图直接放本地页面级别按需引入组件别在全局引入一堆 UI 组件数据列表考虑用recycle-view或者限制渲染条数频繁的数据更新用局部 setData减少传输数据量。这些优化做在前面成本低效果好等项目上线后用户已经流失了再回头优化就很难受了。回到最开始的问题H5 和小程序到底怎么选我的个人体会是这不是选工具的问题而是选生态位的问题。H5 的自由、轻量、热更新、SEO 是它不可替代的优势小程序的微信生态、稳定体验、原生能力让它更适合承载复杂的业务闭环。绝大多数时候两者不是替代关系而是协作关系。遇到需求别急着喊我做个小程序也别上来就写 H5 页面先把用户在哪、业务形态是什么、需要调用什么能力想清楚答案自然就出来了。