一、 媒体查询 (Media Queries)
场景: 响应式官网、展示型门户。 弊端: 非平滑跳变(Breakpoint 切换时页面闪烁)、开发工作量巨大。
1. 落地步骤
- 断点设计:根据设计稿(如 1920px, 768px, 375px)定义标准断点。
- 样式覆盖:先写移动端(Mobile First),再通过 @media 覆盖 PC 样式。
2. HTML 模板
<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="mobile.css" media="screen and (max-width: 768px)">
3. 吊打面试官点:如何解决“非平滑跳变”?
“面试官,媒体查询最大的痛点是跳变。我的解决方案是:配合 Flex/Grid 弹性布局使用。通过媒体查询只改变大框架(如一栏变两栏),而内部细节利用 flex-grow 和 clamp() 函数实现平滑过渡,这样即使在断点边缘,视觉也不会生硬。”
二、 REM + Flexible
场景: 移动端 H5 活动页。 弊端: 1px 缝隙、高度无法适配、高频触发 Resize 导致的重排性能开销。
1. 落地步骤
- 引入脚本:在 HTML 头部注入 lib-flexible,动态设置 html.fontSize = window.innerWidth / 10。
- 配置插件:安装 postcss-pxtorem。
- 参数设置:rootValue: 75(若设计稿是 750px)。
2. HTML 模板
codeHtml
<head>
<script src="https://cdn.bootcdn.net/ajax/libs/amfe-flexible/2.2.1/index.min.js"></script>
</head>
<style>
.box { width: 2rem; height: 1rem; border-bottom: 1px solid #000; /* 需要处理 1px */ }
</style>
3. 吊打面试官点:如何解决 1px 边框和舍入缝隙?
“面试官,REM 有两个致命缺陷。 第一:1px 边框变粗。 我通常开启插件的 minPixelValue: 2 忽略 1px 转换,并手动用 伪元素 + transform: scale(0.5) 来绘制真正的 1px 物理像素。 第二:色块间白线缝隙。 这是由于 rem 转换后的小数点舍入误差导致的。我会给相邻色块设置 margin-right: -1px 物理重叠,或者使用 box-shadow: 0 0 1px #color 扩张阴影来填补像素空隙。”
三、 VW / VH (视口百分比)
场景: 现代移动端、全屏背景页。 弊端: 无法限制最大宽度(在大屏平板上元素会巨大无比)、计算繁琐。
1. 落地步骤
- 确定基准:设计稿宽度 375px,则 1vw = 3.75px。
- 配置插件:使用 postcss-px-to-viewport。
2. 吊打面试官点:如何解决“无限拉伸”?
“面试官,VW 方案最怕用户在 iPad 上看手机版。我会通过 CSS 锁(CSS Locks) 或 clamp() 函数来限制范围。例如:width: clamp(300px, 50vw, 800px),确保元素在极小或极大屏幕下都有保底尺寸。”
四、 Transform Scale (大屏首选)
场景: 指挥中心、数据大屏。 弊端: 边缘黑边、地图/Canvas 坐标偏移。
1. 落地步骤
- 固定基准:按 1920x1080 布局。
- 脚本计算:计算 min(window.innerWidth/1920, window.innerHeight/1080)。
2. HTML 模板
<div id="app-container" style="width: 1920px; height: 1080px; transform-origin: 0 0;">
<!-- 业务代码 -->
</div>
<script>
const warp = document.getElementById('app-container');
const setScale = () => {
const s = Math.min(window.innerWidth / 1920, window.innerHeight / 1080);
warp.style.transform = `scale(${s}) translate(-50%, -50%)`;
warp.style.left = '50%'; warp.style.top = '50%';
};
window.onresize = setScale; setScale();
</script>
3. 吊打面试官点:如何解决“黑边”和“文字模糊”?
“面试官,Scale 等比缩放必有黑边。 针对黑边: 我会使用一张跨度极大的背景图(如 4000px 宽)平铺全屏,而核心数据容器居中缩放,视觉上黑边消失。 针对文字模糊: Scale 缩放会导致 Canvas 或高频更新的文本模糊。我会针对这些特定组件进行 反向缩放(Inversed Scaling) ,即父级 scale(0.5),组件内 scale(2),并开启 will-change: transform 强制 GPU 渲染。”
五、 Autofit.js (快速交付)
场景: 甲方要求今天上线的大屏。 弊端: 默认拉伸会导致布局稍微变形(填满屏幕但比例不对)。
1. 落地步骤
- 引入:import autofit from 'autofit.js'。
- 初始化:autofit.init({ designHeight: 1080, designWidth: 1920, renderDom: "#app" })。
2. 吊打面试官点:如何解决“组件被强行拉伸变形”?
“面试官,Autofit 默认是填满全屏,这会导致圆形变椭圆。我会利用它的 ignore 参数,把诸如 实时监控视频、圆形进度条、GIS 地图 设为忽略元素,对这些元素单独采用 CSS 媒体查询或百分比布局,保护它们不发生纵横比畸变。”
在 Vue 2 项目中落地 autofit.js 非常简单,但要达到“工业级”的稳健性,你需要注意初始化时机、销毁逻辑以及局部组件屏蔽。
以下是 Vue 2 项目集成 autofit.js 的保姆级步骤:
1、 安装依赖
npm install autofit.js --save
2、 核心集成逻辑
推荐在 App.vue 中进行初始化,因为 autofit.js 需要操作最外层的 DOM 容器。
<!-- App.vue -->
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
import autofit from 'autofit.js';
export default {
name: 'App',
mounted() {
// 初始化自适应
this.initAutofit();
},
methods: {
initAutofit() {
autofit.init({
designHeight: 1080, // 设计稿高度
designWidth: 1920, // 设计稿宽度
renderDom: "#app", // 渲染的容器ID
resize: true, // 是否监听窗口变化
// ignore: ['.map-container', '.no-scale'], // 忽略缩放的元素
});
}
},
// 落地细节:如果是单页应用,且只有某一个页面需要大屏适配,
// 建议在 beforeDestroy 中关闭,防止影响其他管理后台页面
beforeDestroy() {
// 注意:autofit 目前没有专门的 off() 方法,
// 通常通过 window.onresize = null 或刷新页面处理,
// 或者在 init 时动态判断路由。
}
};
</script>
<style>
/* 必须清除 body 的默认边距,防止计算偏移 */
html, body, #app {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden; /* 大屏通常禁止滚动 */
}
</style>
3、 面试级进阶:如何在 Vue 2 中处理特殊情况?
单纯引入代码只能算“会用”,能处理好以下三个问题才叫“落地”。
1. ECharts 的自适应配合
虽然 autofit.js 缩放了容器,但 ECharts 内部的 Canvas 还是需要手动 Resize 才能保持高清。
codeJavaScript
// 在业务组件中
mounted() {
this.chart = echarts.init(this.$refs.chartRef);
window.addEventListener('resize', this.handleResize);
},
methods: {
handleResize() {
// 延迟执行,等待 autofit 缩放完成后再重绘图表
setTimeout(() => {
this.chart && this.chart.resize();
}, 100);
}
}
2. 地图点击偏移(Ignore 参数的使用)
如果你在 Vue 2 中集成了高德地图或百度地图,scale 会导致点击经纬度发生偏移。
codeJavaScript
// 在 App.vue 的 init 中
autofit.init({
renderDom: "#app",
designHeight: 1080,
designWidth: 1920,
ignore: [
'.amap-container', // 忽略高德地图容器的整体缩放
'.el-notification' // 忽略 UI 库的通知弹窗(防止变形)
]
})
3. 动态设置适配开关(针对混合项目)
如果你的 Vue 2 项目中,只有 /visual 路由是可视化大屏,其他路由是普通的管理后台。
codeJavaScript
// App.vue
watch: {
$route(to) {
if (to.path === '/visual') {
autofit.init({ ... });
} else {
// 退出大屏时,重置 transform,避免普通页面缩放
const dom = document.querySelector('#app');
if (dom) dom.style.transform = 'none';
// 暴力方案:如果是混合项目,建议直接 window.location.reload() 或通过 CSS 变量隔离
}
}
}
4、 为什么在 Vue 2 里它比 REM 方案好?
当面试官问你:“为什么你的 Vue 2 项目选择用 autofit.js 而不是传统的 lib-flexible?”
你可以这样降维打击:
- 开发效率: “REM 方案需要配置 postcss-pxtorem,在开发中看代码全是 rem 单位,调试时不直观。autofit.js 让我直接在 Vue 组件里写 px,标注图是多少我就写多少,大大提升了还原度。”
- 视觉体验(黑边问题) : “普通的 scale 方案在大屏长宽比不一致时会出现黑边。autofit.js 通过运行时计算,反向调整了逻辑宽高,填补了视口空白。在 Vue 2 这种生命周期明确的框架里,它能很好地在 mounted 时接管布局。”
- 局部保护机制: “它提供的 ignore 机制解决了可视化项目中地图、Canvas 在全局缩放下的交互偏移难题。在 Vue 项目中,我可以很方便地通过 CSS 选择器将特定组件排除在缩放逻辑外,这是 REM 方案很难精细化控制的。”
5、 补充:autofit.js 在 Vue 2 中的避坑点
-
z-index 混乱:由于 autofit.js 使用了 transform,根据 CSS 规范,这会创建一个新的“层叠上下文”。如果你有 z-index 极高的弹窗挂载在 body 下,它可能会被 scale 容器遮挡。
- 解决:将所有弹窗通过 getContainer 或 append-to-body="false" 的方式挂载到 #app 内部。
-
计算精度:如果发现页面边缘有 1px 的缝隙,检查是否给容器加了 border,建议使用 box-shadow 代替外边框,避免占据计算位置。
六、 自定义增强 Scale (企业级)
场景: 高端定制化大屏、GIS 深度集成项目。 优势: 坐标点对点精准、局部组件保护。
1. 落地步骤
- 矩阵转换:不只是 scale,而是计算 matrix3d 进行补偿。
- 局部缩放保护:通过全局状态管理(Vuex/Pinia)注入当前的 scale 值。
2. 吊打面试官点:如何解决“地图交互坐标偏移”?
“面试官,在大屏上使用 Echarts 或 Leaflet 地图时,缩放会导致鼠标点击位置和实际反馈点对不上。 我的方案是: 在点击事件触发时,手动对坐标执行逆矩阵运算。将 e.clientX 除以当前的 globalScale 比例。更高级的做法是使用 CSS 的 zoom 属性(虽然有兼容性问题,但在大屏特定的 Chrome 环境下很稳),因为它不会改变元素的物理坐标占据空间。”
总结:我的选型逻辑
- H5 活动页:VW + 1px 伪元素补偿(最顺应标准)。
- 企业看板:Transform Scale + 背景平铺(成本最低,还原度最高)。
- 高交互地图大屏:自定义 Scale + 坐标逆运算(解决交互偏差)。
七、 flexible + rem详解
REM 方案不仅仅是一个 JS 脚本,它是一套包含:动态计算脚本 + 自动转换插件 + 边缘情况处理(1px 问题、最大宽度限制)的完整链路。
以下是三种版本的工程级实现方案:
1、HTML 原生版本 (最底层的原理)
面试点: 为什么要放在 里? 回答: 为了在 DOM 渲染之前就计算好根字号,防止页面因字号突变导致的“闪烁(FOUC)”。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>REM落地方案</title>
<script>
/**
* 核心逻辑:1rem = 1/10 视口宽度
* 设计稿 750px -> 1rem = 75px
*/
function setRem() {
const designWidth = 750; // 设计稿宽度
const maxWidth = 750; // 最大宽度限制,防止在大屏(平板)上字号过大
let width = document.documentElement.clientWidth;
if (width > maxWidth) width = maxWidth;
// 计算根字号:10rem 等于 100% 宽度
const rem = width / 10;
document.documentElement.style.fontSize = rem + 'px';
}
setRem();
// 监听窗口变化和旋转
window.addEventListener('resize', setRem);
window.addEventListener('pageshow', function(e) {
if (e.persisted) setRem(); // 解决部分手机后退不刷新的问题
});
</script>
<style>
/* 落地细节:body 必须重置字号,否则会继承 html 的巨大字号 */
body {
font-size: 16px;
margin: 0;
}
.box {
/* 若设计稿宽度 750px,盒宽 375px,则写 5rem */
width: 5rem;
height: 2rem;
background: #007bff;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
2、 Vue 3 + Vite 工程版本 (生产级)
在 Vue 项目中,你不需要手动写 JS 计算逻辑,通常使用成熟的 amfe-flexible,并配合 PostCSS 自动转换。
1. 安装依赖
npm i amfe-flexible
npm i postcss-pxtorem -D
2. 入口引入 (main.ts)
import { createApp } from 'vue'
import App from './App.vue'
import 'amfe-flexible' // 自动在html注入font-size
createApp(App).mount('#app')
3. 配置 Vite (vite.config.ts)
面试点: “我配置了 selectorBlackList 来避免 UI 组件库(如 Vant)的尺寸也被缩小。”
import { defineConfig } from 'vite'
import postCssPxToRem from 'postcss-pxtorem'
export default defineConfig({
css: {
postcss: {
plugins: [
postCssPxToRem({
rootValue: 75, // 设计稿 750px,1rem = 75px
propList: ['*'], // 所有属性都转换
selectorBlackList: ['.norem'], // 过滤掉不需要转换的类名
exclude: /node_modules/i // 排除第三方库,如果要适配 Vant 则不加这行
})
]
}
}
})
3、 React + Webpack/CRA 版本 (兼容性处理)
在 React 体系中,如果是使用 Ant Design Mobile,适配方案略有不同。
1. 安装依赖
npm i amfe-flexible
npm i postcss-pxtorem -D
2. 入口引入 (index.js)
import 'amfe-flexible';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
3. 修改配置 (通过 craco 或 eject)
React 项目通常不暴露 Webpack 配置,推荐使用 @craco/craco。
// craco.config.js
const pxToRem = require('postcss-pxtorem');
module.exports = {
style: {
postcss: {
mode: 'extends',
loaderOptions: {
postcssOptions: {
ident: 'postcss',
plugins: [
pxToRem({
rootValue: 75,
propList: ['*'],
// 特别注意:针对 antd-mobile,它的设计稿是 375
// 如果你的设计稿是 750,需要在这里做逻辑判断
exclude: /node_modules/antd-mobile/i
}),
],
},
},
},
},
};
4、 深度进阶:吊打面试官的 4 个落地细节
如果你能在回答完以上代码后,补充以下几点,面试官会觉得你是有大型项目落地经验的:
1. 解决 1px 边框变粗问题
问题: 750 设计稿上的 1px,在手机上会变成 0.5 物理像素,但 CSS 写的 1px 在高清屏下显得很粗。 解法: 使用伪元素 + transform: scaleY(0.5)。
codeCSS
.hairline-border {
position: relative;
}
.hairline-border::after {
content: "";
position: absolute;
top: 0; left: 0;
width: 200%; height: 200%;
border: 1px solid #ddd;
transform: scale(0.5);
transform-origin: 0 0;
}
2. 解决 Canvas 渲染模糊
问题: 在 REM 布局下,Canvas 画布内部坐标系会失真。 解法: 必须手动获取 window.devicePixelRatio(DPR),并在绘制前将 Canvas 的 width 和 height 属性放大 DPR 倍,再用 CSS 缩回来。
3. 字体不推荐用 REM
面试点: “虽然宽度用了 REM,但我通常建议字体大小使用 px 配合媒体查询,或者直接用 px。因为我们不希望在大屏幕上看到巨大的文字,而是希望看到更多的内容。”
4. 解决“页面瞬间闪烁”
终极回答: “在 Vite/Webpack 构建时,我会将计算 rem 的内联脚本直接注入到 index.html 的 HTML 标签之前(利用 html-webpack-plugin 或 vite-plugin-html),而不是等待 JS Bundle 加载。这样可以确保在首屏绘制时,rem 基准值已经就绪。”
八、 vw vh详解
1、 核心原理:舍弃 JS,回归原生
VW (Viewport Width) 和 VH (Viewport Height) 是 CSS3 提供的原生单位。
- 1vw = 视口宽度的 1%
- 1vh = 视口高度的 1%
- 本质:它直接将设计稿的像素(px)映射为视口的百分比,不再需要像 REM 那样通过 JS 动态修改根字号,减少了主线程的计算开销,彻底杜绝了页面闪烁(FOUC) 。
2、 移动端 H5 落地方案(工程化)
在 H5 开发中,手动计算 100 / 750 * 100 = 13.333vw 是极其低效的。我们通过 PostCSS 自动化流水线 来解决。
1. 核心插件配置 (Vue/React 通用)
目前最主流的是 postcss-px-to-viewport-8-plugin(兼容性最好)。
安装:
npm install postcss-px-to-viewport-8-plugin -D
PostCSS 配置 (postcss.config.js):
module.exports = {
plugins: {
'postcss-px-to-viewport-8-plugin': {
viewportWidth: 750, // 设计稿宽度 (iPhone 2倍图)
unitPrecision: 3, // 转换后的精度,保留3位小数
viewportUnit: 'vw', // 转换成的单位
selectorBlackList: ['.ignore-vw'], // 不转换的类名
minPixelValue: 1, // 小于或等于 1px 不转换
mediaQuery: false, // 允许在媒体查询中转换 px
exclude: [/node_modules/], // 排除 UI 库(如果 UI 库是按 375 设计的)
}
}
}
2. 面试必杀点:解决“平板大屏”失真问题
痛点:如果用户用 iPad 打开 750px 的 H5 页面,100vw 会导致 UI 被无限拉大。 解法:设置最大宽度限制。
/* 给 body 设置最大宽度,并水平居中 */
body {
max-width: 540px; /* 经验值:超过此宽度不再随屏幕放大 */
margin: 0 auto;
}
/* 核心:利用 CSS 变量动态锁定宽度 */
:root {
--app-width: 100vw;
}
@media screen and (min-width: 540px) {
:root {
--app-width: 540px;
}
}
/* 页面容器引用此变量 */
.container {
width: var(--app-width);
}
3、 大屏自适应方案(比例锁定流)
在大屏项目中,单纯用 vw 会导致:如果屏幕很宽但很矮,内容会超出底部。 吊打面试官的方案:利用 vmin 实现等比缩放。
1. 什么是 vmin?
- vmin:取 vw 和 vh 中较小的一个。
- 原理:在大屏中,无论屏幕如何变形,我们始终保证内容按照设计稿的比例(如 16:9)缩放在屏幕内部且不溢出。
2. 大屏 CSS 落地逻辑:
假设设计稿是 1920x1080 (16:9)。
// 定义 SCSS 函数自动转换
$design-width: 1920;
$design-height: 1080;
@function px2vmin($px) {
// 核心逻辑:基于最小边进行缩放
@return ($px / $design-width) * 100vmin;
}
.big-screen-box {
width: px2vmin(400); // 无论窗口怎么变,它始终占据屏幕宽度的固定比例
height: px2vmin(300);
background: rgba(0,0,0,0.8);
}
4、 VW 方案的“三大毒瘤”及解法
面试官必问: “VW 方案有什么缺陷?” 你要是能答出这三点,稳了。
1. 1px 像素问题
现象:1px 在转换成 vw 后,由于精度问题可能导致线条消失。 解法:
- 在插件配置中设置 minPixelValue: 1,保证 1px 永远是 1px。
- 使用 transform: scaleY(0.5) 手动处理 Retina 屏的高清边框。
2. 纵横比失效 (Aspect Ratio)
现象:图片原本是正方形,容器宽高都写成 vw,在非标比例屏幕上可能变长方形。 解法:使用 CSS 新属性 aspect-ratio。
.card-img {
width: 20vw;
aspect-ratio: 1 / 1; /* 强制锁定宽高比为 1:1,不再需要写 height */
object-fit: cover;
}
3. 兼容性降级 (非常极端的情况)
现象:虽然几率极低,但如果要求兼容老旧 WebView。 解法:使用 viewport-units-buggyfill 插件,它会自动把 vw 转换成基于 JS 计算的像素值。
九、 详解 Transform Scale
1、 Transform Scale 标准方案:基础落地
1. 实现过程
- 第一步(设计稿): 统一按 1920x1080px(或 3840x2160)出图。
- 第二步(开发): 页面所有元素直接按 px 写死,不写相对单位。
- 第三步(缩放): 编写 JS 动态计算窗口与设计稿的比例,应用到主容器。
2. HTML 模板
<body style="background: #000; overflow: hidden;">
<!-- 大屏主容器,固定宽高 -->
<div id="big-screen" style="width: 1920px; height: 1080px; transform-origin: 0 0; background: url('bg.png');">
<div class="chart">这里是图表</div>
</div>
</body>
<script>
function handleScale() {
const designWidth = 1920;
const designHeight = 1080;
// 计算缩放比例,取宽高中较小的一个,确保内容能完整显示
const scale = Math.min(window.innerWidth / designWidth, window.innerHeight / designHeight);
const screenDom = document.querySelector('#big-screen');
// 应用缩放,并居中显示
screenDom.style.transform = `scale(${scale})`;
// 计算居中偏移量(如果不需要黑边居中,可以去掉这部分)
const left = (window.innerWidth - designWidth * scale) / 2;
const top = (window.innerHeight - designHeight * scale) / 2;
screenDom.style.marginLeft = `${left}px`;
screenDom.style.marginTop = `${top}px`;
}
window.onresize = handleScale;
handleScale();
</script>
2、 标准方案的 3 个致命坑及解决方案
-
坑一:边缘黑边。
- 现象: 当屏幕宽高比与 16:9 不同时,上下或左右会出现难看的黑条。
- 方案: 见下方的“升级方案一”。
-
坑二:文字和 Echarts 图表模糊。
- 现象: scale 属于位图缩放,当缩放倍数较小时,文字和图表边缘有毛刺。
- 方案: Echarts 渲染器切换为 svg 模式(echarts.init(dom, null, {renderer: 'svg'}));对于文字,使用 initial-scale 优化或设置 text-rendering: optimizeLegibility;。
-
坑三:地图点击坐标偏移。
- 现象: 在缩放后的容器内使用 Leaflet 或原生鼠标事件,点击位置对不上。
- 方案: 见下方的“升级方案二”。
3、 升级方案一:铺满全屏 + 逻辑留白(视觉完美版)
场景: 甲方不能接受黑边,但要求图表不拉伸。
-
思路: 背景图(Theme Background)拉伸铺满全屏,而真正的内容容器(Content)保持等比缩放。
-
实现步骤:
- body 设置一张 4K 的星空/科技感背景图,设置为 background-size: 100% 100%。
- 内部内容容器(设计稿尺寸)依然用 scale 缩放并居中。
- 吊打面试官点: “我通过双层容器法解决了黑边痛点。外层容器负责用 CSS 绘制充满科技感的底图和流动边框,这些不怕拉伸;内层容器承载精密数据,保持 Scale 等比,这样在任何屏幕上都像是一个完整的沉浸式系统。”
4、 升级方案二:局部补偿算法(企业级高要求版)
场景: 页面里有地图(GIS)、实时监控视频、或者需要在缩放后依然保持 1:1 像素精度的 UI 元素。
-
思路: 在全局缩放的基础上,对特定组件执行“逆缩放”。
-
实现步骤:
- 获取全局缩放值 S。
- 对地图容器应用 transform: scale(1/S)。
- 手动调整该组件的宽高,使其在视觉上看起来恢复了原始大小,但内部渲染是点对点的。
【HTML 模板】
// 核心逻辑:反向补偿
const globalScale = getScale(); // 假设当前缩放了 0.5
// 针对地图组件
const mapDom = document.querySelector('#gis-map');
// 1. 放大两倍抵消全局的 0.5,这样地图内部渲染就是 100% 清晰的
mapDom.style.transform = `scale(${1 / globalScale})`;
// 2. 必须同步修改宽高,否则地图显示区域会缩水
mapDom.style.width = `${originalWidth * globalScale}px`;
mapDom.style.height = `${originalHeight * globalScale}px`;
-
吊打面试官点:
- “面试官,单纯的 Scale 会导致交互坐标偏移。在做 高精度 GIS 交互 时,我会重写坐标计算逻辑:const realX = e.clientX / currentScale。
- 更高级的解决办法是:在大屏常用的 Chrome 环境下,我会优先使用 zoom 属性替代 transform: scale。因为 zoom 是真实的空间缩放,浏览器会自动处理鼠标事件的坐标转换,不会产生偏移,且不会触发 BFC 异常。”
5、 两种升级方案对比选型
| 方案 | 核心技术 | 解决的问题 | 适合场景 |
|---|---|---|---|
| 升级方案一 (Padding-Fill) | 双层布局 + 居中 Scale | 彻底消除黑边,视觉一致性强 | 多数常规数据可视化看板 |
| 升级方案二 (Inversed Scale) | 反向缩放 + 坐标校正 | 解决地图模糊、点击偏移、视频拉伸 | 智慧城市、GIS 地图、公安指挥中心 |
总结实现流程:
-
拿到设计稿: 确认是 1920 还是 16:10(如 1920x1200)。
-
基础开发: 使用 px 配合百分比或 Flex 完成基础布局。
-
注入 Scale: 使用脚本控制 #app 缩放。
-
避坑检查:
- 检查图表文字是否模糊 -> 切换 SVG 渲染。
- 检查地图点击准不准 -> 执行 1/S 坐标补偿。
- 检查两侧是否有黑边 -> 外层铺满背景图遮瑕。