资讯专栏INFORMATION COLUMN

响应式布局方案

lowett / 1592人阅读

摘要:说到响应式布局方案,我们首先需要了解视口这个概念视口在早期的时候我们没有专门针对手机尺寸写的页面,所以在用手机浏览页面的时候我们看到的都是专门针对端的页面,在这种情况下页面会被严重压缩,而且会极大的影响页面的结构和布局,为了解决这个问题,苹

说到响应式布局方案,我们首先需要了解视口这个概念

视口

在早期的时候我们没有专门针对手机尺寸写的页面,所以在用手机浏览页面的时候我们看到的都是专门针对PC端的页面,在这种情况下页面会被严重压缩,而且会极大的影响页面的结构和布局,为了解决这个 问题,苹果公司提出了视口的概念,因为我们早期的PC端的页面的版心一般是960px,为了容纳这个页面,我们在手机建立一个虚拟的区域,大小一般为980px,来容纳PC的页面,以方便用户来浏览页面

但是在如今移动端快速发展的时候,我们有了专门针对手机屏幕尺寸的的移动端页面,所以在写移动端的页面的时候我们需要调整视口的宽度,保证页面内容会在手机屏幕尺寸大小的页面上进行展示

 


 


 
 

 
媒体查询 媒体类型

媒体查询可以为不同的设备规定不同的样式,常用的一般有三种设备 screen(计算机屏幕,该值是默认值)、print(打印预览)、all(所有设备)

@media screen
媒体属性

媒体属性用来规定在指定的符合某些条件的情况下为指定的元素设置样式,需要注意媒体属性必须用()包起来,否则无效,常用的媒体属性有

width    可视区域宽度,取值格式为指定宽度或者范围,如  @media (width: 900px){ }
height 可视区域高度,取值格式为指定宽度或者范围,如 @media (max-height: 900px){ }
device-width 设备宽度,取值格式为指定宽度或者范围,如 @media (max-device-width: 5000px) { }
device-height 设备高度 取值格式为指定宽度或者范围,如 @media (max-device-height: 5000px) { }
orientation 设备是竖屏还是横屏模式,可选值有landscape(横屏)、portrait(竖屏),如 @media (orientation: landscape) { }
aspect-ratio 可视区域宽高比,取值格式为水平像素/垂直像素,如@media (device-aspect-ratio:16/9) { }
device-aspect-ratio 设备宽高比,取值格式为水平像素/垂直像素,如@media (device-aspect-ratio:16/9) { }

例如我们要针对某个设备的body在横屏时设置的背景颜色是黑色,在竖屏的时候背景是白色,那么可以使用以下写法

html, body {
    height: 100%;
    }
@media  (orientation: landscape) {
    body{
        background-color:#000;
    }
}
@media  (orientation: portrait) {
    body{
        background-color:#fff;
    }
}
逻辑操作符

媒体查询可以使用三种操作符,通过操作符配合媒体属性来判断是否载入媒体属性下的样式表

and 将每一个条件组合起来,只有当所有条件都成立时条件才成立,可以理解为JavaScript中的&

not 对媒体查询的条件取反

or 只要有一个媒体属性条件成立就成立,可以理解为JavaScript中的||

配合逻辑操作符设置设备在可视窗口大小变化时背景颜色发生改变

html,body{
    height: 100%;
}
    
@media screen and (max-width: 500px ){
    body{
        background-color: skyblue;
    }
}
@media screen and (min-width: 501px) and (max-width: 800px){
    body{
        background-color: #ccc;
    }
}
@media screen and (min-width: 900px){
    body{
        background-color: yellowgreen;
    }
}
vw、vh布局方案

在CSS3规范中引入了vwvh单位,分别将视口划分为100份,一个vw单位相当于视口宽度的1%,一个vh相当于视口高度的1%,需要注意的是不同于百分比的布局方案,vw和vh不受父元素宽高的影响,只由视口的大小决定
同时还有两个单位vmaxvmin,vmax表示取视口宽度和高度中比较大的值,将其等分为100份,vmin表示取比较小的值,将其等分为100份




    
    
    
    
    vw、vh


目前浏览器的支持情况

rem布局

rem是css中的一个单位,是根据根字体大小来设定的,也就是html的font-size

在正常的UI设计稿件的时候一般设置大小为640/750px大小,我们一般选择将稿件等分为20份(20份在设备大小和稿件大小一般可以除尽,我们尽量避免出现小数)

那么如果UI稿件为640px大小,每一份的大小为32px,假设UI稿件上有一个160*160大小的元素,那么该元素占整个页面的160/32份

同时我们也将屏幕分为20份,以Iphon为例(屏幕大小为320px),那么每份大小为16px,我们通过媒体查询将html根字体大小设置为16px,那么在UI稿件上160px大小的元素在Iphon5上的实际大小为160/32 rem,那么通过这个公式我们就可以通过JavaScript设置不同的根节点字体大小来进行适配

我们来写一个简单的例子

