19758

写在之前,3年前端开发经验,刚开始对于适配的概念就是只知rem,对于各种成型的布局方式或者适配想法,都是很模糊的,没有体系的概念, 所以做了一些功课,也参考了许多优秀博文~ 欢迎补充~

指路下篇~ ☞ 移动端适配及PC端适配心得总结体会(二) (可能比较全

1.相关概念

像素就是构成图像的最小单位,指显示屏上的最小单位, 图像由像素组成,单位面积内的像素越多 效果就越好 像素的大小不是绝对的,是根据设备的分辨率决定的

2.分辨率

屏幕分辨率 : 屏幕横向和纵向的像素点数,单位为px

相同大小的屏幕 分辨率越低,单位像素尺寸越大,分辨率越高,单位像素尺寸越小

图像分辨率 : 指图片含有的像素数 , 表示图片分别在垂直和水平上所具有的像素点数

同一尺寸的图片,分辨率越高,图片越清晰。

3. PPI

每英寸包括的像素数

PPI 可以用于描述屏幕的清晰度以及一张图片的质量, PPI 越高,屏幕越清晰。

4.设备物理像素 (物理分辨率)

设备的真实分辨率 屏幕有多少个像素点 就是多少分辨率

以iphone6 为例 物理分辨率为750*1334,也就是显示屏内部led灯的个数

5.设备独立像素dips (逻辑分辨率)

一种单位来告诉不同分辨率的手机,它们在界面上显示元素的大小是多少 即设备几个像素当成一个像素使用

以iphone6为例, dips为375* 667 即是2*2个物理像素当做一个设备独立像素

各种设备,手机,平板,笔记本等逻辑像素

手机:逻辑像素在3xx-4xx(短边)之间

平板:10寸平板7xx-8xx(短边)

笔记本:13寸 1280 (长边)

24寸显示屏:1920(长边)

6.设备像素比dpr

物理像素比设备独立像素的比值

css中的像素只是一个抽象的单位,在不同的设备或不同的环境中,css中的1px所代表的设备物理像素是不同的,1px并不是绝对的,它只代表了当前设备像素的最小单位.

在pc端 1px等于一个设备的物理像素,但是移动设备的屏幕像素密度越来越高 ,iphone6上一个css像素是等于两个物理像素,通过 dpr ,我们可以知道该设备上一个css像素代表多少个物理像素

获取dpr :

window.devicePixelRatio

css:

-webkit-min-device-pixel-ratio
React Native: PixelRatio.get()

为什么iphone6的逻辑像素是375 ,设计稿为750宽

这种设计图秤为2倍图,因为切图时获取的图片是页面的两倍大, 但是视网膜屏幕会把图片缩小一倍,这样会更加细腻 更清晰,

7.css像素

CSS像素,当页面缩放比例为100%时,一个CSS像素等于一个设备独立像素。

但是CSS像素是很容易被改变的,当用户对浏览器进行了放大,CSS像素会被放大,这时一个CSS像素会跨越更多的物理像素。

页面的缩放系数 = CSS像素 / 设备独立像素

1.布局视口layout viewport

布局视口:当前浏览器的可视区域,不包括菜单栏及浏览器的ui不包含滚动条

在PC端上,设置viewport不生效,布局视口永远等于浏览器窗口的宽度。

在移动端上,由于要使为PC端浏览器设计的网站能够完全显示在移动端的小屏幕里 布局视口默认是980px,会出现滚动条

但是在iphone和ipad上没有指定初始的缩放值的话,那么iphone和ipad会自动计算initial-scale这个值,以保证当前layout viewport的宽度在缩放后就是浏览器可视区域的宽度

//获取布局视口宽度
document.documentElement.clientWidth / Height

2.视觉视口visual viewport

视觉视口:用户当前看到的区域,包含滚动条等.默认等于当前浏览器的窗口大小

用户通过缩放放大网站,CSS像素增大,一个CSS像素可以跨越更多的设备像素,我们能看到的网站区域将缩小,此时视觉视口变小

假设屏幕上本来需要200个CSS像素才能占满屏幕,由于放大,现在只需要100个CSS像素就能占满,所以视觉视口的宽就变成100px。

同理, 用户缩小网站,我们看到的网站区域将变大,此时视觉视口变大

//获取视觉窗口宽度
window.innerWidth

3.理想视口 ideal viewport

布局视口的一个理想尺寸,只有当布局视口的尺寸等于设备屏幕的尺寸时,才是理想视口。

ideal viewport 的意义在于,无论在何种分辨率的屏幕下,那些针对ideal viewport 而设计的网站,不需要用户手动缩放,也不需要出现横向滚动条,都可以完美的呈现给用户。

比如一段14px大小的文字,不会因为在一个高密度像素的屏幕里显示得太小而无法看清,理想的情况是这段14px的文字无论是在何种密度屏幕,何种分辨率下,显示出来的大小都是差不多的。

//获取理想视口宽度
window.screen.width

4.移动端如何得到理想视口

<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; minimum-scale=1; user-scalable=no;">

该meta标签的作用是让当前布局视口的宽度等于设备的宽度,同时不允许用户手动缩放

视觉视口等于理想视口这时,1个CSS像素就等于1个设备独立像素,而且我们也是基于理想视口来进行布局的,所以呈现出来的页面布局在各种设备上都能大致相似。

要把当前的viewport宽度设为ideal viewport的宽度,既可以设置 width=device-width,也可以设置 initial-scale=1,但这两者各有一个小缺陷,就是iphone、ipad以及IE 会横竖屏不分,通通以竖屏的ideal viewport宽度为准。所以,最完美的写法应该两者都写上去,这样就 initial-scale=1 解决了 iphone、ipad的毛病,width=device-width则解决了IE的毛病:

页面的缩放系数 = 理想视口宽度 / 布局视口宽度

如果meta同时设置了 initial-scale和width,布局视口 讲取两者间的最大值

参考:视口解析

5.常见获取窗口的大小

  • window.innerHeight:获取浏览器视觉视口高度(包括垂直滚动条)。
  • window.outerHeight:获取浏览器窗口外部的高度。表示整个浏览器窗口的高度,包括侧边栏、窗口镶边和调正窗口大小的边框。
  • window.screen.Height:获取获屏幕取理想视口高度,这个数值是固定的,设备的分辨率/设备像素比
  • window.screen.availHeight:浏览器窗口可用的高度。
  • document.documentElement.clientHeight:获取浏览器布局视口高度,包括内边距,但不包括垂直滚动条、边框和外边距。
  • document.documentElement.offsetHeight:包括内边距、滚动条、边框和外边距。
  • document.documentElement.scrollHeight:在不使用滚动条的情况下适合视口中的所有内容所需的最小宽度。测量方式与clientHeight相同:它包含元素的内边距,但不包括边框,外边距或垂直滚动条。
  • 响应式设计与自适应设计的区别:响应式开发一套界面,通过检测视口分辨率,针对不同客户端在客户端做代码处理,来展现不同的布局和内容;自适应需要开发多套界面,通过检测视口分辨率,来判断当前访问的设备是pc端、平板、手机,从而请求服务层,返回不同的页面。

    2.常见的布局方案

    固定布局:以像素作为页面的基本单位,不管设备屏幕及浏览器宽度,只设计一套尺寸; 可切换的固定布局:同样以像素作为页面单位,参考主流设备尺寸,设计几套不同宽度的布局。通过识别的屏幕尺寸或浏览器宽度,选择最合适的那套宽度布局;

    弹性布局:以百分比作为页面的基本单位,可以适应一定范围内所有尺寸的设备屏幕及浏览器宽度,并能完美利用有效空间展现最佳效果; 混合布局:同弹性布局类似,可以适应一定范围内所有尺寸的设备屏幕及浏览器宽度,并能完美利用有效空间展现最佳效果;只是混合像素、和百分比两种单位作为页面单位布局响应:对页面进行响应式的设计实现,需要对相同内容进行不同宽度的布局设计,有两种方式:pc优先(从pc端开始向下设计);移动优先(从移动端向上设计);无论基于那种模式的设计,要兼容所有设备,布局响应时不可避免地需要对模块布局做一些变化(发生布局改变的临界点称之为断点)

    pc端布局

    1. 媒体查询

    主流系统分辨率尺寸

    然后我们看下当前主流系统及分辨率有哪些

    PC & MAC & Chrome

    1280 x 800 1366 x 1024 (IPad Pro) 1440 x 900 1680 x 1050 1600 x 900 1920 x 1200 2560 x 1440 2880 x 1620 3200 x 1800 5120 x 2880

    PC & Windows & Chrome (或 PC & MAC & Chrome & 外设显示器)

    1280 x 720/1024
    1366 x 768
    1440 × 900
    1600 x 900
    1920 x 1080
    

    Mobile & Android

    360 x 480
    412 x 732
    

    Mobile & IOS

    IPhone 6:         375 x 667
    IPhone 6 Plus:    414 x 736
    IPhone X:         375 x 812
    

    不上不下的 IPad:

    768 x 1024
        默认样式    注意:默认样式要写在最前面
        /* 打印样式 */
            @media print {}
        /* 手机等小屏幕手持设备 */
            @media screen and (min-width: 320px) and (max-width: 480px) {}
        /* 平板之类的宽度 1024 以下设备 */
            @media only screen and (min-width: 321px) and (max-width: 1024px) {}
        /* PC客户端或大屏幕设备: 1028px 至更大 */
            @media only screen and (min-width: 1029px) {}
        /* 竖屏 */
            @media screen and (orientation:portrait) {对应样式}
        /* 横屏 */
            @media screen and (orientation:landscape){对应样式}
    
    移动优先:
    /* iphone6 7 8 */
    body {
        background-color: yellow;
    /* iphone 5 */
    @media screen and (max-width: 320px) {
        body {
          background-color: red;
    /* iphoneX */
    @media screen and (min-width: 375px) and (-webkit-device-pixel-ratio: 3) {
        body {
          background-color: #0FF000;
    /* iphone6 7 8 plus */
    @media screen and (min-width: 414px) {
        body {
          background-color: blue;
    /* ipad */
    @media screen and (min-width: 768px) {
        body {
          background-color: green;
    /* ipad pro */
    @media screen and (min-width: 1024px) {
        body {
          background-color: #FF00FF;
    /* pc */
    @media screen and (min-width: 1100px) {
        body {
          background-color: black;
    
    PC优先:
    /* pc width > 1024px */
        body {
            background-color: yellow;
    /* ipad pro */
    @media screen and (max-width: 1024px) {
        body {
            background-color: #FF00FF;
    /* ipad */
    @media screen and (max-width: 768px) {
        body {
            background-color: green;
    /* iphone6 7 8 plus */
    @media screen and (max-width: 414px) {
        body {
            background-color: blue;
    /* iphoneX */
    @media screen and (max-width: 375px) and (-webkit-device-pixel-ratio: 3) {
        body {
            background-color: #0FF000;
    /* iphone6 7 8 */
    @media screen and (max-width: 375px) and (-webkit-device-pixel-ratio: 2) {
        body {
            background-color: #0FF000;
    /* iphone5 */
    @media screen and (max-width: 320px) {
        body {
            background-color: #0FF000;
    
    媒体查询加rem布局
    html{
       font-size:19.20px;  /*默认以设计稿为基准,将设计稿除100*/
       //1rem = 19.20px
    @media only screen and (max-width: 1366px) {
    	 //1rem = 13.66px;
       html{
          font-size:13.66px;
    #test{
       width:14.21875rem;
    

    优点: 面对不同分辨率设备灵活性强, 能够快捷解决多设备显示适应问题

  • 只能在选取的几个主流设备尺寸下呈现完美适配,
  • 用户体验也不友好,布局在响应断点范围内的分辨率下维持不变,而在响应断点切换的瞬间,布局带来断层式的切换变化
  • 代码累赘 工作量大 效率低 加载时间长
  • 一定程度上改变了原有的网站结构
  • 2.百分比布局

    通过百分比单位,可以使得浏览器中组件的宽和高随着浏览器的高度的变化而变化,从而实现响应式的效果。整体布局不变,Bootstrap里面的栅格系统就是利用百分比来定义元素的宽高,CSS3支持最大最小高,可以将百分比和max(min)一起结合使用来定义元素在不同设备下的宽高。

    设计方法:使用%百分比定义宽度,高度大都是用px来固定住,可以根据可视区域 (viewport) 和父元素的实时尺寸进行调整,尽可能的适应各种分辨率。往往配合 max-width/min-width 等属性控制尺寸流动范围以免过大或者过小影响阅读。

    关于百分比的具体分析

  • 子元素height和width/ top和bottom 、left和right的百分比是相对于父元素width,height
  • 子元素的padding/margin 不论是垂直方向或者是水平方向,都相对于直接父亲元素的width,而与父元素的height无关。
  • 百分比单位布局应用

    设置padding-top为百分比来实现等比例的自适应块

    自适应的长方形:

    <div class="trangle"></div>
    

    设置样式让其自适应:

    //这个长方形一直会是4:3
    .trangle{
      height:0;
      width:100%;
      padding-top:75%;//相对于宽度的75%
    
    /* pc width > 1100px */
    html, body { margin: 0;padding: 0;width: 100%;height: 100%;}
    aside {
        width: 10%;
        height: 100%;
        background-color: red;
        float: left;
    main {
        height: 100%;
        background-color: blue;
        overflow: hidden;
    /* ipad pro */
    @media screen and (max-width: 1024px) {
        aside {
          width: 8%;
          background-color: yellow;
    /* ipad */
    @media screen and (max-width: 768px) {
        aside {
          float: none;
          width: 100%;
          height: 10%;
          background-color: green;
        main {
          height: calc(100vh - 10%);
          background-color: red;
    /* iphone6 7 8 plus */
    @media screen and (max-width: 414px) {
        aside {
          float: none;
          width: 100%;
          height: 5%;
          background-color: yellow;
        main {
          height: calc(100vh - 5%);
          background-color: red;
    /* iphoneX */
    @media screen and (max-width: 375px) and (-webkit-device-pixel-ratio: 3) {
        aside {
          float: none;
          width: 100%;
          height: 10%;
          background-color: blue;
        main {
          height: calc(100vh - 10%);
          background-color: red;
    /* iphone6 7 8 */
    @media screen and (max-width: 375px) and (-webkit-device-pixel-ratio: 2) {
        aside {
          float: none;
          width: 100%;
          height: 3%;
          background-color: black;
        main {
          height: calc(100vh - 3%);
          background-color: red;
    /* iphone5 */
    @media screen and (max-width: 320px) {
        aside {
          float: none;
          width: 100%;
          height: 7%;
          background-color: green;
        main {
          height: calc(100vh - 7%);
          background-color: red;
    
  • 适配计算麻烦
  • 各个属性中如果使用百分比,其相对的元素的属性并不是唯一的,使布局问题变得复杂.
  • 如果屏幕尺度跨度太大,那么在相对其原始设计而言过小或过大的屏幕上不能正常显示。因为宽度使用%百分比定义,但是高度和文字大小等大都是用px来固定,所以在大屏幕的手机下显示效果会变成有些页面元素宽度被拉的很长,但是高度、文字大小还是和原来一样,显示非常不协调。
  • 3.rem布局

    REMCSS3新增的单位,并且移动端的支持度很高,Android2.x+,ios5+都支持。rem单位都是相对于根元素html的font-size来决定大小的,根元素的font-size相当于提供了一个基准,当页面的size发生变化时,只需要改变font-size的值,那么以rem为固定单位的元素的大小也会发生响应的变化。 因此,如果通过rem来实现响应式的布局,只需要根据视图容器的大小,动态的改变font-size即可(而em是相对于父元素的)。

    rem响应式的布局思想:

  • 一般不要给元素设置具体的宽度,但是对于一些小图标可以设定具体宽度值
  • 高度值可以设置固定值,设计稿有多大,我们就严格有多大
  • 所有设置的固定值都用rem做单位(首先在HTML总设置一个基准值:pxrem的对应比例,然后在效果图上获取px值,布局的时候转化为rem值)
  • js获取真实屏幕的宽度,让其除以设计稿的宽度,算出比例,把之前的基准值按照比例进行重新的设定,这样项目就可以在移动端自适应了
  • 全屏16:9的解决方案

  • 在 css 表示长度的时候,用设计稿上的长度除以 192, 算得 rem 的值。
  • 页面内写一段 js 代码,根据我们上面的公式去计算并设置 html 元素的 font-size 值。
  • export function init(screenRatioByDesign: number = 16 / 9) {
      let docEle = document.documentElement
      function setHtmlFontSize() {
        var screenRatio = docEle.clientWidth / docEle.clientHeight;
        var fontSize = (
          screenRatio > screenRatioByDesign
            ? (screenRatioByDesign / screenRatio)
        ) * docEle.clientWidth / 10;
        docEle.style.fontSize = fontSize.toFixed(3) + "px";
      setHtmlFontSize()
      window.addEventListener('resize', setHtmlFontSize)
    

    3.[webpack版本] (github.com/QuellingBla…)

    4.原文地址

    function refreshRem() {
        var docEl = doc.documentElement;
        var width = docEl.getBoundingClientRect().width;
        var rem = width / 10;
        docEl.style.fontSize = rem + 'px';
        flexible.rem = win.rem = rem;
    win.addEventListener('resize', refreshRem);
    

    rem布局的缺点:

    在响应式布局中,必须通过js来动态控制根元素font-size的大小,也就是说css样式和js代码有一定的耦合性,且必须将改变font-size的代码放在css样式之前

    REM布局也是目前多屏幕适配的最佳方式。默认情况下我们html标签的font-size为16px,我们利用媒体查询,设置在不同设备下的字体大小。

    4.视口单位vw

    vh、vw 方案即将视觉视口宽度 window.innerWidth 和视觉视口高度 window.innerHeight 等分为 100 份

    vw也是一个相对单位,它相对的是布局视口,1vw就是1%的布局视口宽度。还是熟悉的iPhone6标准设计图,宽750px。那么1vw = 1%视口宽度的话,按设计图来说就是100vw = 750px,则1vw = 7.5px。

    vw和%的区别为:

    单位含义
    %大部分相对于祖先元素,也有相对于自身的情况比如(border-radius、translate等)
    body或者html设置为width:100%时,是不包括页面滚动条的宽度的
    vw/vh相对于视窗的尺寸,不受父元素影响
    100vw包括了页面滚动条宽度,100vw在有纵向滚动条的情况下,会比100%宽

    vw单位与百分比类似,单确有区别,前面我们介绍了百分比单位的换算困难,这里的vw更像"理想的百分比单位"。任意层级元素,在使用vw单位的情况下,1vw都等于视图宽度的百分之一。

  • px转换成vw不一定能完全整除,因此有一定的像素差。
  • 比如当容器使用vwmargin采用px时,很容易造成整体宽度超过100vw,从而影响布局效果。当然我们也是可以避免的,例如使用padding代替margin,并且配合box-sizing结合calc()函数使用等等
  • vw布局相较之下更纯粹代码逻辑也更清晰
  • 使用视口单位来实现响应式有两种做法:

    1.仅使用vw作为CSS单位

    对于设计稿的尺寸转换为为单位,我们使用Sass函数编译

    //iPhone 6尺寸作为设计稿基准
    $vm_base: 375; 
    @function vw($px) {
        @return ($px / 375) * 100vw;
    

    无论是文本还是布局宽度、间距等都使用vw作为单位

    .mod_nav {
        background-color: #fff;
        &_list {
            display: flex;
            padding: vm(15) vm(10) vm(10); // 内间距
            &_item {
                flex: 1;
                text-align: center;
                font-size: vm(10); // 字体大小
                &_logo {
                    display: block;
                    margin: 0 auto;
                    width: vm(40); // 宽度
                    height: vm(40); // 高度
                    img {
                        display: block;
                        margin: 0 auto;
                        max-width: 100%;
                &_name {
                    margin-top: vm(2);
    

    1px物理像素线(也就是普通屏幕下1px,高清屏幕下0.5px的情况)采用transform属性scale实现

    .mod_grid {
        position: relative;
        &::after {
            // 实现1物理像素的下边框线
            content: '';
            position: absolute;
            z-index: 1;
            pointer-events: none;
            background-color: #ddd;
            height: 1px;
            left: 0;
            right: 0;
            top: 0;
            @media only screen and (-webkit-min-device-pixel-ratio: 2) {
                -webkit-transform: scaleY(0.5);
                -webkit-transform-origin: 50% 0%;
    

    对于需要保持宽高比的图,应该用padding-top实现

    .mod_banner {
        position: relative;
        padding-top: percentage(100/700); // 使用padding-top
        height: 0;
        overflow: hidden;
        img {
            width: 100%;
            height: auto;
            position: absolute;
            left: 0;
            top: 0; 
    

    5.搭配vw和rem

    虽然采用vw适配后的页面效果很好,但是它是利用视口单位实现的布局,依赖视口大小而自动缩放,无论视口过大还是过小,它也随着时候过大或者过小,失去了最大最小宽度的限制,此时我们可以结合rem来实现布局

    给根元素大小设置随着视口变化而变化的vw单位,这样就可以实现动态改变其大小

    限制根元素字体大小的最大最小值,配合body加上最大宽度和最小宽度

    // rem 单位换算:定为 75px 只是方便运算,750px-75px、640-64px、1080px-108px,如此类推
    $vm_fontsize: 75; // iPhone 6尺寸的根元素大小基准值
    @function rem($px) {
         @return ($px / $vm_fontsize ) * 1rem;
    // 根元素大小使用 vw 单位
    $vm_design: 750;
    html {
        font-size: ($vm_fontsize / ($vm_design / 2)) * 100vw; 
        // 同时,通过Media Queries 限制根元素最大最小值
        @media screen and (max-width: 320px) {
            font-size: 64px;
        @media screen and (min-width: 540px) {
            font-size: 108px;
    // body 也增加最大最小宽度限制,避免默认100%宽度的 block 元素跟随 body 而过大过小
    body {
        max-width: 540px;
        min-width: 320px;
    

    6.图片响应式

    这里的图片响应式包括两个方面,一个就是大小自适应,这样能够保证图片在不同的屏幕分辨率下出现压缩、拉伸的情况;一个就是根据不同的屏幕分辨率和设备像素比来尽可能选择高分辨率的图片,也就是当在小屏幕上不需要高清图或大图,这样我们用小图代替,就可以减少网络带宽了。

    1.使用max-width(图片自适应):

    图片自适应意思就是图片能随着容器的大小进行缩放,可以采用如下代码:

    img {
        display: inline-block;
        max-width: 100%;
        height: auto;
    

    inline-block 元素相对于它周围的内容以内联形式呈现,但与内联不同的是,这种情况下我们可以设置宽度和高度。 max-width保证了图片能够随着容器的进行等宽扩充(即保证所有图片最大显示为其自身的 100%。此时,如果包含图片的元素比图片固有宽度小,图片会缩放占满最大可用空间),而heightauto可以保证图片进行等比缩放而不至于失真。如果是背景图片的话要灵活运用background-size属性。

    那么为什么不能用width:100%呢?因为这条规则会导致它显示得跟它的容器一样宽。在容器比图片宽得多的情况下,图片会被无谓地拉伸。

    2.使用srcset
    <img srcset="photo_w350.jpg 1x, photo_w640.jpg 2x" src="photo_w350.jpg" alt="">
    

    如果屏幕的dpi = 1的话则加载1倍图,而dpi = 2则加载2倍图,手机和mac基本上dpi都达到了2以上,这样子对于普通屏幕来说不会浪费流量,而对于视网膜屏来说又有高清的体验。

    如果浏览器不支持srcset,则默认加载src里面的图片。

    但是你会发现实际情况并不是如此,在Mac上的Chrome它会同时加载srcset里面的那张2x的,还会再去加载src里面的那张,加载两张图片。顺序是先把所有srcset里面的加载完了,再去加载src的。这个策略比较奇怪,它居然会加载两张图片,如果不写src,则不会加载两张,但是兼容性就没那么好。这个可能是因为浏览器认为,既然有srcset就不用写src了,如果写了src,用户可能是有用的。而使用picture就不会加载两张

    3.使用background-image
    .banner{
      background-image: url(/static/large.jpg);
    @media screen and (max-width: 767px){
      background-image: url(/static/small.jpg);
    
    4.使用picture标签

    picturefill.min.js :解决IE等浏览器不支持 的问题

    <picture>
        <source srcset="banner_w1000.jpg" media="(min-width: 801px)">
        <source srcset="banner_w800.jpg" media="(max-width: 800px)">
        <img src="banner_w800.jpg" alt="">
    </picture>
    <!-- picturefill.min.js 解决IE等浏览器不支持 <picture> 的问题 -->
    <script type="text/javascript" src="js/vendor/picturefill.min.js"></script>
    

    picture必须要写img标签,否则无法显示,对picture的操作最后都是在img上面,例如onload事件是在img标签触发的,picturesource是不会进行layout的,它们的宽和高都是0。

    另外使用source,还可以对图片格式做一些兼容处理:

    <picture>
        <source type="image/webp" srcset="banner.webp">
        <img src="banner.jpg" alt="">
    </picture>
    

    7.一些特殊情况

    zoom属性
    document.body.style.zoom = window.screen.width / 1920;
    
    ScaleEle 单屏应用插件

    8.PC适配的成型方案

    rem来做字体的适配,用srcset来做图片的响应式,宽度可以用remflex,栅格系统等来实现响应式,然后可能还需要利用媒体查询来作为响应式布局的基础,因此综合上面的实现方案,项目中实现响应式布局需要注意下面几点:

  • 设置viewport
  • 字体的适配(字体单位)
  • 百分比布局
  • 图片的适配(图片的响应式)
  • 结合flex,grid,BFC,栅格系统等已经成型的方案
  • 流式布局(即百分比布局)和媒体查询混合使用
  • 移动端适配方案

    移动端开发的通用原则是:文字流式,控件弹性,图片等比缩放。

    1.媒体查询

    媒体查询可以结合百分比或者flex布局,对特定的模块在特定的屏幕宽度范围内做调整。

    另外一种是结合rem,对不同的屏幕宽度范围内的设备设置不同的rem参照字体大小。

    2.viewport方案

    直接等比缩放

    <script>
        const scale = window.screen.width / 750
        document.write(`<meta name="viewport" content="initial-scale=${scale}">`)
    </script>
    

    缺点:太粗暴,viewport的设置是影响全局,不需要缩放的地方也会缩放,可能还会影响第三方库

    3.rem适配

    1.flexble适配方案 (阿里手淘团队)

    手淘的flexible解决了1px边框的问题, 用 rem 实现在不同设备等比缩放的vw的过渡方案(已停止维护)

    适用场景:等比缩放 图片较多或者业务简单的展示页面

    核心思想:

    // set 1rem = viewWidth / 10
    function setRemUnit () {
        var rem = docEl.clientWidth / 10
        docEl.style.fontSize = rem + 'px'
    setRemUnit();
    

    针对字体的写法

    document.documentElement.setAttribute('data-dpr', dpr)
    

    处理1px边框的副作用,从而写css的时候可以针对不同的dpr固定设置尺寸:

    div {
        width: 1rem; 
        height: 0.4rem;
        font-size: 12px; // 默认写上dpr为1的fontSize
    [data-dpr="2"] div {
        font-size: 24px;
    [data-dpr="3"] div {
        font-size: 36px;
    
    2. 媒体查询+rem(网易前端团队)

    js版修改html的font-size

    $("html").css("font-size",document.documentElement.clientHeight/document.documentElement.clientWidth<1.5 ? (document.documentElement.clientHeight/603*312.5+"%") : (document.documentElement.clientWidth/375*312.5+"%"));
    //单屏全屏布局时使用,短屏下自动缩放
    //$("html").css("font-size",document.documentElement.clientWidth/375*312.5+"%");
    //长页面时使用,不缩放
    

    css媒体查询修改html font-size

    媒体查询并不是最终起作用的,它的存在只是为了防止js没加载到的时候就先渲染了页面,等后面js加载完后,页面样式改变太大而发生页面跳动,体验不好。

    html {
      -ms-text-size-adjust: 100%;
      -webkit-text-size-adjust: 100%;
      font-size: 62.5%;
    html {
      font-size: 312.5%;
    @media screen and (max-width: 359px) and (orientation: portrait) {
      html {
        font-size: 266.67%;
    @media screen and (min-width: 360px) and (max-width: 374px) and (orientation: portrait) {
      //(375/360)*312.5%=300%html {
        font-size: 300%;
    @media screen and (min-width: 384px) and (max-width: 399px) and (orientation: portrait) {
      html {
        font-size: 320%;
    @media screen and (min-width: 400px) and (max-width: 413px) and (orientation: portrait) {
      html {
        font-size: 333.33%;
    @media screen and (min-width: 414px) and (max-width: 431px) and (orientation: portrait) {
      html {
        font-size: 345%;
    @media screen and (min-width: 432px) and (max-width: 479px) and (orientation: portrait) {
      html {
        font-size: 360%;
    @media screen and (min-width: 480px) and (max-width: 639px) and (orientation: portrait) {
      html {
        font-size: 400%;
    @media screen and (min-width: 640px) and (orientation: portrait) {
      html {
        font-size: 533.33%;
    

    html采用312.5%这个基本值是为了计算方便 页面的字体默认是16px,我们把根节点字体设置为312.5%,那么就是16*312.5%=50px,对应设计稿上的100px,那么设计稿上100px的元素,样式表里面写成1rem就可以

  • 根元素font-size值强耦合,系统字体放大或缩小时,会导致布局错乱;弊端之二:html文件头部需插入一段js代码
  • 移动端尺寸自适应与dpr无关,除了淘宝方案外,其他方案还有1px的问题,但也减少针对不同dpr设备做响应式处理的麻烦
  • 4.vw/vh布局

    具体实践: 可以使用webpack loader 插件 postcss-loader的postcss-px-to-viewport 实现px到vw的转化

    loader: 'postcss-loader', options: { plugins: ()=>[ require('autoprefixer')({ browsers: ['last 5 versions'] require('postcss-px-to-viewport')({ viewportWidth: 375, //视口宽度(数字) viewportHeight: 1334, //视口高度(数字) unitPrecision: 3, //设置的保留小数位数(数字) viewportUnit: 'vw', //设置要转换的单位(字符串) selectorBlackList: ['.ignore', '.hairlines'], //不需要进行转换的类名(数组) minPixelValue: 1, //设置要替换的最小像素值(数字) mediaQuery: false //允许在媒体查询中转换px(true/false)

    5.vw+rem布局

    原理: 使用vm去改变html的font-size 使用rem去等比缩放

    // rem 单位换算:定为 75px 只是方便运算,750px-75px640-64px1080px-108px,如此类推
    $vw_fontsize: 75; // iPhone 6尺寸的根元素大小基准值
    @function rem($px) {
         @return ($px / $vw_fontsize ) * 1rem;
    // 根元素大小使用 vw 单位
    $vw_design: 750;
    html {
        font-size: ($vw_fontsize / ($vw_design / 2)) * 100vw; 
        // 同时,通过Media Queries 限制根元素最大最小值
        @media screen and (max-width: 320px) {
            font-size: 64px;
        @media screen and (min-width: 540px) {
            font-size: 108px;
    // body 也增加最大最小宽度限制,避免默认100%宽度的 block 元素跟随 body 而过大过小
    body {
        max-width: 540px;
        min-width: 320px;
    
    #app {
                width: 100%;
                .container {
                    padding: rem(20) rem(20) rem(20) rem(20)
                    .main {
                        width 100%
    

    以750设计稿(转换为1倍图)为准,借助pxtorem转换,设置font-size设置为16

    为什么是16,因为我们在第一步的时候是按一倍图来写的,如果哪天不想用rem了,可以直接,把pxtorem去掉,代码还直接还原成px

    在css最前面加入关于html的字体设置,我用的less

    .font-size(@sizeValue:16) {
      @vw: 16 / 375 * 100;
      @result: @sizeValue / 16 * @vw;
      font-size: ~"@{result}vw";
    html {
      .font-size(16);
    html {
      @media screen and (max-width: 320px) {
        .font-size(16);
      @media screen and (min-width: 480px) {
        .font-size(13);
    

    vw和rem的方案的本质都是“等比例缩放”,因为vw和rem都是相对长度单位,可以很好的满足这个需求。区别是vw是viewport width的1%,而rem是html元素的font-size。当我们让html元素的font-size与viewport width产生了关联后,rem就可以模拟出使用vw进行布局的效果了

    6.flex 弹性布局

    不管移动设备的分辨率怎么变, 关键元素高宽和位置都不变,只有容器元素在做伸缩变换。百分比布局,无需计算百分比,可以很好的适配到所有屏幕

    特点:文字流式,控件弹性,图片等比缩放

    为什么要使用flex布局

    float布局有副作用,如果子元素设置了浮动,会引起父元素的塌陷 /不能动态实现自适应布局/设置padding margin不能正确表达 /之前的元素浮动了,后面的元素可能异位,所以页面越来越复杂,不利于管理

    float布局对于移动端布局很不友好,所以出现了弹性布局flex

    采用 Flex 布局的元素,称为 Flex 容器。它的所有子元素自动成为容器成员

    flex容器属性
  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content
  • 1. flex-direction属性

    flex-direction属性决定主轴的方向(即项目的排列方向)。

    .box {
      flex-direction: row | row-reverse | column | column-reverse;
    //依次表示主轴为水平方向,起点在左端。(默认)
    //主轴为水平方向,起点在右端。
    //主轴为垂直方向,起点在上沿。
    //主轴为垂直方向,起点在下沿。
    
    2. flex-wrap属性

    默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。

    .box{
      flex-wrap: nowrap | wrap | wrap-reverse;
      //依次是不换行
      //换行,第一行在上方。
      //换行,第一行在下方。
    
    3. flex-flow属性

    flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。

    .box {
      flex-flow: <flex-direction> || <flex-wrap>;
    
    4. justify-content属性(这个很重要,经常用)

    justify-content属性定义了项目在主轴上的对齐方式。

    .box {
      justify-content: flex-start | flex-end | center | space-between | space-around;
      //依次是左对齐(默认值)
      //右对齐
      //两端对齐,项目之间的间隔都相等。
      //每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
    
    5. align-items属性(这个也很重要。也常用)

    align-items属性定义项目在交叉轴上如何对齐。

    .box {
      align-items: flex-start | flex-end | center | baseline | stretch;
      //依次是交叉轴的起点对齐。
      //交叉轴的终点对齐。
      //交叉轴的中点对齐。
      //项目的第一行文字的基线对齐。
      //如果项目未设置高度或设为auto,将占满整个容器的高度(默认值)
    
    6. align-content属性

    align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

    .box {
      align-content: flex-start | flex-end | center | space-between | space-around | stretch;
      //依次是与交叉轴的起点对齐。
      //与交叉轴的终点对齐。
      //与交叉轴的中点对齐。
      //与交叉轴两端对齐,轴线之间的间隔平均分布。
      //每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
      //轴线占满整个交叉轴。(默认值)
    
    项目的属性
  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • align-self
  • 1. order属性

    order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

    .item {
      order: <integer>;
    
    2. flex-grow属性(很重要)

    flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

    如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

    .item {
      flex-grow: <number>; /* default 0 */
    
    3. flex-shrink属性

    flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

    如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

    注意:负值对该属性无效。

    .item {
      flex-shrink: <number>; /* default 1 */
    
    4. flex-basis属性(这个是重点,常用)

    flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

    它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。

    5. flex属性(这个最重要)

    flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

    .item {
    //该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
    //建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
      flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
    
    6. align-self属性

    align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

    .item {
      align-self: auto | flex-start | flex-end | center | baseline | stretch;
      //这个其实就是在项目里用align-items 注:auto为默认值
    

    6.1 Flex实际应用

    常用的flex 1

    flex 是 flex-grow、flex-shrink、flex-basis的缩写

    当 flex 取值为 none,则计算值为 0 0 auto

    .div {
        flex-grow: 0;
        flex-shrink: 0;
        flex-basis: auto;
    

    当 flex 取值为 auto,则计算值为 1 1 auto

    .div {
        flex-grow: 1;
        flex-shrink: 1;
        flex-basis: auto;}
    

    当 flex 取值为一个非负数字则 flex-grow 数字,flex-shrink 取 1,flex-basis 取 0%(最常用)

     .div {
        flex-grow: 1;//要取的值
        flex-shrink: 1;//默认
        flex-basis: 0%;//默认
    

    当 flex 取值为一个长度或百分比,则视为 flex-basis 值,flex-grow 取 1,flex-shrink 取 1

     .div {
        flex-grow: 1;//默认
        flex-shrink: 1;//默认
        flex-basis: 0%;//要取得值
    

    当 flex 取值为两个非负数字,则分别视为 flex-grow 和 flex-shrink 的值,flex-basis 取 0%

     .div {
        flex-grow: 1;//要取的第一个值
        flex-shrink: 1;//要取的第二个值
        flex-basis: 0%;//默认
    

    当 flex 取值为一个非负数字和一个长度或百分比,则分别视为 flex-grow 和 flex-basis 的值,flex-shrink 取 1

    .div {
        flex-grow: 1;//要取的第一个值
        flex-shrink: 1;//默认
        flex-basis: 0%;//要取的第二个值
    

    6.2 flex常见布局

    flex实现等分布局
    .box{
                height: 500px;
                display: flex;
    .box div{
                 height: 300px;
                 border: 1px solid #000000;
                 flex: 1;//这就是flex1的妙用
        div class="box">
            <div>等分效果</div>
            <div>等分效果</div>
        </div>
    
    左边固定右边自适应
       .box {
                height: 500px;
                display: flex;
            .box div {
                height: 300px;
                text-align: center;
            .box div.right {
                flex: 1;//右边自适应
                border: 1px solid #000000;
            .box div.left {
                border: 1px solid #000000;
                flex-basis: 100px;//左边固定,优先级最高
        //html
        <div class="box">
            <div class="left">左边固定效果</div>
            <div class="right">右边自适应效果</div>
        </div>
    

    边自适应的内容如果超过范围,自适应的地方添加min-width:0,若 min-width 未设置就默认为 auto,在这里就等于这个自适应的的宽度

    垂直水平居中对齐
     .box {
                width: 100%;
                height: 300px;
                border: 1px solid purple;
                display: flex;
                justify-content: center;
                align-items: center;
    <div class="box"><p>居中</p></div>
    

    7.移动端适配的成型方案

    px+各种布局手段为主/vx,vx+媒体查询为辅的方案(如果不用等比缩放可以不使用)

    在 head 设置 width=device-width 的 viewport

    在 css 中使用 px

    在适当的场景使用 flex 布局,或者配合 vw 进行自适应

    在跨设备类型的时候(pc <-> 手机 <-> 平板)使用媒体查询

    字数不够了,下一个篇章会总结web 移动端适配会经常遇到的一些问题~ 比如1px线问题,微信浏览器配置 safari适配 如何适配iphonex 横屏问题的处理~click 点击事件延时与穿透等 问题

    blossom_
    私信