This is a series of three articles:

  • Mobile Adaptation – Basics

  • Mobile adaptation – Practice

  • Mobile adaptation – Rem layout

In general, before we do front-end projects, we will get the visual draft and interactive draft first. We can write CSS styles according to the size, color and other information on the visual draft, and we can write JS according to the interactive draft.

Each company has different visual specifications, so does the visual draft. Even in large companies, each department has its own visual code. For example, is the page canvas size base 640 or 750? The resulting file for the front-end developer may also be different, such as a PSD file, Sketch file, or image file, which includes a page file and a cut diagram.

In the projects I’ve worked on, there are several scenarios:

  • Sketch package + general design drawing + picture of each page + cut drawing (one copy for @2x and @3X)
  • PSD source file + general design drawing + pictures of each page (some with size/color labels) + cut drawings (one copy for @2x and @3x)
  • Only for pictures with annotations, I will ask UED for the source file for this, it is difficult to draw all the annotations.

Our UED canvas benchmark is iphone6, but some are Sketch files with canvas width of 375, and some are PSD files with canvas width of 750.

Here is an example of a page I did. On the left is a screenshot of a Sketch file and on the right is an image exported from a PSD file.

This page covers several issues related to mobile adaptation:

  • Layout fit, consistent across devices with different screen sizes
  • Picture hd adaptation, high-definition display of pictures in different resolution devices
  • The 1px border display is consistent across devices with different resolutions
  • Content adaptation, text sizes in devices with different screen sizes

So, we got the visuals, and we’re gonna start coding.

Let’s say we have 750 wide visual art ** one more thing we need to do before we write the CSS. The mobile layout viewport is between 768px and 1024px by default. The screen width is 320px for iphone5, 375px for iphone6 plus and 414px for iphone6 plus.

Isn’t it unfriendly to have to scroll horizontally when browsing a page on a mobile phone, as illustrated below?







  • Set the layout viewport width to a fixed value, and then scale the layout viewport width in proportion to the screen width
  • Set layout viewport width = device width

Set the layout viewport width to a fixed value, scaling the layout viewport width in proportion to the screen width

For example, if the screen width is 375px and the visual image is 750px, set the layout viewport width=750 and scale = 375/750 = 0.5

<meta name="viewport" content="Width = 750, initial - scale = 0.5, the maximum - scale = 0.5, user - scalable = no">
Copy the code

For example, if the screen width is 320px and the visual image is 750px, set the layout viewport width=750 and scale = 320/750

Of course, this needs to be set dynamically according to the screen width:

(function(){
	var doc = window.document;
	var metaEl = doc.querySelector('meta[name="viewport"]');
	if(! metaEl){ metaEl = doc.createElement("meta");
		metaEl.setAttribute("name"."viewport");
	}
	var metaCtt = metaEl ? metaEl.content : ' ';
	var matchWidth = metaCtt.match(/width=([^,\s]+)/);
	var width = matchWidth ? matchWidth[1] : 750
	if(width == 'device-width') {return}
	
	var screenWidth = window.screen.width;
	var scale = screenWidth/width;
	metaEl.setAttribute("content"."width="+ width +",user-scalable=no,initial-scale=" + scale + ",maximum-scale=" + scale + ",minimum-scale="+ scale); }) ()Copy the code

Below is the demo on iphone6 plus, iphone6, and iphone5.

Then some people will ask, given the visual art based on iphone5, canvas width 640? ** That CSS programming according to the visual to, width set 640, in the width 640 layout viewport, CSS style written with the same visual draft, the layout can be the same as the visual draft. The entire page can be displayed in a visual window through dynamic scaling.

So again, what if instead of a 750 wide visual Sketch, you get a 375 wide visual Sketch? The layout port width is set to 375, the CSS style is set to 375, and the dynamic scaling is completed.

Okay, so let’s see if this solves a few of our problems.

Image hd problem

** The real problem is how to make one bitmap pixel cover exactly one physical pixel, so that the image looks the same on different DPR phones.

  • DPR is equal to 1. We need a double plot
  • DPR is equal to 2. You need a 2x plot
  • DPR is equal to 3. You need a 3x plot