(function (doc, win) {
       var docEl = doc.documentElement,
/*
          document.documentElement
          返回文档的根节点
        * orientationchange 在用户移动端设备屏幕垂直或水平旋转移动设备时被触发
        * resize 事件,在绑定元素大小发生变化时触发该事件,例如检测屏幕变化:
        * window.addEventLisenter("resize",function(){
        *      alert("屏幕大小变化了")
        * })
        *
        * resize 属性,css3新增属性,用来指定用户是否可以缩放该元素
        * none:用户无法调整该元素尺寸
        * both:用户可以调整元素的高度和宽度
        * horizontal:用户可调整元素的宽度
        * vertical:用户可调整元素的宽度
        * */
           resizeEvt = "orientationchange" in window ? "orientationchange" : "resize",
           recalc = function () {
               var clientWidth = docEl.clientWidth;
               if (clientWidth >= 640) {
                   clientWidth = 640
               }
               if (!clientWidth) return;

               docEl.body.style.fontSize = (clientWidth / 640) * 100 + "px";
           };
       win.addEventListener("resizeEvt", recalc, false);
/*
         * DOMContentLoaded 该事件会在load事件之前触发,在DOM树构建完成时就触发
         * 而load事件则是在DOMContentLoaded事件触发之后,继续加载图片等外部文件完成后触发
         * */
       doc.addEventListener("DOMContentLoaded", recalc, false)
   })(document, window)

之前一直在使用手淘的rem布局方案,可以大概看一下源码

;(function(win, lib) {
        var doc = win.document;
        var docEl = doc.documentElement;
        var metaEl = doc.querySelector("meta[name="viewport"]");
        var flexibleEl = doc.querySelector("meta[name="flexible"]");
        var dpr = 0;
        var scale = 0;
        var tid;

        var flexible = lib.flexible || (lib.flexible = {});

        if (metaEl) {

            var match = metaEl.getAttribute("content").match(/initial-scale=([d.]+)/);


        }if (match) {
            scale = parseFloat(match[1]);
            dpr = parseInt(1 / scale);
        }
        else if (flexibleEl) {
            var content = flexibleEl.getAttribute("content");
            if (content) {
                var initialDpr = content.match(/initial-dpr=([d.]+)/);
                var maximumDpr = content.match(/maximum-dpr=([d.]+)/);
                if (initialDpr) {
                    dpr = parseFloat(initialDpr[1]);
                    scale = parseFloat((1 / dpr).toFixed(2));
                }
                if (maximumDpr) {
                    dpr = parseFloat(maximumDpr[1]);
                    scale = parseFloat((1 / dpr).toFixed(2));
                }
            }
        }
        //如果用户自定了name="viewport"的meat标签,那么通过match获取用户设置的initial-scale,也就是缩放级别,然后获得设置dpr
        //如果用户没有设定name="viewport"的meat标签,那么获取flexible.js自身定义的缩放级别来设置dpr


        if (!dpr && !scale) {
            //检测的当前设备的版本
            var isAndroid = win.navigator.appVersion.match(/android/gi);
            var isIPhone = win.navigator.appVersion.match(/iphone/gi);

            var devicePixelRatio = win.devicePixelRatio;
            //window.devicePixelRatio 该属性返回当前显示设备的物理像素分辨率与css像素分辨率的比值
            //可以通过重写window.devicePixelRatio来更改此属性,例如window.devicePixelRatio=2;

            if (isIPhone) {
                // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
                if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
                    dpr = 3;
                } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
                    dpr = 2;
                } else {
                    dpr = 1;
                }
            } else {
                // 其他设备下,仍旧使用1倍的方案
                dpr = 1;
            }
            scale = 1 / dpr;
        }

        docEl.setAttribute("data-dpr", dpr);
        //判断页面是否存在 metaEl
        if (!metaEl) {
            metaEl = doc.createElement("meta");
            metaEl.setAttribute("name", "viewport");
            metaEl.setAttribute("content", "initial-scale=" + scale + ", maximum-scale=" + scale + ", minimum-scale=" + scale + ", user-scalable=no");
            if (docEl.firstElementChild) {
                docEl.firstElementChild.appendChild(metaEl);
            } else {
                var wrap = doc.createElement("div");
                wrap.appendChild(metaEl);
                doc.write(wrap.innerHTML);
            }
        }

        function refreshRem(){
            var width = docEl.getBoundingClientRect().width;
            //getBoundingClientRect
            //返回一个DOMRect对象,包含一组矩形的集合,该集合内是与该元素相关的css边框集合

            // DOMRect
            // bottom:8
            // height:8
            // left:0
            // right:520
            // top:0
            // width:520
            // x:0
            // y:0

            if (width / dpr > 540) {
                width = 540 * dpr;
            }
            //手淘的布局方案默认将屏幕分成十份,当然,如果愿意我们可以对其进行更改
            var rem = width / 10;
            docEl.style.fontSize = rem + "px";
            flexible.rem = win.rem = rem;
        }
        // resize 在设备宽度发生改变时触发
        win.addEventListener("resize", function() {
            clearTimeout(tid);
            tid = setTimeout(refreshRem, 300);
        }, false);
        //pageshow firefox/open的一个事件,在chrome中不会触发
        //在页面后退时静态资源会直接重缓存中读取
        win.addEventListener("pageshow", function(e) {
            if (e.persisted) {
                clearTimeout(tid);
                tid = setTimeout(refreshRem, 300);
            }
        }, false);
        //document.readyState 描述文档的加载状态

        // loding 文档仍然在加载中
        // interactive 文档已经加载完成并已经被解析,但是图像,框架之类的资源仍然在加载中
        // complete 说有资源都已经加载完成,load事件即将被触发
        // 在状态改变时document.readyState事件将被触发

        if (doc.readyState === "complete") {
            doc.body.style.fontSize = 12 * dpr + "px";
        } else {
            //DOMContentLoaded 在文档加载完成后触发,不会等待图像,框架等资源,参考$(function(){}) / $.ready()
            doc.addEventListener("DOMContentLoaded", function(e) {
                doc.body.style.fontSize = 12 * dpr + "px";
            }, false);
        }


        refreshRem();

        flexible.dpr = win.dpr = dpr;
        flexible.refreshRem = refreshRem;
        //rem 2 px  转化方法
        flexible.rem2px = function(d) {
            var val = parseFloat(d) * this.rem;
            if (typeof d === "string" && d.match(/rem$/)) {
                val += "px";
            }
            return val;
        }
        //px 2 rem  转化方法
        flexible.px2rem = function(d) {
            var val = parseFloat(d) / this.rem;
            if (typeof d === "string" && d.match(/px$/)) {
                val += "rem";
            }
            return val;
        }

    })(window, window["lib"] || (window["lib"] = {}));

手淘的布局方法主要是通过dpr来设置不同屏幕下的不同比例关系,drp指的是默认缩放为100%的情况下设备像素和CSS像素的比值

dpr=设备像素 / CSS像素

具体的关于dpr的解释可以看下面这篇文章

移动web开发之像素和DPR

如果使用手淘的布局方案注意一个问题,我们需要去除页面中设置了name=viewportmeta标签,在源码中我们可以看到如果存在改标签,那么lib-flexible不会动态改变缩放比例

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/117362.html

相关文章

  • 响应布局的实现

    摘要:响应式布局的概念响应式布局,即,在实现不同屏幕分辨率的终端上浏览网页的不同展示方式。框架实现响应式布局利用中栅格系统可以简单实现响应式布局,这里就需要去理解一下啥是栅格系统代表在端上显示在一行的个栅栏,也就是一半。 响应式布局的概念 响应式布局,即 Responsive design,在实现不同屏幕分辨率的终端上浏览网页的不同展示方式。通过响应式设计能使网站在手机和平板电脑上有更好的浏...

    syoya 评论0 收藏0
  • CSS及布局

    摘要:经过半年的打磨,正式发布,主要是新增了一些常用组件,并使用命名,为接下来的微信小程序开发做好准备。这两种方式实现的瀑布流式布局均支持首屏和网页窗口大小改变时的列数自适应。主要是对于标准里的布局方式草案中的布局方式进行一些总结。 一劳永逸的搞定 flex 布局 寻根溯源话布局 一切都始于这样一个问题:怎样通过 CSS 简单而优雅的实现水平、垂直同时居中。记得刚开始学习 CSS 的时候,看...

    jaysun 评论0 收藏0
  • 不规则图片列表实现响应布局

    摘要:优点在于响应式布局非常方便,都是按照比例进行的缩放,弊端是在于如果图片不规则,那么图片变形是难免的。一次布局多终端友好 技术开发和实际运营总是有很大差别的,比如常见的图片列表,一般设计图上都是固定尺寸大小的,但是实际操作起来并没有太多人去ps修剪图片到知道的尺寸,大部分都是差不多比例的图片就直接上传了,为了解决不规则图片列表展示问题有相应的解决方案例如瀑布流,或者相册等,但是对于多终端...

    ASCH 评论0 收藏0
  • 不规则图片列表实现响应布局

    摘要:优点在于响应式布局非常方便,都是按照比例进行的缩放,弊端是在于如果图片不规则,那么图片变形是难免的。一次布局多终端友好 技术开发和实际运营总是有很大差别的,比如常见的图片列表,一般设计图上都是固定尺寸大小的,但是实际操作起来并没有太多人去ps修剪图片到知道的尺寸,大部分都是差不多比例的图片就直接上传了,为了解决不规则图片列表展示问题有相应的解决方案例如瀑布流,或者相册等,但是对于多终端...

    linkFly 评论0 收藏0
  • 真的,移动端尺寸自适应与dpr无关

    摘要:做移动端自适应时可能很多人都对自适应和之间的关系产生疑问也有一些人会疑虑比如我的自适应方案没有加会不会出问题针对这些疑问我说一下我的见解。 做移动端自适应时可能很多人都对自适应和dpr之间的关系产生疑问,也有一些人会疑虑比如我的自适应方案没有加dpr会不会出问题,针对这些疑问我说一下我的见解。 1. 什么是尺寸自适应 首先标题说的自适应,可能自适应在不同人眼里理解不同,特别与响应式的关...

    omgdog 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<