响应式布局:
根据不同的移动设备的尺寸,开发一套可以适应各种尺寸的页面,让页面以最好的视觉效果呈现在屏幕;

常见的响应式布局方法:

  • 媒体查询
  • rem 布局
  • flexBox
  • 流式布局

一、1. flex 布局

什么是 flex?

flex 是 Flex box 的缩写,意为弹性布局,用来为盒模型提供最大的灵活性;

  • 容器指定为 flex 布局:
  1. display: flex;
  • 行内元素也可以使用flex布局:display: inline-flex
  • 使用 flex 布局后,子元素的 float clear vertical-align 属性自动失效

二、基本概念

2.1 容器:采用 flex 布局的元素称为 flex 容器(flex container),简称容器。它所有的子元素自动成为容器成元素,称为Flex项目(flex item)简称项目;

2.2 主轴和交叉轴:

  • 默认 水平的主轴和垂直的交叉轴。
  • 主轴开始的位置与边框的交叉点叫做 main start,结束位置叫做 main end;
  • 交叉轴开始的位置叫做 cross start,结束位置叫做 cross end;

项目默认沿着主轴排列,单个项目占据的主轴空间叫做 main size,占据交叉轴空间叫做 cross size;

三、容器属性

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content

3.1 flex-direction: 设置主轴方向;可选值:
row (默认值) 主轴为水平方向,起点在左端
row-reverse: 主轴为水平方向,起点在左端
column: 主轴为垂直方向,起点在上沿
column-revers: 主轴为垂直方向,起点在下沿。

3.2 flex-wrap : 设置项目拍不下时如何换行

  • nowrap 默认值 不换行,压缩 item 的尺寸来实现
  • wrap: 换行,第一行在上方
  • wrap-reverse: 换行,第一行在下方

3.3 flex-flow flex-direction 和 flex-wrap 的简写

3.4 justify-content 设置项目在主轴上的对齐方式,可选值:

  • flex-start: 默认值,左对齐
  • flex-end: 右对齐
  • center: 居中
  • space-between: 两端对齐,项目之间间隔相等
  • space-around: 每个项目两侧间距相等,所以项目之间的距离比项目和边框之间的距离大一倍

3.5 align-items 设置项目在交叉轴上对齐方式

  • flex-start: 交叉轴起点对齐
  • flex-end: 交叉轴终点对齐
  • center: 交叉轴的终点对齐
  • baseline: 项目第一行文字基线对齐
  • stretch: 默认值,如果项目未设置高度或者设为 auto,将占满整个容器的高度

四 项目属性:

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self

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

4.2 flex-grow 属性:定义项目的放大比例,默认为0,如果剩余空间也不会放大;如果所有的项目的 flex-grow 都为1,则他们等分剩余空间,如果某一个的 flex-grow 为2,其余的都为1,为2的那个占据的剩余空间比其他的大

4.3 flex-shrink 属性定义了项目的缩小比例,默认为1,即空间不足,该项目将缩小;如果所有的项目的 flex-shrink都为1,当空间不足时,都将等比缩小;如果一个项目的 flex-shrink 为0,其他的都为1时,前者不缩小;(如果容器设置了 flex-wrap 无效了)

4.4 align-self: 允许单个项目与其他项目的对齐方式不同,可以覆盖容器的 align-items 属性;默认值 auto,表示继承父元素的 align-item 属性,如果没有 stretch

  • auto
  • flex-start
  • flex-end
  • center
  • baseline
  • stretch

二、rem布局

viewport

在使用 rem 布局前,必须先在 html 开头加入一个 meta 标签,name 是 viewport

<meta name="viewport" content="width=device-width, initial-scale=1.0">

rem 是什么?

rem: 和 px 一样都是单位,px 是固定单位,rem 是相对单位,是相对于 html 标签的字体大小来的,html 标签的字体大小 font-size 就是 1rem;

为什么用 rem 布局?

成 rem 有一个好处,如果写成 px 就是死的,现在我们写成 rem,把元素的跟字体大小调成 50px,页面中所有的盒子都缩放了,而且比例一致;我们按照一个手机的尺寸把图切好了,但是拿到另一个手机上了,此时另一个手机的尺寸和之前的手机不一样,样式就全乱了。现在用 rem 来写,当换了手机后,我们根据手机屏幕的大小改 html 的字体大小,这些样式自动按照比例改了。

rem 布局的思路

我们开始给 html 的字体大小设置为 100px(此时 1rem 就是100px),接下来我们写样式的时候,把所有的尺寸都用 rem 设定(测量出来的px / 100 就是需要设置的 rem 的值),但是如果 html 的 font-size 不变,用 rem 和 px 一样,但是如果字体改变了,也就是改变了 rem 和 px 之间的换算比例,那么之前所有用 rem 做单位的样式都会按照最新的比例进行缩放(实现了改动 html 的 font-size,整个页面中的元素都会跟着缩放了);

