16 KiB
门户全终端自适应技术实现方案
项目:
txw-mhzc-web(Vue 2.6 + vue-cli 4 + TDesign Vue + Less)
目标:移动端重新排版 + 平板/桌面/超宽屏统一自适应,兼顾视觉一致性与可用性
参考站点:上海市企业走出去综合服务平台(固定版心 + 断点响应,非整页 scale)
版本:v1.0 | 2026-05-26
一、方案总览与原则
1.1 技术路线(推荐)
采用 「CSS 设计令牌 + 断点媒体查询 + 流式布局」 为主、「路由级 scale 画布」 为辅的 混合方案:
| 场景 | 策略 | 说明 |
|---|---|---|
| 门户主站(home2、fwsc、gxnlpt、qych 等) | 响应式重排 | 与 segg.sh.gov.cn 同类政务门户一致 |
| 固定画布子系统(iframe 大屏、部分 mhNewMain) | 可选 scale |
仅 meta.fixedCanvas === true 的路由启用 |
| 禁止 | 全站整页 transform: scale |
手机端字糊、触控区缩小、弹层错位 |
视觉一致性 指:品牌色、版心对齐关系、模块层级、间距节奏在各断点可预测变化,而非「桌面缩小版像素级一致」。
1.2 与现有代码的关系
仓库内已具备基础能力,实施时 优先激活与统一,避免重复引入重型框架:
| 资产 | 路径 | 状态 |
|---|---|---|
| 断点常量 | src/pages/index/styles/breakpoints.less |
已定义 |
| 版心 / 栅格变量 | src/pages/index/styles/page-layout.less |
已定义 |
| 移动端全局样式 | src/pages/index/styles/mobile-adaptation.less |
需在 main.js 引入 |
| 验证清单 | docs/test-reports/mobile-adaptation-checklist.md |
已存在 |
| 大屏 scale 试验 | app.vue / mhNewMain.vue |
与门户主流程隔离 |
二、开源方案调研与对比(第一部分交付)
2.1 筛选标准
- 持续维护(近 12 个月有 release 或活跃 commit)
- 社区文档完善、Issue 可检索
- 兼容 iOS 12+、Android 8+、Chrome / Safari / Edge 近两代
- 轻量化:不强制替换 Vue 技术栈
- 集成成本低:与 Vue CLI 4、Less、TDesign 共存
2.2 方案分类说明
自适应实现分四类,门户类项目通常只需 A + 少量 D:
- A. CSS 响应式体系(断点、Grid/Flex、CSS 变量)— 主推
- B. 构建期单位转换(px→vw/rem)— 活动页/H5 子模块可选
- C. 运行时整页 scale(autofit、v-scale-screen)— 仅大屏/数据可视化
- D. JS 能力增强(断点检测、懒加载、resize 节流)— 辅助
以下 不推荐 作为门户主方案全量引入:Bootstrap 全量、Element UI 第二套组件库、整站 rem flexible(amfe-flexible)— 与现有 TDesign + Less 变量体系冲突且收益低。
2.3 对比清单
| 方案 | 类型 | 维护 / 生态 | 核心特性 | 适用场景 | 集成流程(概要) | 优点 | 缺点 |
|---|---|---|---|---|---|---|---|
原生 CSS + 项目令牌(page-layout / breakpoints) |
A | 标准、零依赖 | 变量、@media、Grid、clamp | 门户全站(首选) | 已有;补 main.js 引入 mobile-adaptation.less |
可控、无运行时开销、与 Figma 1440 对齐 | 需逐页改样式 |
| TDesign Vue Row/Col + 断点 | A | 腾讯维护 | 24 栅格、xs/sm/md/lg |
表单、列表、后台区块 | 已依赖,按文档包一层 | 与组件库一致 | 需熟悉 TDesign 断点 API |
| Tailwind CSS(项目已部分引入) | A | 活跃 | 工具类、响应式前缀 md: |
局部快速排版 | vue.config 配 PostCSS;避免与 Less 变量双主源 |
开发快 | 与 Less 混用易混乱,需约束使用范围 |
| postcss-px-to-viewport-modern | B | 活跃 fork | 设计稿 px 自动转 vw | 375 宽 H5 活动页 | vue.config.js → css.loaderOptions.postcss |
一稿多宽省事 | 不适合 1200 版心门户;与变量体系冲突 |
| postcss-pxtorem + lib-flexible | B | 经典但大屏少用 | rem 等比 | 老 H5 | flexible 脚本 + postcss | 移动端成熟 | Vue2 门户性价比低 |
| autofit.js | C | 活跃 | 整页 scale、ignore 节点 | 1920 固定画布大屏 | mounted → autofit.init({ dw, dh, el }) |
接入极简 | 门户手机不可用 |
| v-scale-screen@1.x | C | 活跃 | Vue 2.6 组件包裹 scale | 可视化大屏页 | Vue.use + 包一层 template |
与 Vue 集成好 | 仅适合大屏路由 |
| @fit-screen/vue | C | 中等 | Vue2/3 scale 封装 | 同上 | 需 @vue/composition-api |
类型友好 | Vue 2.6 多一层依赖 |
@vueuse/core useBreakpoints` |
D | 极活跃 | matchMedia 响应式 |
需 JS 切换布局时 | Vue 2.7+ 原生;2.6 用 composition-api | API 优雅 | Vue 2.6 需额外插件 |
| vue-mq / vue-screen | D | 一般 | 断点 inject | 少量组件切换 | 注册插件 + $mq |
简单 | 维护不如 VueUse |
| Container Queries(原生 CSS) | A | 浏览器已普及 | 按父容器宽度适配卡片 | 卡片、侧栏模块 | @container + container-type |
比纯 vw 稳 | 需 postcss 插件做旧版兜底(可选) |
2.4 本项目推荐组合(集成成本最低)
主路径:page-layout.less + breakpoints.less + mobile-adaptation.less + 各页 @media
组件层:TDesign Grid / Drawer(移动菜单)
增强层:v-lazy(已有清单)+ resize 节流 + ECharts resize
隔离路径:meta.fixedCanvas 路由 → autofit 或 v-scale-screen(可选)
不引入 新的 UI 框架;不 全站 postcss-px-to-viewport;不 全站 scale。
三、断点设计规范
3.1 断点表(与 Figma / 现有 Less 对齐)
| 令牌 | 范围 | 设备 | 版心 / 列数策略 |
|---|---|---|---|
xs |
0 – 359px | 小屏手机 | 100% 宽,gutter 12px,栅格 1 列 |
sm |
360 – 480px | 常规手机 | 100% 宽,gutter 16px,栅格 1 列 |
md |
481 – 767px | 大屏手机 / 小平板竖屏 | 100% 宽,gutter 16–36px,栅格 1–2 列 |
lg |
768 – 1023px | 平板 | max-width 100%,部分 2 列 |
xl |
1024 – 1279px | 小桌面 | 版心可 100% 或保留 padding 40px |
2xl |
1280 – 1439px | 标准桌面(Figma 1440 画布) | --page-content-max-width: 1200px |
3xl |
1440 – 1919px | 宽桌面 | 版心 1200 居中,两侧留白随屏宽增加 |
4xl |
≥ 1920px | 超宽屏 | 版心仍 1200;禁止 无限制拉伸内容区 |
Less 常量(已有,建议扩展):
// breakpoints.less
@mq-mobile-xs-max: 360px;
@mq-mobile-sm-max: 480px;
@mq-mobile-max: 767px;
@mq-tablet-max: 1023px;
@mq-desktop-sm-max: 1279px;
@mq-desktop-max: 1439px;
@mq-ultrawide-min: 1920px;
3.2 媒体查询书写约定
- 移动优先(推荐新代码):默认手机样式 →
min-width逐级增强。 - 桌面优先(兼容旧代码):保持现有
max-width块,逐步迁移。 - 禁止 同一属性在多个断点反复覆盖且无变量来源。
- 断点内只改 CSS 变量 或 布局模式(列数、flex-direction),避免魔法数字散落。
3.3 设计令牌扩展(:root)
在 page-layout.less 按断点扩展(示例):
// 平板
@media (min-width: 768px) and (max-width: 1023px) {
:root {
--portal-services-fwsc-cols: 2;
--page-section-padding-y: 48px;
}
}
// 超宽屏:版心不变,仅增大「出血背景」感知
@media (min-width: 1920px) {
:root {
--page-content-max-width: 1200px; /* 保持 */
}
}
四、流式布局适配逻辑
4.1 版心模型(与 segg 类门户一致)
┌──────────────────────────────────────────── viewport ────┐
│ margin-auto │
│ ┌──────────────── page-content-max 1200 ─────────────┐ │
│ │ gutter │ content aligned to nav logo │ │
│ └────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
- 容器:
.page-content-wrap/.page-nav-inner(已有) - 宽度:
width: 100%+max-width: var(--page-content-max-width) - 小屏:
--page-content-max-width: 100%(mobile-adaptation.less已定义)
4.2 栅格与模块列数
| 模块 | ≥1280 | 768–1279 | 481–767 | ≤480 |
|---|---|---|---|---|
| 服务中心四宫格 | 4 列 | 2 列 | 2 列 | 1 列 |
| 共性能力卡片 | 3–4 列 | 2 列 | 2 列 | 1 列 |
| 页脚链接组 | 横排 | 横排/折行 | 纵排 | 纵排 |
| 首页 Hero 搜索 | 横排 | 横排 | 纵排 | 纵排(home2 已部分实现) |
实现方式:
.portal-services-grid {
display: grid;
grid-template-columns: repeat(var(--portal-services-fwsc-cols, 4), minmax(0, 1fr));
gap: var(--portal-services-grid-gap, 24px);
}
4.3 超宽屏策略
- 内容区不随 4K 变宽:保持 1200px 版心,避免行长过长。
- 全宽背景 使用
.home-section-bleed()(已有 mixin)铺满视口。 - 装饰性大图 使用
max-width: 100%+ 居中,而非拉伸版心。
4.4 大屏固定画布(可选子路由)
仅 route.meta.layout === 'fixed-canvas':
scale = Math.min(innerWidth / DESIGN_W, innerHeight / DESIGN_H)
与门户响应式 路由级隔离,避免 app.vue 全局 scale 影响主站。
五、弹性图片与媒体资源
5.1 图片
| 策略 | 实现 |
|---|---|
| 响应式尺寸 | max-width: 100%; height: auto;(mobile-adaptation 已有) |
| 分辨率适配 | <img srcset="..." sizes="(max-width: 768px) 100vw, 1200px"> 对 Banner/大图 |
| 懒加载 | loading="lazy" 或 v-lazy(见 checklist) |
| 格式 | 优先 WebP(构建或 CDN),PNG 用于透明图标 |
| 艺术方向 | 窄屏可选裁切图(picture + source media) |
5.2 视频 / 背景
- 首页 Banner 视频:窄屏降低
preload,必要时poster静帧。 - CSS 背景:
background-size: cover; background-position: center; - 避免固定
1920px背景宽导致小屏横向滚动(参考政务站仅背景层用 1920 的情况)。
5.3 图标与 SVG
- 图标优先 SVG / iconfont,随字号
em缩放。 - Font Awesome 已引入,控制只打包使用子集(长期优化)。
六、响应式交互适配策略
6.1 导航
| 断点 | 行为 |
|---|---|
| ≥768px | 横排菜单(new-nav / nav/index2) |
| <768px | 隐藏横菜单,汉堡 + Drawer/侧滑(mobile-menu-item 样式已有) |
6.2 触控与表单(WCAG 2.5 目标尺寸)
- 可点击区域 ≥ 48×48px(
mobile-adaptation.less) - 输入框
font-size: 16px防止 iOS 聚焦放大 touch-action: pan-y于主滚动容器,减少误触横向滑动
6.3 弹层与固定元素
- TDesign
Dialog/Drawer:窄屏优先placement全屏或底部抽屉。 - 避免 在带
transform的 scale 祖先内挂position: fixed弹层。 - 返回顶部、悬浮客服:小屏抬高
bottom,避开安全区:
padding-bottom: env(safe-area-inset-bottom, 0);
6.4 JS 辅助(按需)
// utils/breakpoint.js
export const BP = { mobile: 768, tablet: 1024, desktop: 1280 }
export function getDeviceClass() {
const w = window.innerWidth
if (w < BP.mobile) return 'is-mobile'
if (w < BP.tablet) return 'is-tablet'
if (w < BP.desktop) return 'is-desktop-sm'
return 'is-desktop'
}
用于:ECharts resize、是否加载重动画、Tab 横滑 vs 下拉。
6.5 图表(ECharts)
window.addEventListener('resize', throttle(() => chart.resize(), 200))
移动端 legend 改底部、减小 grid 边距,在 @media 或 getDeviceClass() 分支配置 option。
七、性能优化措施
| 项 | 措施 |
|---|---|
| CSS | 断点样式集中在 mobile-adaptation.less,避免每组件重复 @media |
| 图片 | 懒加载 + 合适尺寸,首屏 LCP 图不用 lazy |
| JS | resize / scroll 监听必须 throttle(200–300ms) |
| 字体 | 子集化或系统字体栈回退,减少 FOUT |
| 长列表 | 虚拟滚动(TDesign Table 大数据)或分页 |
| 动画 | prefers-reduced-motion: reduce 关闭非必要动效 |
| 构建 | 路由懒加载(已有 vue-router);按页拆分 CSS |
八、落地实施路线图
阶段 0:基线(1 天)
main.js增加:import './styles/mobile-adaptation.less'- 确认
public/index.htmlviewport:width=device-width, initial-scale=1 - 移除或路由隔离
app.vue未使用的全局 scale 逻辑 - 统一断点:新代码引用
breakpoints.less变量
阶段 1:全局与导航(2–3 天)
- 导航:移动 Drawer + 桌面横栏双态完整联调
page-layout.less:补齐 tablet / ultrawide 变量- 页脚、面包屑窄屏折行
阶段 2:核心页面重排(5–8 天)
按 checklist 顺序:
home2/index.vue— 合并零散@media到变量驱动fwsc— 四宫格 + 列表筛选堆叠gxnlpt— 侧栏置顶 + 卡片单列qych— 法案区块与卡片
每页完成即在 mobile-adaptation-checklist.md 打勾。
阶段 3:大屏与回归(2 天)
- ≥1280 / 1920 / 2560 版心居中与背景出血
- 固定画布子路由(若有)单独测 scale
- 桌面回归:与改版前 1280 对齐
阶段 4:验收
- 真机:iOS Safari、Android Chrome,宽度 320 / 390 / 414
- 桌面:1280、1440、1920、2560
- 工具:Chrome DevTools + Lighthouse 移动端评分
九、目录与文件规范(建议)
src/pages/index/styles/
breakpoints.less # 断点常量(唯一来源)
page-layout.less # 版心、间距令牌
mobile-adaptation.less # 全局移动端 @media
mixins/
responsive.less # .respond-to(@bp) 等 mixin(可选新建)
src/pages/index/utils/
breakpoint.js # 设备类名 / matchMedia(可选)
docs/
responsive-adaptation-implementation-plan.md # 本文档
test-reports/mobile-adaptation-checklist.md # 验收清单
Less mixin 示例(可选)
.respond-to(@max) when (default()) {
@media screen and (max-width: @max) {
@content();
}
}
// 使用
.respond-to(@mq-mobile-max) {
.foo { flex-direction: column; }
}
十、风险与决策记录
| 风险 | 缓解 |
|---|---|
| 双轨样式(桌面 scale + 移动重排)冲突 | 路由 meta 明确 layout: portal | fixed-canvas |
| TDesign 组件窄屏溢出 | 表格外包 .table-scroll-x { overflow-x: auto } |
旧页大量魔法 @media |
逐页迁移,不一次性重写 |
| 超宽屏内容过宽 | 严格 max-width 1200,不改用 scale 撑满 |
十一、附录:快速集成示例
A. 启用全局移动端样式
// main.js
import './styles/page-layout.less';
import './styles/mobile-adaptation.less';
B. 页面内仅补结构差异
<template>
<div class="page-content-wrap portal-page">
<section class="portal-services-grid">...</section>
</div>
</template>
列数由 --portal-services-fwsc-cols 控制,不在组件内写死 width: 280px。
C. 可选大屏路由(autofit)
// 仅 fixed-canvas 布局的 mounted
import autofit from 'autofit.js'
autofit.init({ dw: 1920, dh: 1080, el: '#fixed-canvas-root', resize: true })
十二、结论
- 移动端重新排版:依赖 CSS 变量 + 断点 + Grid/Flex,激活并扩展现有
mobile-adaptation.less,逐页改造核心视图。 - 大屏/超宽屏:版心锁定 + 背景出血,与 segg.sh.gov.cn 同类,不用 整站 scale。
- 开源框架:不新增重型 UI 框架;可选 autofit / v-scale-screen 仅服务固定画布子系统;主站以 原生响应式 + TDesign 为准。
本文档为实施依据,具体排期可与 mobile-adaptation-checklist.md 联合跟踪。