Mobile end adapted H5 page

Write pictures described here

First, the basic concept


Learn how to do the front page of H5 adaptation, we should put some of the concepts involved thoroughly understand the mobile terminal, such as: dpr What does it mean?

Moving end doubts H5 - conceptual terms (a)

Second, why do fit the page


Why 2.1 PC-side to resolve browser compatibility

Because the PC side, because too many friends browser type, such as several commonly used: IE, Firefox, Chrome , Safari and so on. At the same time, due to historical reasons, different browsers at different times have some different process (although most of the same), such as the time for the WEB standard: IE6, IE8, IE10 + event handling, etc. For some JS, CSS style rendering different . 
And there are just some people use different versions of different types of browsers, as well as different browsers. So, in order to allow your site to make these different people see the same results, you have to do is compatible, unless these people are not your target audience.

2.2 Why do the mobile terminal adapter

In the end though on the whole most of the mobile browser kernel is webkit, and most of the CSS3 support all syntax. However, the mobile phone screen size is not the same, not the same resolution, or you need to consider the issue of horizontal and vertical screen, and this time you will have to deal with on a different phone, showing the effects of different circumstances.

Another point, UI draft general visual output of only one, such as Taobao will output: 750px width (height is dynamic generally not considered) (details), this time the developers will have a design for this draft, so display screen width at different consistency.

What does it mean the same? Several mentioned below is the main problem.

Third, the main page adaptation problems solved


  1. Element adaptive problem
  2. Text rem problem
  3. HD Picture problem
  4. 1 pixel problem
  5. Horizontal and vertical screen display problems
  6. Phone font scaling problem

3.1 adaptive elements of the problem

For chestnut:

In  1080px visual artwork, a logo upper left corner, width  180px(height problem Similarly available).

Then the logo should be fine to scale what size it in a different phone screen?

In fact, according to scaling, we can generally get the following results:

  • In CSS pixels are  375px on the phone, the display should be? The result is:375px * 180 / 1080 = 62.5px
  • In CSS pixels are  360px on the phone, the display should be? The result is:360px * 180 / 1080 = 60px
  • In CSS pixels are  320px on the phone, the display should be? The result is:320px * 180 / 1080 = 53.3333px

Here are some ideas to achieve:

Scenario 1: Using css media queries @media

@media only screen and (min-width: 375px) {
  .logo {
    width : 62.5px;
  }
}

@media only screen and (min-width: 360px) {
  .logo {
    width : 60px;
  }
}

@media only screen and (min-width: 320px) {
  .logo {
    width : 53.3333px;
  }
}

This program has two of the more prominent issues:

  1. If one kind of screen size more, much more to write a query @media block;
  2. All the elements on the page again had to define different sizes in different @media in, and that price is a little high.

Scenario 2: Using  rem units

Note that our derivation formula:

  • In CSS pixels are  375px on the phone, the display should be? The result is:375px * 180 / 1080 = 62.5px
  • In CSS pixels are  360px on the phone, the display should be? The result is:360px * 180 / 1080 = 60px
  • In CSS pixels are  320px on the phone, the display should be? The result is:320px * 180 / 1080 = 53.3333px
@media only screen and (min-width: 375px) {
  html {
    font-size : 375px;
  }
}

@media only screen and (min-width: 360px) {
  html {
    font-size : 360px;
  }
}

@media only screen and (min-width: 320px) {
  html {
    font-size : 320px;
  }
}

.logo{
    width : 180rem / 1080;
}

Scenario 2 effective solution to the scenario 1, the same elements of a problem in multiple media need to write in here just need to define a few media can generally solve the problem.

But the program still has the following problems:

  1. For different phone resolution, need to write multiple sets of  @media queries, one more model will need to write a query, but now with the mobile phone after another, this page is likely to have on a number of new models problem.
  2. Each element is divided by the size of the design draft of 1080.

For 1080 we can divide directly into the html of font-size, become like this:

@media only screen and (min-width: 375px) {
  html {
    font-size : 375px / 1080;
  }
}

@media only screen and (min-width: 360px) {
  html {
    font-size : 360px / 1080;
  }
}

