This article is mainly aimed at beginners of mobile web development readers, the author is also a beginner, there are many misnomers in the article look for readers to correct.

preface

From the beginning of web app development to now, there has been a vague concept of mobile terminal size adaptation. Could say to the media query, rasterize layout, some technical term such as’ fluid layout and the way of implementation, but every time you do a web app development, make product is always unsatisfactory, such as text overflow on the iphone 5, adjust good layout in small size found on mobile location is wrong, It’s masking other elements, or it’s wrapping lines.

If it was before, I did it like this:

Keep writing media queries for compatibility until PM or QA is satisfied.

Such a method has the following problems:

  1. It’s hard to fit all phone screen sizes. There will always be incompatible sizes. The problem is still there, it’s just not discovered yet.
  2. It’s so tired. it’s so exhausting. In particular, these problems will generally be concentrated in the online before being put forward, and that time is the greatest pressure.

I thought about why there would be a case of treating the symptoms but not the root cause:

  1. Did not coordinate the specification with the UI at the beginning of the project.
  2. There are not too many test machines around, can not test too comprehensive.
  3. Not realizing that mobile adaptation is a tricky issue.

So, is there one of thoseOnce and for all.Full size support.It's a no-brainerMobile terminal size adaptation scheme?

** Of course there is. ** The author combined with their own read a few popular blogs, summed up a few useful knowledge points, hoping to let readers quickly grasp and use this’ once and for all method ‘. Be lazy when you can be lazy. 🐷 (a popular blog title with flexible Github Repo shown here)

What we’re trying to achieve

  • Develop directly from the dimensions above the UI annotated visual draft. As indicated230px, which is converted by a functionremYou don’t have to do it by hand.
  • The page looks the same visually on most phones.

What is a rem

In short: if the < HTML > tag is set to font-size:16px, then 1rem = 16px. So:

Collaboration with UI

First, I need to say a word to UI:

“Mark elements as 750px by 1334px.”

So, what you’ll get is an annotated image like this:

【 Core 】 Dynamic calculation + REM

At this point, we still haven’t addressed the core issue:

  1. You have to convert px into REM yourself. (Probably with a calculator next to it)
  2. Full size fit.

Next, is the most core link, the author through the step diagram to restore the calculation process.

Step 1: Suppose there are three phones with different lengths and widths.

Step 2: Divide the width of the phone into 10 pieces, so each of the above three phones is 35px/36px/37px wide. And add a different font size to the < HTML > tag.

That is: one 35px/36px/37px

Step 3: Calculate the corresponding REM according to the PX annotation diagram of UI:

Step 4: REM will convert it into different px sizes and present it on different mobile phones: (ps: The division result in the picture is wrong)

In this way, you can have the same display effect on different sizes of phones. And the cool part is that this whole process is auto-adaptive. Instead of winking at Chrome Devtools and trying to debug it, developers can just write minustily from the UI annotations.

Code implementation

Dividing the width of the phone into 10 pieces, the width of each of these three phones is 35px/36px/37px. And add a different font size to the < HTML > tag.

Use JavaScript to dynamically calculate the current screen width, cut it into 10 pieces and set the fontSize of < HTML > to 1 unit width.

document.addEventListener('DOMContentLoaded'.function(e) {
    document.getElementsByTagName('html') [0].style.fontSize = window.innerWidth / 10 + 'px';
}, false);

Copy the code

The DOMContentLoaded event is fired after the initial HTML document has been fully loaded and parsed, without waiting for the stylesheet, images, and subframes to complete loading. A different event, Load, should only be used to detect a fully loaded page. MDN::DOMContentLoaded

Calculate the corresponding REM according to the PX annotation diagram of UI

This step requires you to define a px2rem utility function using Sass:

// utils.scss
@function px2rem($px) {$rem : 75px; // '750/10': divided into 10 parts
    @return ($px/$rem) + rem;
}

// foo.scss

.box1 {
 	width: px2rem(320px); // '(320/750) * 10 = 4.266rem'
 }
Copy the code

