我家等离子电视也能用的移动端适配方案
前几天我的领导“徐江”让我把一个移动端项目做一下适配,最好让他在家用等离子电视也能看看效果,做不出来就给我“埋了”,在这种情况下才诞生了这篇文章~
什么是移动端适配
移动端适配是指在不同尺寸的移动端设备上,页面能相对达到合理的显示或者保持统一的等比缩放效果
移动端适配的两个概念
- 自适应:根据不同的设备屏幕大小来自动调整尺寸、大小
- 响应式:会随着屏幕的实时变动而自动调整,是一种自适应
而在我们日常开发中自适应布局在pc端和移动端应用都极为普遍,一般是针对不同端分别做自适应布局,如果要想同时兼容移动端和pc端,尤其是等离子电视这样的大屏幕,那么最好还是使用响应式布局~
移动端适配-视口(viewport)
在一个浏览器中,我们可以看到的区域就是视口(viewport),我们在css中使用的fixed定位就是相对于视口进行定位的。
在pc端的页面中,我们不需要对视口进行区分,因为我们的布局视口和视觉视口都是同一个。而在移动端是不太一样的,因为我们的移动端的网页往往很小,有可能我们希望一个大的网页在移动端上也可以完整的显示,所以在默认情况下,布局视口是大于视觉视口的。
<style>
.box {
width: 100px;
height: 100px;
background-color: orange;
}
</style>
<body>
<div class="box"></div>
</body>
pc端展示效果
移动端展示效果
从上图可以看出在移动端上同样是100px的盒子,但是却没有占到屏幕的1/3左右的宽度,这是因为在大部分浏览器上,移动端的布局视口宽度为980px,我们在把pc端的页面切换成移动端页面时,右上角也短暂的显示了一下我们的布局视口是980px x 1743px。
所以在移动端下,我们可以将视口划分为3种情况:
- 布局视口(layout viewport)
- 视觉视口(visual layout)
- 理想视口(ideal layout)
这些概念的提出也是来自于ppk,是一位世界级前端技术专家。
贴上大佬的文章链接quirksmode.org/mobile/view…
所以我们相对于980px布局的这个视口,就称之为布局视口(layout viewport),而在手机端浏览器上,为了页面可以完整的显示出来,会对整个页面进行缩小,那么显示在可见区域的这个视口就是视觉视口(visual layout)。
但是我们希望设置的是100px就显示的是100px,而这就需要我们设置理想视口(ideal layout)。
// initial-scale:定义设备宽度与viewport大小之间的缩放比例
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
移动端适配方案
- 百分比设置
- rem单位+动态html的font-size
- flex的弹性布局
- vw单位
在我们移动端适配方案中百分比设置是极少使用的,因为相对的参照物可能是不同的,所以百分比往往很难统一,所以我们常常使用的都是后面3种方案。
rem单位+动态html的font-size
rem单位是相对于html元素的font-size来设置的,所以我们只需要考虑2个问题,第一是针对不同的屏幕,可以动态的设置html不同的font-size,第二是将原来的尺寸单位都转换为rem即可。
talk is cheap, show me the code
/*
* 方案1:媒体查询
* 缺点:需要针对不同的屏幕编写大量的媒体查询,且如果动态的修改尺寸,不会实时的进行更新
*/
<style>
@media screen and (min-width: 320px) {
html {
font-size: 20px;
}
}
@media screen and (min-width: 375px) {
html {
font-size: 24px;
}
}
@media screen and (min-width: 414px) {
html {
font-size: 28px;
}
}
.box {
width: 5rem;
height: 5rem;
background-color: orange;
}
</style>
<body>
<div class="box"></div>
</body>
/*
* 方案2:编写js动态设置font-size
*/
<script>
const htmlEl = document.documentElement;
function setRem() {
const htmlWidth = htmlEl.clientWidth;
const htmlFontSize = htmlWidth / 10;
htmlEl.style.fontSize = htmlFontSize + "px";
}
// 第一次不触发,需要主动调用
setRem();
window.addEventListener("resize", setRem);
</script>
<style>
.box {
width: 5rem;
height: 5rem;
background-color: orange;
}
</style>
<body>
<div class="box"></div>
</body>
但是写起来感觉还是好麻烦,如果可以的话我希望白嫖-0v0-
所以我选择 postcss-pxtorem,vscode中也可以下载到相关插件哦,一鱼多吃,😁
vw单位
/*
* 方案1:手动换算
*/
<style>
/** 设置给375的设计稿 */
/** 1vw = 3.75px */
.box {
width: 26.667vw;
height: 26.667vw;
background-color: orange;
}
</style>
/*
* 方案2:less/scss函数
*/
@vwUnit: 3.75;
.pxToVw(@px) {
result: (@px / @vwUnit) * 1vw;
}
.box {
width: .pxToVw(100) [result];
height: .pxToVw(100) [result];
background-color: orange;
}
当然白嫖党永不言输,我选择 postcss-px-to-viewport,贴一下我的配置文件~
module.exports = {
plugins: {
"postcss-px-to-viewport": {
unitToConvert: "px", //需要转换的单位,默认为"px"
viewportWidth: 750, // 视窗的宽度,对应设计稿的宽度
viewportUnit: "vw", // 指定需要转换成的视窗单位,建议使用 vw,兼容性现在已经比较好了
fontViewportUnit: "vw", // 字体使用的视口单位
// viewportWidth: 1599.96, // 视窗的宽度,对应设计稿的宽度
// viewportUnit: 'vw', // 指定需要转换成的视窗单位,建议使用 vw
// fontViewportUnit: 'vw', // 字体使用的视口单位
unitPrecision: 8, // 指定`px`转换为视窗单位值的小数后 x位数
// viewportHeight: 1334, //视窗的高度,正常不需要配置
propList: ["*"], // 能转化为 rem的属性列表
selectorBlackList: [], //指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
mediaQuery: false, // 允许在媒体查询中转换
replace: true, //是否直接更换属性值,而不添加备用属性
// exclude: [], //忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
landscape: false, //是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
landscapeUnit: "rem", //横屏时使用的单位
landscapeWidth: 1134 //横屏时使用的视口宽度
}
}
};
rem单位和vw单位的区别
rem事实上是作为一个过渡方案,它利用的也是vw的思想,并且随着前端的发展,vw的兼容性已经越来越好了,可以说具备了rem的所有优势。
但是我们假想一个这样的场景,我们希望网页在达到800px的时候页面布局不需要继续扩大了,这个时候如果我们采用的是rem布局,我们可以使用媒体查询设置max-width,而vw则始终是以视口为单位,自然不容易处理这样的场景。
当然,vw相比于rem,存在以下优势:
- 不需要计算font-size大小
- 不存在font-size继承的问题
- 不存在因为某些原因篡改了font-size导致页面尺寸混乱的问题
- vw更加的语义化
- 具备rem的所有优点
所以在开发中也更推荐大家使用vw单位进行适配。
来源:juejin.cn/post/7197623702410248251