@media only screen and (min-width: 320px) {
  html {
    font-size : 320px / 1080;
  }
}

.logo{
    width : 180rem;
}

If that becomes the case, then  .logo the css in the draft design will only need to press the case of the size of it. Can it in the end?

The answer is: not .

The main reason is that there is a minimum font browser restrictions:

  • The minimum on PC font-size=12
  • Minimum phone font-size=8

If less than the minimum font, the default font is the smallest font.

Let's look at the above css, such as:

@media only screen and (min-width: 375px) {
  html {
    font-size : 375px / 1080; //0.347222px
  }
}

.logo{
    width : 180rem; //期望结果:375px / 1080 * 180 = 62.5px
}

So when you're so set the font-size, less than the minimum due on your mobile phone font 8px, so the page will be considered in accordance with the default font.

So, ultimately you are the equivalent of such settings:

@media only screen and (min-width: 375px) {
  html {
    font-size : 8px;
  }
}

.logo{
    width : 180rem; //实际结果:1440px
}

Therefore, we set the html font-size when we must guarantee a minimum equal to 8px!

Therefore, in order to solve this problem, we recommend that you use this Css Sass development language, you can define formulas, write css on the convenience.

Sass end-use code is as follows:

@media only screen and (min-width: 375px) {
  html {
    font-size : 375px;
  }
}

@media only screen and (min-width: 360px) {
  html {
    font-size : 360px;
  }
}

@media only screen and (min-width: 320px) {
  html {
    font-size : 320px;
  }
}

//定义方法:calc
@function calc($val){
    @return $val / 1080;
}

.logo{
    width : calc(180rem);
}

Although the above solutions solves the problem, but any course has the following drawbacks:

  1. Different sizes need to write more @media
  2. Css dependent development tools, such as: sass / less etc.
  3. All the places related to the use of rem, all you need to call a method  calc() , this is also very troublesome.


Program 3: js dynamic setting root fonts

Since the program 2 main problem is the need for different screen sizes, multiple definitions  @media, so we first set this font to a dynamic setting.

Note that our derivation formula:

  • In CSS pixels are  375px on the phone, the display should be? The result is:375px * 180 / 1080 = 62.5px
  • In CSS pixels are  360px on the phone, the display should be? The result is:360px * 180 / 1080 = 60px
  • In CSS pixels are  320px on the phone, the display should be? The result is:320px * 180 / 1080 = 53.3333px
//获取手机屏幕宽度
var deviceWidth = document.documentElement.clientWidth;

//将方案二中的media中的设置,在这里动态设置
//这里设置的就是html的font-size
document.documentElement.style.fontSize = deviceWidth + 'px';

requires attention:

document.documentElement.clientWidth this statement to be able to get exactly the premise of the size of the phone is set to establish the following tags in html:

<meta name="viewport" content="width=device-width">
  • 1

Or else to get results will always be: 980

Then you can Sass in accordance with the size of the design draft to write on the line:

//定义方法:calc
@function calc($val){
    @return $val / 1080;
}

.logo{
    width : calc(180rem);
}

If you do not consider other factors, but generally fit the page element, then the program will meet the basic requirements, but in reality, we in fact there are a lot of problems, so we also need to continue to optimize the program.

 

3.2 rem text issues

Text also used rem units what is the main problem?

  1. Rem may occur through the calculation, the final show to be 23.335px such a wonderful font size on the page, and therefore may also appear jagged, blurred and other issues;
  2. For the big screen want to line shows the text a little more, a little less small-screen display, rather than displaying all treated equally as much text. Such words seem particularly large (hereinafter the large screen  3.5 横竖屏显示问题 will carefully speak).

For these questions, my personal suggestion:

  1. For wonderful font problems, in fact, the performance of the phone did not so obvious, mainly because the screen display is now unified in number, html font display is also optimized to do so, if the product is not critical and can not be considered processing;
  2. For horizontal and vertical screen problem, look at the situation right, if not critical, and can not be considered.

If we have to solve this problem, then do not use rem font scheme, but rather continue to use px units.

We mentioned above,  大屏 小屏 in fact, the implication is not a big-screen phone, but the phone's screen resolution is not the same, in fact, is dprnot the same, so we set a specific font for different dpr it.