So what we actually have in our styleSheet is a height of 4.266rem, and how many pixels corresponds to 1rem is precalculated by the JavaScript code above based on the different window. InnerWidth. So auto-adaptation is implemented.

If you don’t want to write px2rem(), you can define the function simply.

Can’t get around viewport and DPR

At the beginning of this blog post, I tried to steer clear of the abstract concepts of viewport and DPR, because it already addresses most problems in one dimension. But if you want to do it better, you have to start from another dimension, and that dimension is DPR.

First, distinguish two concepts:

  1. The device’s pixels
  2. CSS pixels

Here’s a scenario

A front end engineer typed it out

.box {
    width: 100px;
    height:100px;
}
Copy the code

So in this case, he means that the actual size of the box on our screen is 100px by 100px, and here’s what he has in mind:

After the project went live, one user ‘maliciously’ used the magnifying glass function to double the width and length of the project, which now looks like this:

You’ll notice that it takes the Device 200px width and width to render the 100px width and width defined in the CSS. The Ratio of the Device pixels to the style pixels is called the DPR, which is the Device Pixel Ratio. If you still have questions about this concept, see the Viewport analysis.

We all know about Retina displays. The reason they look so high definition is that apple devices take two pixels to render one pixel object, so they must look more refined.

So, if we’re targetingdpr=1Writing therem2px(100px)And so ondpr=2The device will look like a 2x magnified element.

So, if we can query the DPR of the current device and do the corresponding scaling, we can solve this problem.

For example: Some Android devices have a DPR =1, but the UI uses a DPR =2 to create the image, like 750px * 1334px. Elements written directly as 750px by 1334px will be twice as large, so we will make the page twice smaller, how to control?

In the viewport

In short, we’re using viewport here to control the zoom of the screen.

var dpr = window.devicePixelRatio;
meta.setAttribute('content'.'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no'); 
// To help understand if DPR =2, it means that I wrote 100px and rendered it to 200px, so I need to shrink it to 1/2, or 1/ DPR
Copy the code

It’s also worth mentioning that the UI is usually designed at 750px by 1334px because it makes the design more detailed. For example, if we write rem2px(375px), then we will go through the following process to convert the device pixels width of the phone 390px and DPR =3.

  1. rem2px(375px) —-> 5rem
  2. 5rem —–> 195px (Style Pixels)
  3. Style 195 px——> Now it seems to have pixels195*3 = 585pxThe length of the
  4. Set the DPR = 1/3——-> At this point it looks like only195px

In this way, we complete the adaptation from the DPR dimension.

Show me the code:

<script>
  var dpr = window.devicePixelRatio;
  var meta = document.createElement('meta');

  // dpr
  meta.setAttribute('content'.'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no'); 
  document.getElementsByTagName('head')[0].appendChild(meta);

  // rem
  document.addEventListener('DOMContentLoaded'.function (e) {
    document.getElementsByTagName('html')[0].style.fontSize = window.innerWidth / 10 + 'px';
  }, false);
</script>
Copy the code

To prevent global variables from contaminating or overwriting others’ variables, encapsulate them into modules and reuse them.

One More Thing

In the process of writing this blog, I was struggling with the problem that the REM layout and percentage layout felt the same because the REM layout was based on cutting the width to 10 pieces, like 1REM = 10% = 10vw. At one point, I thought I could use percentage layouts. It turns out that if the boxes are nested (which happens a lot), the percentage layout is a problem because the reference frame for the percentage is the parent element, so if we define the 10% width of the child box, we are referring to the parent box instead of the 10% we want for the entire window. InnerWidth. Vw’s code maintainability is not as good as the above scheme, and its compatibility is not as good as REM’s (the difference is not too great).

For more information on PC or mobile layouts, see resources & Credits.

Resources & Thanks

Mobile page adaptation solution

Use Flexible to realize terminal adaptation of H5 page

An introduction to the six layouts + REM layout

DOMContentLoaded vs. Load

How is REM achieved

AlloyTeam Mobile Web adapter

Viewport analysis

lib-flexible