Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

移动端适配 #17

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的长度单位

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

No branches or pull requests

1 participant