For example, we font size for the title of the page can be set as follows:

.title {
    font-size: 12px;
}
[data-dpr="2"] .title {
    font-size: 24px;
}
[data-dpr="3"] .title {
    font-size: 36px;
}

 

Figure 3.3 HD problem

First take a look at  this article, I have to explain why you want to use on some screen  @2x @3x high-definition map.

Let's look here to explain the solution to specific high-definition map.

I am here briefly summarized below.

3.3.1 For labels introduced high-definition picture Solutions

1, the use of  srcset labels

<img src="http://g.ald.alicdn.com/bao/uploaded/i1/TB1d6QqGpXXXXbKXXXXXXXXXXXX_!!0-item_pic.jpg_160x160q90.jpg" srcset="http://img01.taobaocdn.com/imgextra/i1/803091114/TB2XhAPaVXXXXXmXXXXXXXXXXXX_!!803091114.jpg 2x, http://gtms04.alicdn.com/tps/i4/TB1wDjWGXXXXXbtXVXX6Cwu2XXX-398-510.jpg_q75.jpg 3x">

Notes srcset of: Mengchuo here

2, using js own  Image asynchronous loading images

//html
<img id="img" data-src1x="[email protected]" data-src2x="[email protected]" data-src3x="[email protected]"/>
//js
var dpr = window.devicePixelRatio;
if(dpr > 3){
    dpr = 3;
};

var imgSrc = $('#img').data('src'+dpr+'x');
var img = new Image();
img.src = imgSrc;
img.onload = function(imgObj){
    $('#img').remove().prepend(imgObj);//替换img对象
};


3.3.2 HD solution for the background image

1,  media query to process

/* 普通显示屏(设备像素比例小于等于1)使用1倍的图 */
.css{
    background-image: url(img_1x.png);
}

/* 高清显示屏(设备像素比例大于等于2)使用2倍图  */
@media only screen and (-webkit-min-device-pixel-ratio:2){
    .css{
        background-image: url(img_2x.png);
    }
}

/* 高清显示屏(设备像素比例大于等于3)使用3倍图  */
@media only screen and (-webkit-min-device-pixel-ratio:3){
    .css{
        background-image: url(img_3x.png);
    }
}

2,  image-set to handle (there are compatibility issues)

.css {
    background-image: url(1x.png); /*不支持image-set的情况下显示*/
    background: -webkit-image-set(
            url(1x.png) 1x,/* 支持image-set的浏览器的[普通屏幕]下 */
            url(2x.png) 2x,/* 支持image-set的浏览器的[2倍Retina屏幕] */
            url(3x.png) 3x/* 支持image-set的浏览器的[3倍Retina屏幕] */
    );
}

3.4 1像素问题

What is the pixel problem?

We are talking about one pixel, meaning 1 CSS pixel. 
For example, designers actually a line, but looking at on some phones obviously very thick, and why? 
1px Because of this, in some devices (for example: dpr = 3), is to use the physical vertical, is 3 pixel matrix (i.e.: 3x3 = 9 CSS pixels) Display this 1px, results in these devices, this line It looks very rough! 
In fact, on the phone should be 1 / 3px display this line.

1: Use of css3 scaleY (0.5) to resolve

For example: 1px div problem of border-top solution.

.div:before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: auto;
  right: auto;
  height: 1px;
  width: 100%;
  background-color: #c8c7cc;
  display: block;
  z-index: 15;
  -webkit-transform-origin: 50% 0%;
          transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
  .div:before {
    -webkit-transform: scaleY(0.5);
            transform: scaleY(0.5);
  }
}
@media only screen and (-webkit-min-device-pixel-ratio: 3) {
  .div:before {
    -webkit-transform: scaleY(0.33);
            transform: scaleY(0.33);
  }
}

However, this program can only solve the problem straight line, involving the fillet and the like, they do nothing !

Scenario 2: page zoom to solve the problem

We'll attempt to page zoom principles to solve problems 1px show.

First we need to understand some  viewport common sense, refer to: here

If the phone dpr=2