真实项目中:设计师会给我们一套设计稿,设计稿的常用宽度,640 和 750
常用的宽度是750px 的,拿到设计稿后,我们严格按照设计稿中尺寸编写样式;此时设置html {font-size: 100px};

接下来写样式,把测量出来的 px 都除以100变为 rem,所有的单位都基于 rem 来写;
=> 假设设计稿是750px,相当于在750的设备下,1rem = 100px
如果页面运行在375的设备上,我们需要修改 html 的字体大小,以此实现页面整体缩放;375 / 750 * 100 => 当前设备上 HTML 字体的大小。
如果现在页面运行在375的设备上,我们根据这个比例把 html 的 font-size 进行修改,页面中所有用 rem 的尺寸都会自动跟着修改;

rem 计算方法

function computedFont() {
    let winW = document.documentElement.clientHeight || document.body.clientWidth;
    let desW = 750;
    document.documentElement.style.fontSize = 100 * winW / 750 + 'px';
  }

  computedFont();
  window.addEventListener('resize', computedFont)

三、移动端事件

移动端有单独的触摸事件,一般不使用 click 事件,因为在移动端有 300ms 的延迟;

let box = document.querySelector('#box');
  • touchstart 触摸元素时触发
box.addEventListener('touchstart', function (e) {
    console.log('toustart');
    console.log(e); // TouchEvent 触摸事件对象
    // 在触摸事件对象中,把触摸的信息存放在 touches 中;
    console.log(e.touches[0].clientX);
  });
  • touchmove 在元素上滑动时触发
box.addEventListener('touchmove', function (e) {
    console.log(e.touches);
  });
  • touchend 当手指离开元素时触发
box.addEventListener('touchend', function (e) {
    console.log('touchend');
    console.log(e.changedTouches); // touchend 没有 e.touches ,事件信息放到了 e.changedTouc
  // hes 属性上
  })

四、事件案例

  • 如果在盒子上水平或者竖直滑动距离超过 30px,让当前盒子的透明度变为1,否则盒子旋转540deg;
  • HTML 代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Title</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    html {
      font-size: 100px;
    }
    #box {
      width: 3rem;
      height: 1.5rem;
      background: lightgreen;
    }
  </style>
  <script>
    ;(function (designWidth = 750) {
      function computedFont() {
        let winW = document.documentElement.clientWidth || document.body.clientWidth;
        document.documentElement.style.fontSize = winW / designWidth * 100 + 'px';
      }
      computedFont();
      window.addEventListener('resize', computedFont);
    })(750)
  </script>
</head>
<body>
<div id="box"></div>
</body>
</html>
  • JS 代码
let box = document.querySelector('#box');
    box.addEventListener('touchstart', function (e) {
        // dom2 级事件中函数 this 仍然是绑定当前事件的元素
        let {touches: {0: point}} = e;
        this.x = point.clientX;
        this.y = point.clientY;
        this.style.transition = 'all 0s';
        this.style.transform = 'rotate(0)'
    });
    box.addEventListener('touchmove', function (e) {
        let {touches: {0: {clientX, clientY}}} = e;
        let {x, y} = this;
        this.moreThan30 = clientX - x > 30 || clientY - y >30;
    });
    box.addEventListener('touchend', function (e) {
        this.style.transition = 'all 1s';
        if (this.moreThan30) {
            this.style.opacity = 1;
        } else {
            this.style.transform = 'rotate(540deg)';
        }
    })

五、swiper 插件的使用

本例是讲解查阅文档的能力;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="swiper/swiper.min.css">
    <style>
        .swiper-container {
            margin: 40px auto;
            width: 800px;
            height: 500px;
        }
        .swiper-slide img {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
<div class="swiper-container">
    <div class="swiper-wrapper">
        <div class="swiper-slide">
            <img src="banner/banner1.jpg" alt="">
        </div>
        <div class="swiper-slide">
            <img src="banner/banner2.jpg" alt="">
        </div>
        <div class="swiper-slide">
            <img src="banner/banner3.jpg" alt="">
        </div>
        <div class="swiper-slide">
            <img src="banner/banner4.jpg" alt="">
        </div>
        <div class="swiper-slide">
            <img src="banner/banner5.jpg" alt="">
        </div>
    </div>
    <!-- 如果需要分页器 -->
    <div class="swiper-pagination"></div>

    <!-- 如果需要导航按钮 -->
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>

    <!-- 如果需要滚动条 -->
    <div class="swiper-scrollbar"></div>
</div>

<script src="swiper/swiper.min.js"></script>

<script>
    var mySwiper = new Swiper ('.swiper-container', {
        direction: 'horizontal', // 垂直切换选项
        loop: true, // 循环模式选项
        autoplay: true,

        // 如果需要分页器
        pagination: {
            el: '.swiper-pagination',
        },

        // 如果需要前进后退按钮
        navigation: {
            nextEl: '.swiper-button-next',
            prevEl: '.swiper-button-prev',
        }
    })
</script>
</body>
</html>