背景:pc端项目原本都是固定写死的宽高,没做适配效果。需求:将pc端的web改造支持ipad显示,保持布局正常。
一、PC端到ipad端的web适配方案
考虑方案有如下几种:
- 动态计算meta标签大小的initial-scale值,进行缩放,默认为1。效果相当于把整个页面缩放 (实验可行,简单暴力)。
通过设置缩放比例达到缩放效果,缺点是无法控制不缩放的元素,因为他是整个项目进行缩放。据说易企秀使用这种方案,因为它们是通过拖拽开发生成手机端web页面,做适配这种最快。
function setScale() {
const viewportWidth = 1920; // 设计稿的宽度
const clientWidth = document.documentElement.clientWidth;
const viewport = document.querySelector('meta[name="viewport"]');
const viewportScale = clientWidth / viewportWidth;
viewport.setAttribute('content', 'width=' + viewportWidth + ', initial-scale=' + viewportScale + ', minimum-scale=' + viewportScale + ', maximum-scale=' + viewportScale + ', user-scalable=0');
if (document.addEventListener) {
const resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'
window.addEventListener(resizeEvt, setRem, false)
document.addEventListener('DOMContentLoaded', setRem, false)
}
}
- postcss-px-to-viewport (未实践)
- pxtorem (当前方案)
二、采用pxtorem方案实现流程
知识点:em是根据父级的字体大小来计算,rem是根据root根节点大小来计算(即HTML标签的font-size),web默认为16px,即1rem=16px。
所以,为了保证移动端多种屏幕分辨率下能自适应缩放到合理效果(视觉窗口),就要先计算在不同像素屏幕下的根节点字体大小,然后rem会再根据这个根节点字体大小在自动适配宽高字体大小边距等。这是实现的思路的解析。
看如下代码实现:
1、 在项目启动时设置html的font-size大小
// 设计稿宽度
const DESIGN_WIDTH = 1920 // 以你的基础设计图宽度为标准,手机端可能是750或是其他标准
export default function setRem(designWidth = DESIGN_WIDTH) {
const docEl = document.documentElement
const resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'
const reCalc = function () {
const clientWidth = docEl.clientWidth
if (!clientWidth) return
// 这里的默认值 100 也可以设置其他值,但需要与第二步的rootValue相同
docEl.style.fontSize = 100 * (clientWidth / designWidth) + 'px'
}
reCalc()
if (document.addEventListener) {
window.addEventListener(resizeEvt, reCalc, false)
document.addEventListener('DOMContentLoaded', reCalc, false)
}
}
2、 安装 npm install postcss-pxtorem。在vue.config.js文件中使用pxtorem插件,该插件会自动把px转化为rem(修改完需要重启项目)
module.exports = {
// 在css下添加引用这个插件
css: {
loaderOptions: {
postcss: {
plugins: [
require('postcss-pxtorem')({
rootValue: 100, // 这个值表示根节点的基础值大小,随意设置,但一定要与第一步的值相同
unitPrecision: 5,
propList: ['*'],
selectorBlackList: [],
replace: true,
mediaQuery: true,
minPixelValue: 0,
// 是否排除转换node_modules下的px,一般不排除,因为使用的ui组件是px为单位也需要转换
// exclude: /node_modules/i
})
]
}
}
},
}
3、 添加meta标签,一般默认都会有的
<meta name="viewport" content="width=device-width,initial-scale=1">
三、遇到的问题,最佳实践解决方案
1、雪碧图怎么适配缩放?
添加background-size属性,必须和当前的图片宽高大小相等,原理是pxtorem也会同步转换它的背景大小。
2、img标签图片大小怎么适配缩放?
使用css给img添加宽高属性,不写行内样式,因为行内样式pxtorem无法转换
3、页面内嵌套iframe怎么适配当前页面 缩放?
- 使用meta强制通过设置initial-scale缩放会有跨域问题
(不推荐)。 - 嵌套的页面也使用pxtorem做转换(
不推荐,工作量大;且可能iframe还有iframe;子页面可能是其他网站改不了) - 使用transform缩放iframe来解决 (推荐)
.mydiv {
position:relative;
width: 500px;
height: 500px;
}
#iframeA {
position: absolute;
transform: scale(.5, .5) translate(-50%, -50%); // 缩放0.5倍
width: 200%;
height: 200%;
top: 0;
left: 0
}
<div class="mydiv">
<iframe id="iframeA" src="http://www.baidu.com" frameborder="0"> </iframe>
</div>
可以js动态计算transform: scale的比例来控制缩放大小,即设计稿宽度 / document.documentElement.clientWidth来设置缩放的准确比例。
4、如何处理1px问题?
画一条1px的线条:
.wrap_div {
height: 1px;
overflow: hidden;
background: #000;
}
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
.wrap_div:before {
transform: scaleY(0.5);
}
}
@media only screen and (-webkit-min-device-pixel-ratio: 3) {
.wrap_div:before {
transform: scaleY(0.33);
}
}
<div className={styles.wrap_div}>
</div>
四、关于调试
知识点:PC端最小字体是12px,移动端则没有限制。所以在电脑上模拟调试ipad效果时候可能会有点不同,字体的显示效果。
五、响应式和固定排版有些区别要注意下(附图)
1、响应式适配:
实现:使用 @media + 百分比% + 动态calc() + rem来写,实现到不同设备屏幕不同布局的不同效果。rem是必须,因为设计移动端的字体大小,布局则用百分比%和@media来控制。
展示效果预览:data.gov.mo/ 切换不同分辨率可查看,根据不同的屏幕大小情况下展示不同的布局,这是响应式布局。
2、固定排版的适配(如在手机端时候):
目的,为了实现不同移动端,假设是手机端,都显示相同的布局相同的效果,即排版不变,看下面图例。
实现:使用固定像素px(rem),即固定宽高,或vw、vh来写。最好不要用百分比%配合px来写宽高边距等。
因为,可能在A机型上面正常,B机型上宽度不够,出现塌缩了。如左右两个div,左边div 300px,右边50%(或是50vw),这种情况容易造成宽度不够影响布局效果;或是里面有文字时宽度不够被压缩出现省略号或者换行的效果(假设我们不想要这种效果)。
请看下面的错误例子:❌