对于dpr=2的手机设备,1px就会有 2x2 的物理像素来渲染,但是当缩放以后其实就变成 1x1 个单位渲染了,看下面示意图:

所以,我们的思路就是将整个页面缩小dpr倍,再将页面的根字体放大dpr倍。这样页面虽然变小了,但是由于页面整体采用rem单位,当根字体放大dpr倍以后,整体都放大了,看上去整体样式没什么变化。

1、将scale设置为1/dpr

假如:dpr = 2

<meta name="viewport" content="width=device-width,initial-scale=0.5">

2、clientWidth获取的值会自动扩大dpr倍

比如,以前是360px,当页面缩小0.5倍,获取到的值会变为720px。

var deviceWidth = document.documentElement.clientWidth;
document.documentElement.style.fontSize = deviceWidth + 'px';

3、css中涉及到1像素问题的地方使用 px 作为单位

比如:

.box{
    border : 1px solid #ddd;
}

以上步骤最终整理的结果:

html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
</head>
<body>
    <div class="box">
        <div class="logo">Logo</div>
    </div>
</body>
</html>
  •  

js:

//获取屏幕宽度、dpr值
var deviceWidth = document.documentElement.clientWidth,
    dpr = window.devicePixelRatio || 1;

//设置根字体扩大dpr倍
//由于deviceWidth当页面缩小dpr倍时,本身获取的值就增加dpr倍
//所以这里不需要再乘以dpr了
document.documentElement.style.fontSize = deviceWidth + 'px';

//设置页面缩放dpr倍
document.getElementsByName('viewport')[0]
    .setAttribute('content','width=device-width;initial-scale=' + 1/dpr)

scss:

@function calc($val){
    @return $val / 1080;
}

.logo{
    width : calc(180rem);
}

.box{
    border : 1px solid #ddd;
}

3.5 横竖屏显示问题

横竖屏问题,就是当你横屏手机、竖屏手机时看到的不一样的效果问题。

我这里要说的这个问题,就是设计师会针对横屏或者竖屏,做不一样的设计,比如:横屏时显示摘要,竖屏时只有标题,这种情况下,我们应该怎么适配的问题。

关于横竖屏问题,我将会分2个部分来说明:

  1. 横竖屏显示内容不同;
  2. 横竖屏显示样式不同;

3.5.1 横竖屏显示内容问题

我们知道横屏,相当于屏幕变宽了,这时候一行显示的内容就可以更多。所以,设计师可能会对横竖屏做2种不同的内容设计,如:

 如果设计师本身就设计了2套样式,那么我们只需要准备2套css,依据横竖屏直接显示对应的样式,然后html中做好兼容即可。 下文会将如何判断横竖屏。 **3.5.2 横竖屏显示样式问题** 这里有个要说的就是,设计师没有设计横屏的样式,那么如果我们按照上文提到的方案去处理,那么就会发现在横屏模式下字体显得非常大(因为屏幕宽了),显示的内容就少了。 这种情况会显得很不协调,虽然还是等比例显示的,只不过需要多拖动下滚动条而已,但是你会觉得很怪。尤其是再有弹出框的时候,会更麻烦,弹出框有时候可能还会显示不完全。。。 比如,下面的样式:

 像这种问题,我们上面提到的依据屏幕宽度自动调整根目录font-size的大小,就有点不合适了。这样虽然保证了横向的比例是严格按照设计搞来的,但是显示上非常丑。 所以,我们一般的做法就是在横屏的时候将 `deviceWidth=deviceHeight`。 - 正常竖屏大小: - 横屏时让width=height- 不做横竖屏特殊宽度处理时 以上3组画面对比我们得到的效果是: 1. 在横屏下如果让width=height,那么整体页面的宽度等于竖屏时看到的宽度,整体布局不会有变化,只是纵向看到的内容多少发生了变化; 2. 如果横屏不做处理,横屏是width其实就等于竖屏时的height,即700px,这时候整体页面显示非常宽,文字比较大。 所以,经过我们的实际对比体验以后,一致认为横屏时让 `width=height` 体验比较好。 附上核心代码:

var deviceWidth = document.documentElement.clientWidth,
    deviceHeight = document.documentElement.clientHeight

