自适应需要解决的问题

  1. 屏幕像素大小不同,统一表现
  2. 画面比例不同,统一表现
  3. 浏览器字体最小限制,不可能无限等比缩小

自适应不成功的表现:

  1. 画面尤其是图片出现拉伸压缩
  2. 文字内容显示异常,超出范围,显示不全等
  3. 画面出现空白区域

自适应方案

方案一:%单位

作为一个css相对单位,其相对计算的对象不固定(并不是所有元素都相对于父元素宽高),会造成计算的复杂性

方案二:vw/vh

按照占据视宽(高)比例设计

vw/vh缺陷
一些图表的自适应方式需要特别处理

方案三:rem

css 相对单位,相对于根元素的 font-size 值的大小
将设计稿的单位转化为rem单位就可以实现等比例的自适应缩放
随窗口变化响应地调整根元素font size

;(function () {
  let docEle = document.documentElement
  let screenRatioByDesign = 16/9 // 相当于同时给出了宽高
  function setHtmlFontSize() {
    var screenRatio = docEle.clientWidth / docEle.clientHeight;
    var fontSize = ( 
      // 针对比例不对产生白边的优化
      screenRatio > screenRatioByDesign
        ? (screenRatioByDesign / screenRatio)
        : 1
    ) * docEle.clientWidth / 10; // 数值可根据实际换算比例调整

    docEle.style.fontSize = fontSize.toFixed(3) + "px";
  }

  setHtmlFontSize()

  window.addEventListener('resize', setHtmlFontSize)

})();

px自动转化为rem:

  1. 使用 less / sass
  2. 相关插件 postcss-plugin-px2rem
    smart-rem (自动计算rem) 加 postcss-auto-rem (打包px转化为rem 比 px2rem)
    参考博客

rem 局限性
将根元素 fontsize 作为基准,属于一种hack行为;
rem的方案对于1920及以上分辨率屏幕来说基本适用,但当切换到1366*768等小分辨率时,由于浏览器默认最小字体为12px,所以会导致文字比理想效果更大, 而echarts生成的canvas图中单位是以固定px写死的,也会出现超出画布的问题

因此衍生另一种方案: scale缩放

方案四:transform.scale()

通过缩放可以保证字体和canvas一并完成缩放

// index.html
;(function(win){
  var bodyStyle = document.createElement('style')
  bodyStyle.innerHTML=`body{width:1920px; height:1080px!important;}`
  document.documentElement.firstElementChild.appendChild(bodyStyle)

  function refreshScale(){
    let docWidth = document.documentElement.clientWidth;
    let docHeight = document.documentElement.clientHeight;
    var designWidth = 1920,
        designHeight = 1080,
        widthRatio = docWidth / designWidth,
        heightRatio = docHeight / designHeight; // 缩放比例
     document.body.style = `transform:scale(${widthRatio},${heightRatio});transform-origin:left top;`;
   // 应对浏览器 全屏切换前后 窗口因短暂滚动条问题出现未占满情况
    setTimeout(function(){
      var lateWidth= document.documentElement.clientWidth,
        lateHeight = document.documentElement.clientHeight;
      if(lateWidth===docWidth) return;

      widthRatio = lateWidth/ designWidth
      heightRatio = lateHeight/ designHeight
      document.body.style = "transform:scale(" + widthRatio + "," + heightRatio + ");transform-origin:left top;"
    },0)
  }
  refreshScale()

  win.addEventListener("pageshow", function (e) {
    if (e.persisted) { // 浏览器后退的时候重新计算
      refreshScale()
    }
  }, false);
  win.addEventListener("resize", refreshScale, false);
})(window)

自己封装 Vue 组件
第三方 Vue 组件 v-scale-screen

scale() 的弊端:在比例不对的情况下,画面可能会被压缩

其他方案

  • postcss-px-to-viewport(饿了么移动端做法)
    直接计算每个像素在设计稿中占据的%来输出vw,rem
    (转换rem但固定font size)
postcss-px-to-viewport -- vw
postcss-px-to-viewport -- rem

dpr 物理像素 与 设备像素比

  • rem + vw(网易移动端做法)
    vw表示根元素font size, 随后采用rem

  • lib-flexible 前淘宝做法 viewport被广泛支持后此法已被放弃


echarts 可封装 fontSize 来转换数据

function fontSize(res) {
  let docEl = document.documentElement,
    clientWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
  if (!clientWidth) return
  let fontSize = clientWidth / 1920 // 此处 1920 为设计稿的宽度
  return res * fontSize
}

使用 fontSize() 包裹 echarts 各种尺寸的原数据

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