Skip to content

响应式布局 #32

Open
Open
@TieMuZhen

Description

@TieMuZhen

建议提前学习以下两个知识点:


一、前言

响应式网站设计(Responsive Web design)是一种网络页面设计布局,页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整

响应式网站常见特点:

  • 同时适配PC + 平板 + 手机等
  • 标签导航在接近手持终端设备时改变为经典的抽屉式导航
  • 网站的布局会根据视口来调整模块的大小和位置

二、实现方式

响应式设计的基本原理是通过媒体查询检测不同的设备屏幕尺寸做处理,为了处理移动端,页面头部必须有meta声明viewport

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

属性对应如下:

  • width=device-width: 是自适应手机屏幕的尺寸宽度
  • maximum-scale:是缩放比例的最大值
  • inital-scale:是缩放的初始化
  • user-scalable:是用户的可以缩放的操作

实现响应式布局的方式有如下:

  • 媒体查询
  • 百分比
  • vw/vh
  • rem

媒体查询

CSS3中的增加了更多的媒体查询,就像if条件表达式一样,我们可以设置不同类型的媒体条件,并根据对应的条件,给相应符合条件的媒体调用相对应的样式表

使用@Media查询,可以针对不同的媒体类型定义不同的样式,如:

@media screen and (max-width: 1920px) { ... }

当视口在375px - 600px之间,设置特定字体大小18px

@media screen (min-width: 375px) and (max-width: 600px) {
  body {
    font-size: 18px;
  }
}

通过媒体查询,可以通过给不同分辨率的设备编写不同的样式来实现响应式的布局,比如我们为不同分辨率的屏幕,设置不同的背景图片

比如给小屏幕手机设置@2x图,为大屏幕手机设置@3x图,通过媒体查询就能很方便的实现

百分比

通过百分比单位 " % " 来实现响应式的效果

比如当浏览器的宽度或者高度发生变化时,通过百分比单位,可以使得浏览器中的组件的宽和高随着浏览器的变化而变化,从而实现响应式的效果

heightwidth属性的百分比依托于父标签的宽高,但是其他盒子属性则不完全依赖父元素:

  • 子元素的top/leftbottom/right如果设置百分比,则相对于直接非static定位(默认定位)的父元素的高度/宽度
  • 子元素的paddingmargin如果设置百分比,不论是垂直方向或者是水平方向,都相对于直接父亲元素的width,而与父元素的height无关。
  • border-radius不一样,如果设置border-radius为百分比,则是相对于自身的宽度

可以看到每个属性都使用百分比,会造成布局的复杂度,所以不建议使用百分比来实现响应式

vw/vh

vw表示相对于视图窗口的宽度,vh表示相对于视图窗口高度。 任意层级元素,在使用vw单位的情况下,1vw都等于视图宽度的百分之一

rem

在以前也讲到,rem是相对于根元素htmlfont-size属性,默认情况下浏览器字体大小为16px,此时1rem = 16px

可以利用前面提到的媒体查询,针对不同设备分辨率改变font-size的值,如下:

@media screen and (max-width: 414px) {
  html {
    font-size: 18px
  }
}

@media screen and (max-width: 375px) {
  html {
    font-size: 16px
  }
}

@media screen and (max-width: 320px) {
  html {
    font-size: 12px
  }
}

为了更准确监听设备可视窗口变化,我们可以在css之前插入script标签,内容如下:

//动态为根元素设置字体大小
function init () {
    // 获取屏幕宽度
    var width = document.documentElement.clientWidth
    // 设置根元素字体大小。此时为宽的10等分
    document.documentElement.style.fontSize = width / 10 + 'px'
}

//首次加载应用,设置一次
init()
// 监听手机旋转的事件的时机,重新设置
window.addEventListener('orientationchange', init)
// 监听手机窗口变化,重新设置
window.addEventListener('resize', init)

无论设备可视窗口如何变化,始终设置remwidth1/10,实现了百分比布局

框架

除此之外,我们还可以利用主流UI框架,如:element uiantd提供的栅格布局实现响应式

总结

响应式布局
优点:

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

缺点:

  • 仅适用布局、信息、框架并不复杂的部门类型网站
  • 兼容各种设备工作量大,效率低下
  • 代码累赘,会出现隐藏无用的元素,加载时间加长
  • 其实这是一种折中性质的设计解决方案,多方面因素影响而达不到最佳效果
  • 一定程度上改变了网站原有的布局结构,会出现用户混淆的情况

三、经典布局案例

div的100%是从其上一级div的宽高继承的,html, body级元素默认宽度是100%;但是高度并不是100%
所以要想实现撑满整个页面,必须显式地设置html, body高度为100%

两栏布局(公司写法)

效果如下图,浏览器缩放时绿色部分宽度固定,粉色部分宽度自适应调节

