Skip to content

移动端适配 #17

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
yaofly2012 opened this issue Oct 16, 2018 · 4 comments
Open

移动端适配 #17

yaofly2012 opened this issue Oct 16, 2018 · 4 comments

Comments

@yaofly2012
Copy link
Owner

yaofly2012 commented Oct 16, 2018

基本概念

一、三种视口(viewport)

1.1 可见视口

移动设备屏幕大小,能看见内容的区域。

1.2 布局视口

移动页面是从PC过渡过来的,移动端可见视口相对于PC可见视口是比较小的。PC页面放到移动端展示就会挤在一起了(如375px宽的屏幕肯定无法正常显示980px宽的PC页面),为了避免这种情况移动设备会用一个比较大的视图(一般980px)进行页面布局。这样布局视口的内容就不能完全展示了,要么进行左右滑动查看,要么缩小页面完全展示。浏览器选择了后者,即缩小布局视口展示在可见视口里(毕竟用户可以手动放大页面)。

这个layout viewport的宽度可以通过document.documentElement.clientWidth 来获取。

在基于REM布局中html的font-size计算就是按照布局尺寸算的。

1.3 理想视口

就是可见视口。讲布局视口的宽度和可见视口宽度一致。本质上采用可见视口的宽度进行布局。

茴字的四种写法—移动适配方案的进化

二、像素

一直以为最小只能显示1px,但其实并不是这样的。

2.1 物理像素(设备像素,device pixel)

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

2.2 独立像素(设备独立像素,device independent pixels,简写dips)

CSS布局像素,即PX。CSS里的1px并不是物理像素的1像素,那还得看独立像素比

1px的东西在屏幕上的大小与那些低分辨率的设备差不多

这里的1像素指的就是1 CSS px,CSS里px也是相对单位(相对于物理像素)。

在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的,而不同的是CSS像素所对应的物理像素具数是不一致的。在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素。

2.3 独立像素比(window.devicePixelRatio)dpr

  1. 浏览器可以通过缩放操作调整dpr的值,同时window.devicePixelRatio的值也会跟着变化;

CSS像素、物理像素、逻辑像素、设备像素比、PPI、Viewport

2.4 视网膜屏幕

一般指ddr > 1的屏幕

三、0.5px问题

1px是CSS最小的单位,并且各个屏幕看起开擦不多。但是理论上在dpr >1的屏幕中可以展示更细的线条,也是大家经常说到的0.5px线条或则Retina屏幕1px问题。

总体方式是:如果设备支持(限iOS 8及以上设备)更好,不支持再hack

hack实现

判断设备是否支持0.5px

目前只能利用JS,可以参考flexible 2.0

// detect 0.5px 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)
  }

hack实现方式

  1. viewport meta + rem
    有坑,flexible都放不用这个了。

  2. 伪类 + transform 的实现

.hairlines li:after{
    content: '';
    position: absolute;
    left: 0;
    background: #000;
    width: 100%;
    height: 1px;
    -webkit-transform: scaleY(0.5);
            transform: scaleY(0.5);
    -webkit-transform-origin: 0 0;
            transform-origin: 0 0;
}

只考虑了drp=2都case,严谨点可以利用媒体查询处理多种drp都场景(当然了代码量不小)
详细参考[前端]移动端Retina视网膜屏1px解决方案(H5))

参考

  1. 茴字的四种写法—移动适配方案的进化
  2. 使用Flexible实现手淘H5页面的终端适配
  3. [前端]移动端Retina视网膜屏1px解决方案(H5)
  4. 如何在Vue项目中使用vw实现移动端适配
  5. https://www.w3cplus.com/css/vw-for-layout.html
  6. Retina屏的移动设备如何实现真正1px的线?](https://jinlong.github.io/2015/05/24/css-retina-hairlines/)
  7. 知乎 移动端1px解决方案总汇
@yaofly2012
Copy link
Owner Author

yaofly2012 commented Dec 13, 2018

REM

Alloy Team 移动web适配利器-rem
也是这个文章里列出的几个点:

  1. rem基准值计算
  2. dpr影响

哪些适合采用rem单位,哪些不适合?

适合:

  1. width, height
  2. margin/padding
  3. border
  4. left/right top/bottom

适合REM布局:

  1. font-size
    使用Flexible实现手淘H5页面的终端适配

我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px和24px,所以我们不希望出现13px和15px这样的奇葩尺寸。

  1. border-width

@yaofly2012
Copy link
Owner Author

yaofly2012 commented Dec 13, 2018

VH,VW

一、语法

MDN css length
Fun with Viewport Units

二、lib-flexible为啥不维护了?

由于viewport单位得到众多浏览器的兼容,lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方。

大漠在再聊移动端页面的适配也说到:

Flexible已经完成了他自身的历史使命,我们可以放下Flexible,拥抱新的变化著作权归作者所有。

v2.0的改变

  1. 看了下源码发现v2.0开始不直接处理Retina屏1px问题了,只保留核心计算htmlfont-size
    淘宝首页也采用这个版本的,但是也不完全是这个版本(后面分析)。
  1. 如果设备不支持0.5px,则会在html标签增加一个特殊的CSS hairlines
    业务可以利用这个CSS进行0.5实现方案hack。
// detect 0.5px 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)
  }
  1. 功能更贴近vw

三、布局方式

1. 直接使用vw替换px;

2. 搭配vwrem

根元素htmlfont-size优先采用vw,其他元素采用rem

优点:

  1. 可以增加最大最小控制;
  2. 方便从rem过渡(只需要修改htmlfont-size值定义单位)。