The best solution is to load images of different sizes for different DPR

1px border problem

** The real problem is how to make one CSS pixel cover exactly one physical pixel, so that the 1px border looks the same thin on different DPR phones. However, a layout viewport scaling ratio of 1/ DPR is needed to determine whether one CSS pixel covers exactly one physical pixel.

Obviously, this method of scaling according to the width of the layout viewport in proportion to the width of the screen, only devices consistent with the baseline of the visual canvas can be consistent with the visual requirements of the display. For example, only on iphone6, does one CSS pixel cover exactly one physical pixel (horizontal 200px element corresponds to 400 physical pixels, and after scaling by 0.5, horizontal 200px element corresponds to 200 physical pixels, 1:1)?

Layout fit

In fact, you can see directly from the comparison diagram above that the layout is consistent on different devices. The principle is simple: we write CSS visually, then scale it to fit devices of all widths, and the proportions of the elements remain the same.

Content adaptation issues

It’s mainly the text size, because it’s a whole zoom, and the bigger the screen, the bigger the font. It depends on the visual specifications. Some people like it, some want the font size to be the same, and some people want the font size not to scale according to the screen size but to have a specific font size for a certain range of screen widths.

conclusion

[principle]

Set the width of the layout viewport to the width of the visual canvas, and dynamically set the zoom scale= screen width/visual canvas width

“Advantages”

Simple to implement, can solve the layout problem of different screen sizes, in a variety of screens layout consistent

“Defect”

  • [Fixed] 1px borders are not fixed
  • The zoom value depends on the screen width. The demo uses screen.width to get the screen width. In chrome the iphone6 returns a screen width of 375, but in other browsers the zoom value is not always the same, as safari returns 1280.
  • Everything is going to be scaled, like the font, it’s going to be a lot smaller on the iphone5, which is not necessarily what you want.

Set layout viewport width = device width

<meta 
      name="viewport" 
      content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
Copy the code

What’s the effect in this case?

demo2

The picture is too long, put ^^ sideways

Look at that. Look at that. It’s all out. Why? This is a screenshot of iphone6, now set the layout viewport width is the width of the screen 375, our visual draft is according to iphone6 two times the width of 750, that of course will not put, such as the visual draft image placeholder 400px x 400px, our CSS write:

img{
	width: 400px;
	height: 400px;
}
Copy the code

But with a layout viewport width of 375, the image won’t fit. Iphone6 layout viewport width is only 375, let’s scale down all the visual art size to 375. So 750 to 375, we’re going to divide by 2, and we’re going to divide by 2 when we’re writing our CSS.

The image in the visual draft above is 400 x 400, and our CSS will say:

img{
	width: 200px;
	height: 200px;
}
Copy the code

All other elements, such as width and height, borders, inside margins, margins, font size, etc., are divided by 2. So now it looks like this, iphone6 plus, iphone6, iphone5

Now we can see 100% rendering in the visual window. So, have we solved the problem?

**1px border problem set to 0.5px, for 1 physical pixel on a DPR =2 device and 1.5 physical pixels on a DPR =3 device. And setting 0.5px on a device with DPR =2 May not give us the desired effect, as shown below:


It is set to 0.5px, but the browser is still using 1px. Under ios7, on android and other systems, 0.5px will be treated as 0px. Right? So setting it to 0.5px is not feasible. This actually requires one CSS pixel covering exactly one physical pixel.

Layout fit issues because there is no dynamic scaling by device properties, every CSS pixel is the same size on every device, and 200px elements are the same size on every device. In fact, it can be seen from the comparison figure above that the image container (gray background) is the same height in phones with different screen sizes. The whole page needs to be scrolled down in phones with small screens, and the right blank of the four image labels displayed in a row is relatively large in phones with large screens. The layout problem is not solved either.

** Content adaptation issues ** Text size is all the same, also not solved.

One CSS pixel is only one physical pixel

As mentioned several times before, to solve the 1px border problem and achieve consistency across devices with different resolutions (and of course with visual art), one CSS pixel on devices with different resolutions covers only one physical pixel.