<style>
    html, body {
        height: 100%;
        margin: 0;
    }
    .left {
        position: absolute;
        left: 0;
        top: 0;
        width: 300px;
        height: 100%;
        background-color: green;
    }
    .right {
        height: 100%;
        margin-left: 300px;
        background-color: indianred;
    }
</style>
<body>
    <div class="left"></div>
    <div class="right"></div>
</body>

三栏布局

三栏布局效果如下所示,要求是两边宽度固定,中间部分随着浏览器缩放自适应改变宽度。具体实现方法有如下六种:

1、圣杯布局

注意: 代码中的中间部分的div代码放在两边div代码前面是为了加载时候先加载中间内容部分

所有浏览器都适配的完美实现方式代码如下:

<style>
    * {
        margin: 0;
    }
    html, body{
        height: 100%;
    }
    .column{
        float: left;
    }
    .main{
        height: 100%;
        padding: 0 100px 0 90px;
        position: relative;
    }
    .center{
        height: 100%;
        width: 100%;
        background-color: red;
    }
    .left{
        position: absolute;
        top: 0;
        left: 0;
        height: 100%;
        width: 90px;
        background-color: green;
    }
    .right{
        height: 100%;
        width: 100px;
        margin-right: -100px;
        background-color: black;
    }
</style>
<body>
    <div class="main">
        <div class="center column"></div>
        <div class="left column"></div>
        <div class="right column"></div>
    </div>
</body>

2、双飞翼布局

与圣杯布局不同的是中间内容div多嵌套一层div

<style>
    * {
        margin: 0;
    }
    html, 
    body,
    .wrap {
        height: 100%;
    }
    .inner {
        height: 100%;
        margin: 0 90px 0 100px;
        background-color: sandybrown;
    } 
    .center {
        height: 100%;
        width: 100%; /* 这句很重要*/
        background-color: green;
    }
    .left {
        width: 100px;
        height: 100%;
        margin-left: -100%;
        background-color: black;
    }
    .right {
        height: 100%;
        width: 90px;
        margin-left: -90px;
        background-color: indianred;
    }
    .column {
        float: left;
        position: relative;
    }
</style>
<body>
    <div class="wrap">
        <div class="center column"> 
            <div class="inner"></div>
        </div>
        <div class="left column"></div>
        <div class="right column"></div>
    </div>
</body>

3、float

该方法必须中间的内容div在最下面

<style>
    * {
        margin: 0;
    }
    html, 
    body,
    .wrap {
        height: 100%;
    }
    .center {
        height: 100%;
        margin: 0 90px 0 100px;
        background-color: green;
    }
    .left {
        width: 100px;
        height: 100%;
        float: left;
        background-color: black;
    }
    .right {
        height: 100%;
        width: 90px;
        float: right;
        background-color: indianred;
    }
</style>
<body>
    <div class="wrap">
        <div class="left"></div>
        <div class="right"></div>
        <div class="center"></div> <!-- center在最下面 -->
    </div>
</body>

4、absolute

该方法中的三个dom位置怎么排列都行

<style>
    * {
        margin: 0;
    }
    html, 
    body,
    .wrap {
        height: 100%;
    }
    .center {
        height: 100%;
        margin: 0 90px 0 100px;
        background-color: green;
    }
    .left {
        width: 100px;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        background-color: black;
    }
    .right {
        height: 100%;
        width: 90px;
        position: absolute;
        top: 0;
        right: 0;
        background-color: indianred;
    }
</style>
<body>
    <div class="wrap">
        <div class="left"></div>
        <div class="right"></div>
        <div class="center"></div>
    </div>
</body>

5、flex

flex: 1;自动填充剩余的空间

<style>
    * {
        margin: 0;
    }
    html, 
    body,
    .wrap {
        height: 100%;
        width: 100%;
        display: flex;
    }
    .center {
        height: 100%;
        flex: 1;
        background-color: green;
    }
    .left {
        height: 100%;
        width: 100px;
        background-color: black;
    }
    .right {
        height: 100%;
        width: 90px;
        background-color: indianred;
    }
</style>
<body>
    <div class="wrap">
        <div class="left"></div>
        <div class="center"></div>
        <div class="right"></div>
    </div>
</body>

flex: 1width: 10px同时出现的时候以flex为准,如下

.div1{
    flex: 1;
    width: 200px;
}
.div2{
    flex: 2;
}

flex布局中子元素宽度失效的问题

6、Grid

包层的div要要设置具体高度,不能用百分比

<style>
    * {
        margin: 0;
        padding: 0;
    }
    .wrap {
        height: 200px; /* 要设置具体高度,不能用百分比*/
        width: 100%;
        display: grid;
        grid-template-columns: 100px auto 90px;
    }
    .center {
        border: 1px solid red;
        background-color: green;
    }
    .left {
        background-color: black;
    }
    .right {
        background-color: indianred;
    }
</style>
<body>
    <div class="wrap">
        <div class="left"></div>
        <div class="center"></div>
        <div class="right"></div>
    </div>
</body>

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions