dogc之移动端适配的问题

519 阅读5分钟

因为我们开始都会用<meta name="viewport" content="width=device-width"/>这种方式来做最基本适配,这就会导致每个布局视口的大小都不一样,比如说iphone6是375 * 667、iphone6 plus是414 * 736。而我们在布局时的css大小是固定,导致在不同手机上显示的效果会不一样, 尽管我们可以使用设备独立像素来保证各个设备在不同手机上显示的效果类似,但这并不能保证它们显示完全一致,我们需要一种方案来让设计稿得到更完美的适配。

适配的本质是等比缩放。

viewport适配

通过meta标签改变布局视口的大小。布局视口的大小由设计图纸的大小决定,使之每种机型的布局视口大小一样。例如现在的设计图纸是375px,

<meta name="viewport" content="width=375"/>

这样方式最为简单,但是兼容行不太好,一般在开发中不会使用。

rem适配

em和rem的区别

  • em: 以最近的元素字体大小为基准。
<div class="box1">
  <div class="box2">box2</div>
</div>

<style>
 .box1{
    font-size:10px;
 }
 .box2{
    font-size:20px;
    width:10em;
 }
</style>

上面box2的宽带是200px,如果.box2没有设置font-size的话,则以.box1的字体大小为基准,为100px

  • rem: 以根元素的字体大小为基准
html{
   font-size:10px
}

这个元素只能是html元素。

rem适配实现

  • 首先js动态获取布局视口的大小,给html元素设置一个合理的字体大小。
const htmlwidth=document.documentElement.clientWidth || document.body.clientWidth; // 获取布局视口大小
const htmlDom=document.getElementByTagName('html')[0]; 
const rem = 20;
htmlDom.style.fontSize=htmlwith/rem+'px';

为什么要这么做呢?在vwvh出来之前,css是不知道布局视口宽度的,所以没法根据比例来适配每一个元素,上面的代码通过js变向的获得了布局视口的宽度,不管是什么设备,布局视口的宽度都是20rem

  • 然后根据设计图计算出每个width属性与布局视口的一个比例,即可算出width在不同设备上的宽度。比如,设计图上有一个盒子的width是200px,设计图的整体大小是375px,则:
width: (200/375)*20rem;

上面的计算css本身是不支持的,我们可以借助less来实现计算,具体的可参考less

vw和vh

这种方式和rem的思想是一样的,以布局视口的宽度为基准,通过百分比适配每一个元素。只不过对于vw来说100vw就是布局视口的宽度,不需要通过js来获取布局视口的宽度,我们只需要计算设计图整体大小和每个元素width的比例就可以了,比如,设计图上有一个盒子的width是200px,设计图的整体大小是375px,则:

width: (200/375)*20vh 

上面的写法css是不支持的,我们可以通过插件postcss-px-to-viewport来实现。

1px问题

设备像素比大于1的屏幕上,我们写的1px实际上是被多个物理像素渲染,这就会出现1px在有些屏幕上看起来很粗的现象。

.border_1px:before{
  content: '';
  position: absolute;
  top: 0;
  height: 1px;
  width: 100%;
  background-color: #000;
  transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
  .border_1px:before{
      transform: scaleY(0.5);
  }
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
  .border_1px:before{
      transform: scaleY(0.33);
  }
}

这种方法能适用于各种场景, 虽然还有各种实现方式。

图片适配

位图像素是图像的最小单位, 当1个位图像素对应于1个物理像素,图片才能得到完美清晰的展示。当1个位图像素占据多个物理像素,图片就会失真。当1个位图像素占据少于1个物理像素,图片就会锐化。

现在有一个盒子div, 它的width和height分别是300px300px, 里面要放一个图片且图片要占满整个div, 正好有一张现成的图片是300 * 300(位图像素)的, 如下面代码:

<div>
   <img src="src">
</div>

<style>
  div{
     width:300px;
     height:300px;
  }
  img{
     width:100%;
     height:100%;
  }
</style>

当在设备像素比是1时,图片能正常显示正常; 但在设备像素比为2的时候, 就会失真。为什么呢? 当设备像素比为2时, 实际的物理像素是600px,而图片的位图像素是300 * 300并且占满整个div, 这样就会导致1个位图像素占用2个物理像素。

解决方式

为了保证图片质量,我们应该尽可能让一个屏幕像素来渲染一个图片像素,所以,针对不同DPR的屏幕,我们需要展示不同分辨率的图片。

使用img标签的srcset属性,浏览器会自动根据像素密度匹配最佳显示图片:

<img src="assets_1x.png"
     srcset="assets_2x.png 2x, assets_3x.png 3x">

如果是背景图的话,则可以:

.avatar{
    background-image: url(conardLi_1x.png);
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
  .avatar{
      background-image: url(conardLi_2x.png);
  }
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
  .avatar{
      background-image: url(conardLi_3x.png);
  }
}

这里, 你可能会想如果我都用最大位图像素的图片不就好了吗,就不会出现失真的情况,但是这样会消耗资源,增加带宽。不是一种好的方式。