如何计算根元素htmlfont-size

  1. 设计稿基数:750px,drp=2
    相当于:100vw=750px / 2,即:1vw = 3.75px, 1px = 1/3.75vw。

  2. Root HTML fontSize计算( px to rem 比率)
    方便整除(设计图标注的px快速转成rem),将比率调整100:
    Root fontSize = 100px = 100* 1/3.75 vm = 26.666666666vw;
    即:1rem = 100px = 26.666666666vw

四、手淘首页布局分析

采用lib-flexiable v2.0的改进版(还没更新到lib-flexiable v2.0里,看来真的不维护了)。
改进版lib-flexiable v2.0唯一到区别在于计算htmlfont-size逻辑(提取代码时间2020-12-10):

  function setRemUnit () {
    var rem = docEl.clientWidth / 3.75
    docEl.style.fontSize = rem + 'px'
  }

即把字体基数改成了100,估计是为了方便除。

五、网易H5布局分析

网易H5采用的是搭配vwrem

html {
  font-size: -webkit-calc(13.33333333vw);
  font-size: calc(13.33333333vw);
}

视口列表CSS

/**
 * view-port list:
320x480
320x568
320x570
360x592
360x598
360x604
360x640
360x720
375x667
375x812
393x699
412x732
414x736
480x854
540x960
640x360
720x1184
720x1280
800x600
1024x768
1080x1812
1080x1920
 */
html {
  font-size: -webkit-calc(13.33333333vw);
  font-size: calc(13.33333333vw);
}
@media screen and (max-width: 320px) {
  html {
    font-size: 42.667px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 321px) and (max-width: 360px) {
  html {
    font-size: 48px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 361px) and (max-width: 375px) {
  html {
    font-size: 50px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 376px) and (max-width: 393px) {
  html {
    font-size: 52.4px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 394px) and (max-width: 412px) {
  html {
    font-size: 54.93px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 413px) and (max-width: 414px) {
  html {
    font-size: 55.2px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 415px) and (max-width: 480px) {
  html {
    font-size: 64px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 481px) and (max-width: 540px) {
  html {
    font-size: 72px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 541px) and (max-width: 640px) {
  html {
    font-size: 85.33px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 641px) and (max-width: 720px) {
  html {
    font-size: 96px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 721px) and (max-width: 768px) {
  html {
    font-size: 102.4px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}
@media screen and (min-width: 769px) {
  html {
    font-size: 102.4px;
    font-size: -webkit-calc(13.33333333vw);
    font-size: calc(13.33333333vw);
  }
}

网易比率是50,所以1rem = 100px = 13.33333333vw

参考

  1. 利用视口单位实现适配布局
  2. 纯CSS3使用vw和vh视口单位实现自适应

@yaofly2012
Copy link
Owner Author

yaofly2012 commented Dec 14, 2018

CSS实现长宽比的几种方案

思路就是高度的计算要基于宽度。
1.

原理是利用padding-top或者padding-bottom的百分比值,实现容器长宽比著作权归作者所有。

  1. vw

需要恶补

1. %单位计算方式.

2. CSS 函数,变量

  1. calc

参考

CSS实现长宽比的几种方案

@yaofly2012
Copy link
Owner Author

yaofly2012 commented Dec 15, 2018

CSS类型

一、<length>长度类型

用来衡量距离的

  1. 相对单位都要最终转成据对单位px

二、<percentage>百分比类型

元素百分比不是长度的类型,而是单独的一种CSS数据类型,属于数字类型。

Each property that allows percentages also defines the quantity to which the percentage refers.

2.1 %的参考值

  1. width/height
  • 流内元素
    所在容器的content矩形框的宽高
  • 流外元素(aboslute, fixed,不包含float)
    所在容器的padding矩形框的宽高
  1. padding/margin-(top/right/bottom/left)
  • 流内元素
    所在容器的content矩形框的宽
  • 流外元素(aboslute, fixed,不包含float)
    所在容器的padding矩形框的宽
    注意:padding/margin-top/bottom也是基于宽度计算的,不是基于高度。
  1. border-width
    不可以用百分比值。
  2. font-size
    父DOM元素的font-size的计算值。跟定位无关。
  3. top/bottom
  • 流外元素(aboslute, fixed,不包含float) :
    所在容器的padding矩形框的高度
  • relative元素:
    所在容器的content矩形框的高度
  1. left/ right
  • 流外元素(aboslute, fixed,不包含float) :
    所在容器的padding矩形框的框度
  • relative元素:
    所在容器的content矩形框的宽度
  1. line-height
    当前元素的font-size计算值

2.2 包含块(Contain Block)

2.1中提到的所在容器指的是元素的包含块。
参考

  1. static和relative定位元素的包含块,为其块级祖先元素(通常是块级父元素)的content box;
  2. absolute定位元素的包含块,为最近的非静态定位祖先元素的padding box,查无非静态定位祖先元素,那么它的包含块是ICB(即根元素的包含块);
  3. fix定位元素的包含块,为当前viewport(视窗)。

注意

  1. 初始化包含快(ICB)是个专用概念,就是viewport的尺寸,它不是根元素html构成的块,而是只根元素html的包含块;
  2. ICB也不一定是父DOM。

2.3 小结

  1. 流内元素以容器的content矩形框,流外元素(aboslute, fixed,不包含float)以padding矩形框
  2. 影响元素宽高的(widht,height, top/bottom, left/right)都是按照容器的宽高计算;
  3. 只是布局但不影响宽高的(padding/margin)都是按照容器的宽度。
    CSS3中可以使用box-sizing修改盒模型,padding/margin本质也会影响宽高。

参考

  1. CSS的长度单位

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

1 participant