移动端布局适配hotcss+postcss-pxtorem

栏目: CSS · 发布时间: 6年前

内容简介:本来团队是搞PC端开发的,前段时间架构调整,内端人力不足,所以团队把移动端的工作也一起接过来了。不过由于我们团队以前没开发过移动端的东西,技术积累较少,因此花费了不少时间在基础技术积累上面。这次介绍一下我们的移动端适配方案的改进过程。

本来团队是搞PC端开发的,前段时间架构调整,内端人力不足,所以团队把移动端的工作也一起接过来了。

不过由于我们团队以前没开发过移动端的东西,技术积累较少,因此花费了不少时间在基础技术积累上面。

这次介绍一下我们的移动端适配方案的改进过程。

hotcss库

最开始进行移动端开发时,由于工期比较紧张,为了快速构建整个项目,我最后选择使用了 hotcss 这个库。 这个库的优点其实挺多的:

  1. 使用方便
  2. 支持不同的设计稿尺寸
  3. 支持在js代码中换算适配后的像素
  4. 有效解决1px问题

最开始选用这个库的原因其实也是因为使用方便,当初经过测试之后发现可以比较好的还原设计稿的尺寸后,我们就选择使用这个方案了。

不过由于担心cdn访问延迟和dns解析能问题导致 hotcss.js 资源加载失败,再加上本身源码也不长,我们直接将源码压缩后内联进模板里面。

不过使用一段时间之后,发现hotcss方案确实也有不少的坑。

1px问题

官方号称完美解决1px的问题,但是经过我们QA同学的真机测试,发现在安卓4dpi=1的情况下, 1pxborder 经过 px2rem 的转换后,还是会有问题,所以我们为了兼容1dpi的手机,不得不专门写了一个 border 的兼容方案(其他css样式同理):

@mixin border-bottom($width: 1) {
  border-bottom: px2rem($width) solid map-get($defaultColor, borderColor);
  [data-dpr='1'] & {
    border-bottom-width: $width + 'px';
  }
}
复制代码

设计稿尺寸问题

其实这个问题并不是hotcss库本身的问题,应该让UI同学出设计稿的时候,给前端同学一套统一的尺寸。

但是我们最开始的UI同学由于个人习惯问题,有的给我们的是iOS尺寸的设计稿,这种的尺寸是375px的,有的是安卓尺寸的设计稿360px的。而 hotcss 这个库需要提前声明 $designWidth 这个变量,之后使用 px2rem() 方法的时候才会进行替换,由于css没有作用域的概念,当碰到单页应用的时候两种尺寸的设计稿就会出现问题。

不过好在我们目前的移动端页面大部分都不是单页应用,少数几个单页应用也是同一尺寸的设计稿。但是这个问题总归是一个隐患。

因此我们后续和UI团队沟通,以后出统一的设计稿尺寸。

书写繁琐

说实话虽然使用起来很方便,只需要引入一个官方的sdk就完成了移动端适配方案。但是当写起业务css代码的时候,还是感觉hotcss使用起来很繁琐。

当UI稿中的尺寸是这样的时候:

font-size: 16px;
font-height: 20px;
height: 50px;
width: 200px;
复制代码

我们就不能直接copy过来了,需要对其进行单位转换:

// 这一块代码可以放到common.scss中
@function px2rem($px) {
  @return $px * 320 / $designWidth/20 + rem;
}

$designWidth: 360;

font-size: px2rem(16);
font-height: px2rem(20);
height: px2rem(50);
width: px2rem(200);
复制代码

总之当业务稳定之后,我们慢慢才发现用这个方案还是非常麻烦的,就经常被同事吐槽。

基于以上种种原因,我们团队在升级打包工具webpack->razzle的过程中,改进了适配方案,采用了 hotcss + postcss-pxtorem 结合的方案。

hotcss配合postcss-pxtorem

postcss-pxtorem 这个 工具 库的使用介绍网上也到处都有,这个库的优点在于有很强的转换规则,可以适配各种场景。我们在这里使用这个插件是为了自动进行px->rem的转化,其他过程还是由 hotcss 来进行。

postcss-px2rem的一些参数

