An overview of the

Flexible was used in the early front-end project to solve the problem of mobile end adaptation, and PX was converted into REM through PX2REM.

Flexible Divides the page into 10 equal portions. The size of each portion is the value of 1rem. This value serves as the fontSize size of the docEl. In HTML documents, a docEl is an HTML tag.

/ / have been scale cyclic treatment var width = docEl. GetBoundingClientRect (). The width; if (width / dpr > 540) { width = 540 * dpr; } var rem = width / 10; docEl.style.fontSize = rem + 'px';Copy the code

In WebPack, the px in the CSS file is converted to REM by configuring the plug-in.

{
  loader: 'postcss-loader'.options: {
    plugins: [
      postcssAutoprefixer({
        browsers: autoprefix
      }),
      px2rem({
        remUnit: 75}),].sourceMap: false,}},Copy the code

RemUnit is set to 75,10 rem is 750px. The iPhone6 physical pixels. It’s consistent with the design.

Designs often have 1px borders and so on, which are converted to 0.013333 REM in code.

Excluding the /* px */ and /* no */ cases, the former is converted to 1.5px on a phone with a DPR of 3, rounded to 2. This is consistent with 2px (most of the time). The latter, at a constant 1px, is also not flexible enough.

The iPhone

Take iPhone6(375 * 667) as an example, devicePixelRadio has a value of 2, initial-scale is 0.5, page enlargement is doubled, and HTML width is 750px. After flexible processing, 1rem is 75px, so 0.013333 REM is exactly 1px, consistent with the design draft.

// Note that the order of code execution is important. Zoom first, then get the width of the HTML. // var width = docEl.getBoundingClientRect().width;if(! dpr && ! scale) { var isAndroid = win.navigator.appVersion.match(/android/gi); var isIPhone = win.navigator.appVersion.match(/iphone/gi); var devicePixelRatio = win.devicePixelRatio;if(isIPhone) {// On iOS, use 2x for screens 2 and 3, and 1x for the restif(devicePixelRatio >= 3 && (! dpr || dpr >= 3)) { dpr = 3; }else if(devicePixelRatio >= 2 && (! dpr || dpr >= 2)){ dpr = 2; }else{ dpr = 1; }}else{// For other devices, still use 1 times DPR = 1; } scale = 1 / dpr; } docEl.setAttribute('data-dpr', dpr);
  if(! metaEl) { metaEl = doc.createElement('meta');
      metaEl.setAttribute('name'.'viewport');
      metaEl.setAttribute('content'.'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
      if (docEl.firstElementChild) {
          docEl.firstElementChild.appendChild(metaEl);
      } else {
          var wrap = doc.createElement('div'); wrap.appendChild(metaEl); doc.write(wrap.innerHTML); }}Copy the code

In the case of iPhone 6/7/8 Plus (414 * 736), the value of devicePixelRadio is 3 and the value of 1 REM is 414 * 3/10 = 124.2px. So 0.013333 REM is around 1.65 rounded to 2. This is consistent with 2px (most of the time). Since the Plus series is wider, the 2px on the Plus and 1px on the non-Plus are visually acceptable.

The android mobile phone

Flexible source, set DPR to 1 directly for Android. Device-width. For my one plus six, device-width is 412. So one rem is 41.2px. CSS writing 1px will be converted to 0.013333 * 41.2 to get a value of 0.55px rounded to 1. I can still see it on my phone,

On Android phones, this may cause a problem, and it may not be visible on the phone when 0.013333 * device-width / 10 < 0.5 (it just might not be). When device-width is less than 375, 1px pixels in CSS may not be visible.

I had this problem with Vivo Y85.

Solve 1px invisible problem

So flexible has been changed to no longer differentiate between iOS and Android. Here’s the code.

if(! dpr && ! scale) { var devicePixelRatio = win.devicePixelRatio; dpr = devicePixelRatio; scale = 1 / dpr; var dataDpr;if(devicePixelRatio >= 2.5&& (! DPR | | DPR > = 2.5)) {dataDpr = 3; }else if(devicePixelRatio >= 1.5&& (! DPR | | DPR > = 1.5)) {dataDpr = 2; }else {
      dataDpr = 1;
    }

    docEl.setAttribute('data-dpr', dataDpr);
}

if(! doc.querySelector('meta[name="viewport"]')) {
    metaEl = doc.createElement('meta');
    metaEl.setAttribute('name'.'viewport'); }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} Not to add may appear page deformation problem. metaEl.setAttribute('content'.'width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
    if (docEl.firstElementChild) {
        docEl.firstElementChild.appendChild(metaEl);
    } else {
        var wrap = doc.createElement('div'); wrap.appendChild(metaEl); doc.write(wrap.innerHTML); }}Copy the code

Scale is still scaled to the device devicePixelRatio so that the width of the HTML is equal to the physical pixels of the device. My one plus 6, for example, the device – width is 412, devicePixelRadio value is 2.625, the document. The documentElement. GetBoundingClientRect (). The value of the width is 1081. It’s almost 412 * 2.625. On many Android machines I’ve tested, both values are within 1. So the value of 1rem is 108.1, and the CSS 1px conversion results in 0.013333 * 108.1 = 1.44, which visually matches 1px.

In theory, to make a 1px pixel invisible, the following conditions need to be met:

0.013333 * device-width * devicePixelRadio / 10 < 0.5
Copy the code

Device-width * devicePixelRadio < 375 device-width * devicePixelRadio < 375 This is only theoretically invisible sufficient and necessary conditions, but in practice it depends on the model. But anyway, this is a safer way to write it than the way we wrote it before.

HTML sets the data-dPR property, which is rounded off devicePixelRatio. When setting a background image (or other behavior) for some elements, set the background image for different pixels depending on the property.

// SCSS mixin syntax
@mixin bg($url1.$url2) {[data-dpr="1"] & {
    background: url($url1) no-repeat top center/750px 670px.#ff776e;
  }
  [data-dpr="2"] & {
    background: url($url1) no-repeat top center/750px 670px.#ff776e;
  }

  [data-dpr="3"] & {
    background: url($url2) no-repeat top center/1125px 1005px.#ff776e; }}Copy the code