Advanced-Frontend/Daily-Interview-Question

第 68 题: 如何解决移动端 Retina 屏 1px 像素问题

zeroone001 opened this issue · 10 comments

  1. viewport + rem
  2. background-image

3、scale
4、border-image

1 伪元素 + transform scaleY(.5)
2 border-image
3 background-image
4 box-shadow

rem + viewport

操作步骤如下。在根元素html设置font-size. 将元素转换成rem

通过 window.devicePixelRatio 拿到dpr 再写meta 设置 viewport的scale : 1/dpr

viewport + rem 实现
box-shadow
background-image
0.5px
transformY:scale(.5)

问题是 现在已经没有1px的问题了啊。17以前的BUG了吧?

多屏幕+高清+手机系统字体大小适配 方案:

1rem = 100px
[⚠️]:更改viewport会影响到iframe,若有使用iframe请忽略此方案,可以尝试用https://github.com/evrone/postcss-px-to-viewport

/**
 * @description (多屏幕+手机系统字体+webview+750设计稿)适配方案
 * 1rem = 100px
 */
(function(win, doc) {
  var docEl = doc.documentElement;
  var metaEl = doc.querySelector('meta[name="viewport"]');
  var _dpr = win.devicePixelRatio || 1;
  var _scale = 1 / _dpr;

  var setStyleFontSize = function(num) {
    docEl.style.fontSize = (num > 100 ? 100 : num) + 'px';
  };
  // 计算并设置根元素fontSize
  var calcRem = function() {
    var _rem = (docEl.clientWidth * _dpr) / 7.5;

    /* 设置viewport,进行缩放,达到高清效果 */
    metaEl.setAttribute(
      'content',
      'width=device-width' +
        ',initial-scale=' +
        _scale +
        ',maximum-scale=' +
        _scale +
        ', minimum-scale=' +
        _scale +
        ',user-scalable=no'
    );
    /* 设置data-dpr属性,留作的css hack之用 */
    docEl.setAttribute('data-dpr', _dpr);

    /* 动态写入样式 */
    setStyleFontSize(_rem);

    /* 给js调用的,某一dpr下rem和px之间的转换函数 */
    win.rem2px = function(v) {
      v = parseFloat(v);
      return v * _rem;
    };
    win.px2rem = function(v) {
      v = parseFloat(v);
      return v / _rem;
    };

    win.dpr = _dpr;
    win.rem = _rem;
  };

  /* 解决部分手机webview一开始获取的clientWidth为0,导致font-size为0即1rem=0 的bug */
  var canSetFontSize = function() {
    if (docEl.clientWidth === 0) {
      setTimeout(function() {
        canSetFontSize();
      }, 50);
      return;
    }
    calcRem();
  };
  canSetFontSize();

  /* 解决手机更改系统字体大小的适配问题 */
  var calcScale = function() {
    setTimeout(function() {
      (function() {
        try {
          var realFz = parseInt(win.getComputedStyle(docEl).fontSize.replace('px', ''), 10);

          var expectFz = parseInt(win.rem, 10);
          console.log(realFz, expectFz);

          if (realFz != expectFz && docEl.clientWidth < 750) {
            var realRem = expectFz / (realFz / expectFz);
            setStyleFontSize(realRem);
          }
        } catch (e) {
          console.error(e);
        }
      })();
    }, 50);
  };
  win.onload = function() {
    console.log('onload');
    calcScale();
  };

  var debounce = function(fn, delay, immediate) {
    if (!delay) {
      delay = 300;
    }
    if (!immediate) {
      immediate = false;
    }
    var timer = null;
    return function() {
      var that = this;
      var argumentsCopy = arguments;
      if (immediate && !timer) {
        console.log(immediate, timer);
        fn.apply(that, argumentsCopy);
      }
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(function() {
        if (!immediate) {
          fn.apply(that, argumentsCopy);
        }
        timer = null;
      }, delay);
    };
  };
  win.onresize = debounce(function() {
    console.log('onresize');
    var _rem = docEl.clientWidth / 7.5;
    setStyleFontSize(_rem);
  });
})(window, document);

问题是 现在已经没有1px的问题了啊。17以前的BUG了吧?

@zhongmeizhi 1px像素问题还是存在的呀,难道不是麽?