Previously we divided the size of 750 artwork by 2 to write the style, which only works on the iphone6. Now we can make one CSS pixel cover only one physical pixel by scaling the layout width = screen width by 1/ DPR.

For example, for 750 visual art, the border of the element is 1px, and we will also write the CSS style:

div{
	border-width: 1px;
}
Copy the code

Then JS dynamically sets the scaling logic to something like this:

var doc = document;
var docEl = document.documentElement;
var isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
var dpr = window.devicePixelRatio || 1;
if(! isIos){ dpr =1 }
var scale = 1 / dpr;
var metaEl = doc.querySelector('meta[name="viewport"]');
if(! metaEl) { metaEl = doc.createElement("meta");
    metaEl.setAttribute("name"."viewport");
    doc.head.appendChild(metaEl)
}
metaEl.setAttribute("content"."width=device-width,user-scalable=no,initial-scale=" + scale + ",maximum-scale=" + scale + ",minimum-scale=" + scale);
Copy the code

Now, no matter what resolution the device is, one CSS pixel is actually one physical pixel. So what does it look like now?

demo3

All elements have been reduced in size by 1/ DPR, essentially 1/ DPR CSS pixel width has been reduced by 1/ DPR. CSS pixels on devices with different DPR have different sizes. So our CSS style of 200px will take up different widths on different DPR devices.

Note: If you view Demo3 on an Android device, it will have the same effect as Demo2, because the DPR is treated to DPR =1, no scaling, and the CSS style is the same as the 750 visual. So it’s not going to work if you just scale and don’t control the layout. ** This can be addressed later when we look at layout adaptation, where the purpose of layout adaptation is to have the same proportion of elements across devices (as in visual artwork).

Solve the layout adaptation problem

Take a look at demo3

  • Phones with different screen sizes are all the same height, so on smaller phones you need to scroll down to see.
  • Select the image TAB to show four on the next line, but on a larger phone the right margin is larger.

So we want the proportions of elements in the layout viewport (width, height, margins, etc.) to be the same across devices how do we get the proportions of elements to be the same in the same style? It’s definitely not going to work in absolute units px, but let’s think about relative units REM.

Suppose there is an element whose width can be expressed as 20rem:

CSS styles Number of CSS pixels
width:20rem 20 * FONT-SIZE of the HTML element
Element ratio = Number of ELEMENT CSS pixels/layout viewport width = 20 * FONT-SIZE of HTML elements/layout viewport widthCopy the code

So just meet:

Constant value * FONT-SIZE of HTML elements = layout viewport widthCopy the code

The element ratio is fixed on any device. We can use the following formula to dynamically set the font size of the HTML element.

Font size = layout viewport width/constant value for HTML elementsCopy the code

The value of this constant can be any constant, but we will make some considerations for styling purposes, such as:

In order to solve the problem of the front 1px border Retina display, the page is scaled 1/ DPR, and the width of the layout viewport of iphone6 is: Font size = 375 * 2/7.5 = 100 for the HTML elements in iphone6, so you can divide the size of the visual image by 100 to get the number of rem units

For 750 visuals based on iphone6 and scaled 1/ DPR, the ratio of font size to layout viewport width of HTML elements can be:

Font-size for HTML elements = layout viewport width /7.5
Copy the code

For 640 visuals based on iphone5, scale by 1/ DPR

Font-size for HTML elements = layout viewport width /6.4
Copy the code

A rough implementation would look like this:

var doc = document;
var docEl = document.documentElement;
var isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
var dpr = window.devicePixelRatio || 1;
if(! isIos){ dpr =1 }
var scale = 1 / dpr;
var metaEl = doc.querySelector('meta[name="viewport"]');
if(! metaEl) { metaEl = doc.createElement("meta");
    metaEl.setAttribute("name"."viewport");
    doc.head.appendChild(metaEl)
}
metaEl.setAttribute("content"."width=device-width,user-scalable=no,initial-scale=" + scale + ",maximum-scale=" + scale + ",minimum-scale=" + scale);
setTimeout(function(){
	var width = docEl.getBoundingClientRect().width;
	docEl.style.fontSize = width / 7.5 + 'px';
})
Copy the code