//横屏状态
if (window.orientation === 90 || window.orientation === -90) {
    deviceWidth = deviceHeight;
};

//设置根字体大小
document.documentElement.style.fontSize = deviceWidth + 'px';

3.5.3 附1:JS检测横竖屏

js获取屏幕旋转方向:window.orientation

  • 0 - 正常方向
  • -90 - 屏幕顺时钟旋转90度
  • 90 - 屏幕逆时针旋转90度
  • 180 - 屏幕旋转180度
window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function() {
    if (window.orientation === 180 || window.orientation === 0) { 
        console.log('竖屏状态!');
    };
    if (window.orientation === 90 || window.orientation === -90 ){ 
        console.log('横屏状态!');
    }  
}, false); 

3.5.4 附2:CSS判断横竖屏

  • 写在同一个CSS中:
@media screen and (orientation: portrait) {
  /*竖屏 css*/
} 
@media screen and (orientation: landscape) {
  /*横屏 css*/
}
  • 分开写在2个CSS中,在link中通过media筛选加载:
<!-- 竖屏 -->
<link rel="stylesheet" media="all and (orientation:portrait)" href="portrait.css">

<!-- 竖屏 -->
<link rel="stylesheet" media="all and (orientation:landscape)" href="landscape.css">

3.6 手机字体缩放问题

手机字体缩放是什么问题呢?

就是当你在手机 设置 -> 字体设置 中将字体放大或者缩小,使得手机整体系统字体发生了变化,这时候可能就会影响到H5页面正常的显示。

经过实际测试,这个问题当前发生的概率不是很大,因为很多手机厂商都已经做了保护措施。但是为了保险起见,我们还是有必要进行检测,一旦不一样就要采取措施。

3.6.1 如何检测手机字体不是默认字体

var deviceWidth = document.documentElement.clientWidth;

//设置根字体大小
var setFz = deviceWidth + 'px';
document.documentElement.style.fontSize = setFz;

//获取实际html字体大小
var realFz = window.getComputedStyle(document.documentElement)
    .getPropertyValue('font-size') //如:360px

//比较二者是否相同
if(setFz !== realFz){
    //TODO 设置的字体和实际显示的字体不同
};

3.6.2 如果手机字体不是默认字体如何处理

For example: You want to set the font size is 100px, but the actual size it is 50px, then you can determine in fact the user font is scaled by 0.5, this time you need your font will be doubled, so as to ensure that the actual page fonts 100.

Therefore, according to this and other after scaling, we need to re-set page page font-size.

var deviceWidth = document.documentElement.clientWidth;

//设置根字体大小
var setFz = deviceWidth + 'px';
document.documentElement.style.fontSize = setFz;

//获取实际html字体大小
var realFz = window.getComputedStyle(document.documentElement)
    .getPropertyValue('font-size') //如:360px

//比较二者是否相同
if(setFz !== realFz){
    //去掉单位px,下面要参与计算
    setFz = parseFloat(setFz);
    realFz = parseFloat(realFz);

    //重新计算要设置的新的字体大小
    //公式推导:100 -> 50,x -> 100,求x?
    //即:setFz -> realFz, x -> setFz,求x?
    var x =  setFz * setFz / realFz;

    //重新设置html的font-size
    document.documentElement.style.fontSize = x + 'px';
};

Do theoretically have solved the problem, but still a little flaw, the question is:

  • If the font is not the default font, will first set up a font-size, font-size set once again recalculated, the reaction to the page is the page can quickly shake once, twice because the font set of sample sizes, if the phone is not configured high, estimated shake will be very obvious.

how to solve this problem? The idea is:

  1. Add a hidden element to the page, set the font size to 100px
  2. Get the actual font size of the element on the page whether 100px
  3. And if the actual range provided that the ratio is calculated.

Final code fragment is as follows:

var deviceWidth = document.documentElement.clientWidth;

var setFz = '100px';

//给head增加一个隐藏元素
var h = document.getElementsByTagName('head')[0],
    s = document.createElement('span');
    s.style.fontSize = setFz;
    s.style.display = 'none';
    h.appendChild(s);