require('postcss-pxtorem')({
  rootValue: 75,
  unitPrecision: 5,
  propList: ['*'],
  selectorBlackList: [],
  replace: true,
  mediaQuery: false,
  minPixelValue: 12
})
复制代码
  1. rootValue 是根标签的 font-size 大小
  2. unitPrecision 是转换成rem后的小数位数
  3. propList 是需要转换的属性列表
  4. selectorBlackList 则是一个对css选择器进行过滤的数组,比如你设置为['fs'],那例如fs-xl类名,里面有关px的样式将不被转换,这里也支持正则写法。
  5. minPixelValue 可以设置小于多少尺寸将不会进行转换。

刚好 minPixelValue 这个属性设置为 1px 的时候,就解决了之前 hotcss 的1px的问题。

postcss.cofnig.js

const PostCssFlexBugFixes = require('postcss-flexbugs-fixes');
const autoprefixer = require('autoprefixer');
const px2rem = require('postcss-pxtorem');
const path = require('path');
const designWidth = 360; // 统一的视觉稿尺寸
const rootValue = (designWidth * 20) / 320; // root FontSize
module.exports = ctx => {
  const remInclude = [
    /\.rem\.less$/,
    /\.rem\.scss$/,
  ]; // 白名单,命中白名单则进行px2rem转换,包括.rem.less、.rem.scss结尾的文件
  const useRem = remInclude.some(x =>
    x.test(path.join(ctx.file.dirname, ctx.file.basename))
  );
  return {
    plugins: [
      PostCssFlexBugFixes, //修复某些浏览器的flex bug
      autoprefixer({
        // autprefixer
        browsers: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9'],
        flexbox: 'no-2009'
      }),
      useRem &&
        px2rem({
          rootValue,
          propList: ['*'],
          minPixelValue: 1
        })
    ].filter(Boolean)
  };
};

复制代码

postcss-pxtorem 完成对 rem 的转换,加上之前 hotcssfont-size 值的计算以及对 viewport 的初始化,我们最终完成了移动端的适配方案。

其中设置白名单列表是为了兼容以前老版本使用 hotcss 时候的写法,在升级razzle完毕之后我们后续的样式全部统一使用 .rem.scss 作为文件名后缀了,这样在样式文件中正常写px单位即可, postcss 会自动为我们进行转换。

hotcss缩放scale的坑

最近使用一些第三方插件(如 echarts 和视频播放器等)的时候,发现 hotcss 根据dpi给页面设置的 meta[viewport] 和插件之间会有坑。

<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5, user-scalable=no">

由于第三方插件一般读取过一次页面的scale之后,后续scale的修改不会影响这些样式。

hotcss 会重新根据dpi重新设置scale,这种情况下当css加载得比js慢的时候,就会导致页面样式会闪烁,并且第三方插件的样式都是根据最开始的scale进行布局的,因此在页面放大之后会显得很小。

不过这种情况一般在本地开发的时候才会出现,线上模式静态资源一般放入cdn,访问速度很快,在css加载速度快于js的时候就不会出现这个问题了。

不过为了在本地开发的时候方便观测样式,我们需要在客户端执行js的时候重新将 font-size 设置回1.0。

document.documentElement.style.fontSize = `${(window.innerWidth * 20) /
    320 / window.devicePixelRatio}px`;
let viewportEl = document.querySelector('meta[name="viewport"]');
const content = `width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no`;
if (viewportEl) {
  viewportEl.setAttribute('content', content);
} else {
  viewportEl = document.createElement('meta');
  viewportEl.setAttribute('name', 'viewport');
  viewportEl.setAttribute('content', content);
  document.head.appendChild(viewportEl);
}
复制代码

这样整个页面上的第三方插件在本地调试的时候也是正常大小了~


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java Message Service API Tutorial and Reference

Java Message Service API Tutorial and Reference

Hapner, Mark; Burridge, Rich; Sharma, Rahul / 2002-2 / $ 56.49

Java Message Service (JMS) represents a powerful solution for communicating between Java enterprise applications, software components, and legacy systems. In this authoritative tutorial and comprehens......一起来看看 《Java Message Service API Tutorial and Reference》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具