Since scale=1/ DPR && is based on 750-wide visuals, the CSS style (REM) of an element can be divided directly by the visuals size by 100. The result is:

demo4

Font-size for HTML elements = layout viewport width /10
Copy the code

demo5

Font-size for HTML elements = layout viewport width /7.5
Copy the code

What if my artwork is based on the iphone6, but I’m given a double image width of 375? ** there are generally two types of visual art: 1x and 2x, such as iphone6 based:

Canvas 750, elements 400 x 400 Canvas 375, elements 200 x 200

There are two general types of scaling:

Scale = 1, layout viewport width = 375 CSS pixels Scale = 1/ DPR, layout viewport width = 750 CSS pixels

If the canvas width is 750 and scale=1, the element CSS pixel should be divided by the size in the canvas by 2, so that the layout viewport width of 400/2 x 400/2 in 375 is proportioned to the 400 x 400 element in 750

If the canvas width is 375 and scale=1/ DPR, the element CSS pixel should be multiplied by 2. Make the 200×2 x 200×2 elements in the layout viewport width 750 proportionate to the 400 x 400 elements in the viewport width 375 otherwise, the CSS pixel value of the element is the value in the viewport.

With this in mind, decide on the px/REM conversion values: font size for HTML elements, and then write CSS styles (REM). A few examples:

If the canvas width is 750 and scale=1, font size = 375/7.5 = 50 and 400/2/50 = 4rem for the HTML elements

img{
    width: 4rem;
    height: 4rem;
}
Copy the code

If the canvas width is 375 and scale=1/ DPR, the FONT size of the HTML element is 750/7.5 = 100 and 200 * 2/100 = 4rem

img{
	  width: 4rem;
	  height: 4rem;
  }
Copy the code

Canvas width 750&scale =1/ DPR, FONT size = 750/7.5 = 100, 400/100 = 4rem for HTML elements

img{
	  width: 4rem;
	  height: 4rem;
  }
Copy the code

Canvas width 375&scale =1, FONT size = 375/7.5 = 50, 200/50 = 4rem for HTML elements

img{
	  width: 4rem;
	  height: 4rem;
  }
Copy the code

conclusion

1. Set the FONT size of the HTML element to be proportional to the width of the layout viewport. CSS styles use the relative unit REM, so the element size is proportional to the width of the layout viewport, so that the layout is consistent on each device. Using the visual draft to determine the scale value will be consistent with the layout of the visual draft.

2. Set the zoom ratio to 1/ DPR to solve the 1px border problem. For rem/PX conversion purposes, you can select a ratio value so that the FONT size of the HTML element is 100px. Iphone6 is 7.5, iphone5 is 6.4, and the conversion ratio between REM and PX for different benchmarks is 100. Finally, if you don’t want to dynamically adapt content, you can simply use px units, such as fonts, and 1px borders.

Taobao and netease

The adaptation scheme here is today [2017-08-11], the website scheme may be changed later, so I saved the code, you can see the adaptation code **

Mobile phone taobao

Taobao unified set 10, iphone6 is 1REM = 75px, iphone5 is 1REM = 64px, you can go to mobile Taobao verification. The conversion ratio between REM and PX is different for different benchmarks.

netease

There’s no scaling, just relative rem.

Font-size = layout viewport width /7.5= Device screen width /7.5
Copy the code

On iphone6, the font size of HTML is 375/7.5 = 50px, so if they have a double image, they divide it by 50 to write CSS, and if they have a double image, they divide it by 100 to write CSS.

This ratio can be set at will. According to actual needs, netease set 7.5 to consider simple conversion, while Taobao set 10 to consider compatibility with VW.

conclusion

Dynamically changing the font size and viewport of HTML elements is incompatible on many Android devices. Now that more and more browsers support VW and VH, viewport+ REM is not necessarily the best solution.

There are many other solutions to the 1px border problem.

  • Check whether the terminal type supports 0.5px. If yes, set the border to 0.5px
  • Use CSS to define the style: -webkit-transform: scale(0.5), scale the border
  • Use CSS to implement shadows instead of borders: -webkit-box-shadow:0 1px 1px-1px rgba(0, 0, 0, 0.5)
  • Use CSS to define background-image to implement borders