Why write this article?

Recently the company made a lot of fancy H5 activity, it is not difficult to H5 page actually each front end can write, but in detail has a lot of front-end detail is not so perfect, perfect the H5 page do actually, fit perfect is also a very difficult thing, at least I think so), we summarized below under those things about H5 adaptation

instructions

To better understand this article, you can first read why we often say 1px instead of 2px to get a basic understanding of the concepts of device-independent pixels, CSS pixels, logical pixels, and device pixel ratios

This article is adapted to a series of articles

Universal solutions

Before the study, we can see how big factories are adapting H5

taobao

Address: main.m.taobao.com/

Solution: Flexible

Analysis: It is worth talking about that although Flexible is a solution for mobile terminal adaptation of Taobao team, but mobile Taobao does not seem to use this solution, you can see the following several pictures to draw a conclusion

We are now changing the phone model

It can be found that other people’s adaptation unit is directly px without rem, but the value of PX is calculated through the different dynamics of the mobile phone screen, so when we change the size of Apple, the website will refresh the dynamic calculation of the corresponding PX value, so as to achieve the purpose of adaptation

Just go into a Taobao inside page, found that the use of the adaptation scheme is VW

jingdong

Address: m.jd.com/ solution :rem

Analysis: the adaptation of JINGdong is rough and directMedia queries change the root font size of HTMLThen use theremADAPTS

Bytes to beat

Address: job.bytedance.com/campus/m/po…

Solution: responsive. Js

I think responsive. Js and Flexible. Js of Taobao are essentially the same thing, both dynamically change the FONT size of HTML and then use REM to adapt

Adaptation to summarize

Through the products of these big factories, we can conclude that there are three solutions for mobile terminal adaptation

  • Rem (Mainstream)
  • Vw/VH (part)
  • Direct PX (scene)

So? Is this the end of the article? 😶 This is actually just the beginning of our dry goods for today

Tell me aboutFlexible

Flexible, as the originator of mobile terminal adaptation, is of great research value. And now many mobile terminal H5 are using this scheme for adaptation. Today we will learn its principle

  • 0.3.2 version

The Flexible adaptation principle of this version is to use meta tags to change the scale of the page to achieve the purpose of adaptation. At the same time, this solution can also solve the 1px problem

(function(win, lib) {
  var doc = win.document;
  var docEl = doc.documentElement;
  var metaEl = doc.querySelector('meta[name="viewport"]');
  var flexibleEl = doc.querySelector('meta[name="flexible"]');
  var dpr = 0;
  var scale = 0;
  var tid;
  var flexible = lib.flexible || (lib.flexible = {});

  // If the 
       property has been set, it is based on the currently set property
  if (metaEl) {
    var match = metaEl
      .getAttribute("content")
      .match(/initial\-scale=([\d\.]+)/);
    if (match) {
      scale = parseFloat(match[1]);
      dpr = parseInt(1/ scale); }}else if (flexibleEl) {
    / / same as above
    var content = flexibleEl.getAttribute("content");
    if (content) {
      var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
      var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
      if (initialDpr) {
        dpr = parseFloat(initialDpr[1]);
        scale = parseFloat((1 / dpr).toFixed(2));
      }
      if (maximumDpr) {
        dpr = parseFloat(maximumDpr[1]);
        scale = parseFloat((1 / dpr).toFixed(2)); }}}if(! dpr && ! scale) {// This is the core code for Flexible
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone) {
      // For iOS, use the double solution for 2 and 3 screens, and use the double solution for the rest
      if (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 the double solution
      dpr = 1;
    }
    // Scale 
       according to the DPR tag of the current device
    scale = 1 / dpr;
  }
  docEl.setAttribute("data-dpr", dpr);
  // Set the 
       attribute automatically according to the current 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); }}function refreshRem() {
    // Compatible with iPad and other devices
    var width = docEl.getBoundingClientRect().width;
    if (width / dpr > 540) {
      width = 540 * dpr;
    }
    // Divide the screen into 10 equal parts and set the fontSize
    var rem = width / 10;
    docEl.style.fontSize = rem + "px";
    flexible.rem = win.rem = rem;
  }
  win.addEventListener(
    "resize".function() {
      clearTimeout(tid);
      tid = setTimeout(refreshRem, 300);
    },
    false
  );
  win.addEventListener(
    "pageshow".function(e) {
      if (e.persisted) {
        clearTimeout(tid);
        tid = setTimeout(refreshRem, 300); }},false
  );
  // Set font 12 * DPR
  if (doc.readyState === "complete") {
    doc.body.style.fontSize = 12 * dpr + "px";
  } else {
    doc.addEventListener(
      "DOMContentLoaded".function(e) {
        doc.body.style.fontSize = 12 * dpr + "px";
      },
      false
    );
  }
  refreshRem();
  flexible.dpr = win.dpr = dpr;
  flexible.refreshRem = refreshRem;
  // Utility functions
  flexible.rem2px = function(d) {
    var val = parseFloat(d) * this.rem;
    if (typeof d === "string" && d.match(/rem$/)) {
      val += "px";
    }
    return val;
  };
  flexible.px2rem = function(d) {
    var val = parseFloat(d) / this.rem;
    if (typeof d === "string" && d.match(/px$/)) {
      val += "rem";
    }
    returnval; }; }) (window.window["lib"] | | (window["lib"] = {}));

Copy the code

The adaptation effect is as follows

We can easily see from the source code how to calculate the scale of data-dPR, HTML,body and meta

So let’s just briefly look at the calculation of DPR

    if (isIPhone) {
      // For iOS, use the double solution for 2 and 3 screens, and use the double solution for the rest
      if (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 the double solution
      dpr = 1;
    }

Copy the code

You can see that in this version, only ios DPR is processed, for Android models are the default DPR = 1, obviously this processing is a little unreasonable

For the
tag, you can read a newspaper (the page content is 750px wide) through a frame (375px width of the phone screen). If the frame is close to the newspaper, you can only see the content in the frame area. In order to see all the content, Flexible means that after doing the above things, we can write the size according to the design draft. It will not help us divide the corresponding MULTIPLE of DPR, but it will help us to pull the viewport away to 1/ DPR

  • Flexible - 2.0 -

– in version 2.0, the viewport zoom has been removed, and the 0.5px judgment has been added.

(function flexible(window.document) {
  var docEl = document.documentElement;
  var dpr = window.devicePixelRatio || 1;
  // Set the body font
  function setBodyFontSize() {
    if (document.body) {
      document.body.style.fontSize = 12 * dpr + 'px';
    } else {
      document.addEventListener('DOMContentLoaded', setBodyFontSize);
    }
  }
  setBodyFontSize();
  // Set rem reference value
  function setRemUnit() {
    var rem = docEl.clientWidth / 10;
    docEl.style.fontSize = rem + 'px';
  }
  setRemUnit();
  // reset rem unit on page resize
  window.addEventListener('resize', setRemUnit);
  window.addEventListener('pageshow'.function (e) {
    if(e.persisted) { setRemUnit(); }});/ / detect 0.5 px supports
  if (dpr >= 2) {
    var fakeBody = document.createElement('body');
    var testElement = document.createElement('div');
    testElement.style.border = '.5px solid transparent';
    fakeBody.appendChild(testElement);
    docEl.appendChild(fakeBody);
    if (testElement.offsetHeight === 1) {
      docEl.classList.add('hairlines');
    }
    docEl.removeChild(fakeBody);
  }
})(window.document);

Copy the code

Let’s look at the treatment of the 0.5px problem


  if (dpr >= 2) {
    var fakeBody = document.createElement('body');
    var testElement = document.createElement('div');
    testElement.style.border = '.5px solid transparent';
    fakeBody.appendChild(testElement);
    docEl.appendChild(fakeBody);
    if (testElement.offsetHeight === 1) {
      docEl.classList.add('hairlines');
    }
    docEl.removeChild(fakeBody);
  }
Copy the code

If the device does not support 0.5px, add a class named hairlines above the body, so that our code can be written like this

/* DPR =1 */
.line{
 border:1px solid red;
}
/* DPR >=2 and support 0.5px */
.hairlines .line{
 border:0.5 px. solid red;
}
Copy the code

But there are two problems with this

  • For those whoDPR >2 and 0.5px is not supportedAndroid, how do we unify it?
  • ifdpr=3thenborderIt should be0.3333 px.Rather than0.5 px.Now, butflexibleLet’s use one for each of these caseshairlinesContains the

It seems that Flexible is not perfect, but we can’t deny that flexible is perfect. Let’s get rid of the 1px problem

Tell me aboutvw/vh

Personally, I think vw adaptation principle is the same as Flexible, which is a split window, but one is divided into 10 and the other into 100

We will explain vw in detail when we use it in the next chapter

How to solve1pxThe problem

As I mentioned in my article why 1px is a problem and not a 2px problem,1px is not a problem when it comes to UI requirements. There are often more important bugs to work on projects than 1px, but understanding the nature of 1px can help us understand how mobile adaptation works

solution

Since one CSS pixel represents two physical pixels and the device doesn’t recognize 0.5px, draw 1px and then try to cut the line width in half. Based on this thinking, we have the following solutions

Image method and background gradient

For example, make a 2px image where 1px is the color we want and 1px is transparent. The adaptation process is as follows

Scaling law

This is also the adaptation scheme used by Flexible 0.3.2. We can change the code a little bit

  if(! dpr && ! scale) {var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
      // For 2 and 3 screens, use 2x scheme, and for the rest, use 1x scheme
      if (devicePixelRatio >= 3&& (! dpr || dpr >=3)) {
        dpr = 3;
      } else if (devicePixelRatio >= 2&& (! dpr || dpr >=2)) {
        dpr = 2;
      } else {
        dpr = 1;
      }
    // Scale 
       according to the DPR tag of the current device
    scale = 1 / dpr;
  }
Copy the code

The principle is also very simple, according to the corresponding DPR to adjust the corresponding scaling, so as to achieve the purpose of adaptation, direct scaling of the page feels a little violent

Use pseudo-element scaling

It’s too violent to scale the whole page, can you just scale the borders? The answer is yes we have transform: scale, right

.border1px{
  position: relative;
  &::after{
    position: absolute;
    content: ' ';
    background-color: #ddd;
    display: block;
    width: 100%;
    height: 1px; 
    transform: scale(1.0.5); /* Scale */
    top: 0;
    left: 0; }}Copy the code

conclusion

This article mainly explains the common mobile terminal adaptation and 1px solutions, this chapter mainly talks about the theory, the next chapter we will draw the best practice of mobile terminal adaptation based on actual combat, if you are interested, remember to click 💓