//判断元素真实的字体大小是否100px
//如果不相等则获取真实的字体换算比例
var realFz = getComputedStyle(s).getPropertyValue('font-size');

if(setFz !== 'realFz'){
    //去掉单位px,下面要参与计算
    setFz = parseFloat(setFz);
    realFz = parseFloat(realFz);

    //由于:var x = setFz * setFz / realFz;
    //公式推导:x -> setFz, y -> deviceWidth
    //所以:var y = deviceWidth * x / setFz;

    //重置deviceWidth
    deviceWidth = deviceWidth * setFz / realFz;
};

document.documentElement.style.fontSize = deviceWidth + 'px';

Fourth, the final adaptation scheme (v1.0)

In addition to the middle of a step by step analysis of the above principle, we may also need to consider or encounter the following problems:

  1. In the end when dynamic initialization above js script?
  2. Occasionally you may encounter when entering the page  document.documentElement.clientWidth=0 the bug?
  3. Page shaking? Page blank? Page and then the whole messy normal issues?

So, after solving many problems as possible, the final script is as follows:

html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
</head>
<body>
    <!-- 正文 -->
</body>
</html>

js:

/**
 * @DESCRIPTION 移动端页面适配解决方案 v1.0
 * @AUTHOR      Night
 * @DATE        2018年08月01日
 */
(function(window, document){
    var docEle = document.documentElement,
        dpr    = window.devicePixelRatio || 1,
        scale  = 1 / dpr;

    var fontSizeRadio = 1, //手机字体正常比例
        isLandscape   = false;//是否横屏

    ///////////////////////// viewport start //////////////////////////////////

    //设置页面缩放比例并禁止用户手动缩放
    document.getElementsByName('viewport')[0].setAttribute('content','width=device-width,initial-scale='+scale+',maximum-scale='+scale+',minimum-scale='+scale+',user-scalable=no');

    ///////////////////////// viewport end //////////////////////////////////

    //横屏状态检测
    if (window.orientation === 90 || window.orientation === -90) {
        isLandscape = true;
    };

    ///////////////////// system font-size check start //////////////////////

    //试探字体大小,用于检测系统字体是否正常
    var setFz = '100px';

    //给head增加一个隐藏元素
    var headEle = document.getElementsByTagName('head')[0],
        spanEle = document.createElement('span');
        spanEle.style.fontSize = setFz;
        spanEle.style.display = 'none';
        headEle.appendChild(spanEle);

    //判断元素真实的字体大小是否setFz
    //如果不相等则获取真实的字体换算比例
    var realFz = getComputedStyle(headEle).getPropertyValue('font-size');

    if(setFz !== 'realFz'){
        //去掉单位px,下面要参与计算
        setFz = parseFloat(setFz);
        realFz = parseFloat(realFz);

        //获取字体换算比例
        fontSizeRadio = setFz / realFz;
    };

    ///////////////////// system font-size check end //////////////////////

    var setBaseFontSize = function(){
        var deviceWidth = docEle.clientWidth,
            deviceHeight= docEle.clientHeight;

        if(isLandscape){
            deviceWidth = deviceHeight;
        };

        docEle.style.fontSize = deviceWidth * fontSizeRadio + 'px';
    };
    setBaseFontSize();

    //页面发生变化时重置font-size
    //防止多个事件重复执行,增加延迟300ms操作(防抖)
    var tid;
    window.addEventListener('resize', function() {
        clearTimeout(tid);
        tid = setTimeout(setBaseFontSize, 300);
    }, false);
    window.addEventListener('pageshow', function(e) {
        if (e.persisted) {
            clearTimeout(tid);
            tid = setTimeout(setBaseFontSize, 300);
        };
    }, false);

})(window, document);

scss:

//设计稿尺寸大小,假如设计稿宽度750
$baseDesignWidth = 750;

@function calc($val){
    @return $val / $baseDesignWidth;
}

//适配元素采用rem,假如设计稿中元素宽度180
.logo{
    width : calc(180rem);
}

//边框采用px,假如设计稿边框宽度1px
.box{
    border : 1px solid #ddd;
}

Guess you like

Origin blog.csdn.net/qq_42043377/article/details/88037638