使用flex进行移动端自适应满屏布局

作者: Lynan 分类: HTML,CSS,Vue.js 发布时间: 2018-10-25 16:35

页面中含有固定在顶部和底部的导航栏和操作栏;中间的内容占满100%屏幕的剩余空间;内容超出容器时滚动显示。

关键: flex-direction; flex-shrink; flex-grow; flex-basis

实现:
1. 将容器设为flex布局display:flex;
2. 指定元素主轴排列方向:flex-direction: column;
3. 设定固定高度的元素flex: 0 0 auto;,即(flex-grow: 0;, flex-shrink: 0; flex-basis: auto)
4. 设定需要占满剩余空间的元素: height: 0; flex: 1 1 auto; 即(flex-grow: 1;, flex-shrink: 1;, flex-basis: auto;);这里的height:0在元素内需要继承高度的时候很重要。

注意:上面第4的的声明元素height: 0; 代表放弃元素自身的高度,由flex-grow或者flex—shrink得到的高度来当做元素高度。

我们可以把上述布局容器封装成Vue组件,使用slot插入以后就可以很方便地使用了。

容器组件flexBox.vue

<template>
  <div class="flex-box" :class="{'full': full, 'row': row}">
    <slot/>
  </div>
</template>
<script>
/* 
  * flex-box 自适应布局容器组件
  * 
  *   props        type         deault        description     
  *   full         Boolean      false         是否占满父级宽高,默认为否。
  *   row          Boolean      false         是否以行排列元素,默认为按列排列元素。
  *   
  * tag: <flex-box></flex-box>
*/
export default{
  props: {
    full: {
      type: Boolean,
      default: false
    },
    row: {
      type: Boolean,
      default: false
    }
  }
}
</script>
<style lang="scss" scoped>
.flex-box{
  display: flex;
  flex-direction: column;
  &.full{
    width: 100%;
    height: 100%;
  }
  &.row{
    flex-direction: row;
  }
}
</style>

元素组件flexItem.vue

<template>
  <div class="flex-item" :class="{'auto': auto}">
    <slot v-if="!auto"></slot>
    <div v-else class="child" :class="{'scroll': scroll}">
      <slot/>
    </div>
  </div>
</template>
<script>
/* 
  * flex-Item 自适应布局容器元素
  * 
  *   props        type         deault        description     
  *   
  *   auto         Boolean      false         是否占满剩余容器控件, 默认为否。
  *   scroll       Boolean      false         是否启用局部滚动, 默认为否。
  *   
  * tag: <flex-item></flex-item>
*/
export default {
  props: {
    auto: {
      type: Boolean,
      default: false
    },
    scroll: {
      type: Boolean,
      default: false
    }
  }
}
</script>
<style lang="scss" scoped>
.flex-item{
  width: 100%;
  flex: 0 0 auto;
  &.auto{
    height: 0;
    flex: 1 1 auto;
    position: relative;
  }
  .child{
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
    &.scroll{
      overflow-x: hidden;
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
    }
  }
}
</style>

使用方法:

  1. 全局注册:
    在main.js中引入并且声明自定义组件名称
import Vue from 'vue'
import flexBox from '@/components/common/flexBox/main.vue'
import flexItem from '@/components/common/flexBox/flexItem/main.vue'

Vue.component('flex-box', flexBox)
Vue.component('flex-item', flexItem)

  1. 使用
<flex-box full>
    <flex-item>
        <div>固定高度的内容</div>
    </flex-item>
    <flex-item auto>
        <div style="width:100%; height: 100%">占满剩余空间</div>
    </flex-item>
    <flex-item>
        <div>固定高度的内容</div>
    </flex-item>
</flex-box>

图例


注解

可以看到上述代码auto的flex-item组件中对child进行了绝对定位;这是因为在height: 0通过flex-grow进行延展得到的元素高度在部分浏览器中无法被继承,但是其本身的高度已经存在,将此元素设置成relative,用一个绝对定位于它本身的元素来显示内容就ok。

详情参见Solutions

1、 Specify a height on all parent elements

A reliable cross-browser solution is to specify a height on all parent elements. This prevents missing links, which Webkit-based browsers consider a violation of the spec.

Note that min-height and max-height are not acceptable. It must be the height property.

More details here: Working with the CSS height property and percentage values

2、 CSS Relative & Absolute Positioning

Apply position: relative to the parent and position: absolute to the child.

Size the child with height: 100% and width: 100%, or use the offset properties: top: 0, right: 0, bottom: 0, left: 0.

With absolute positioning, percentage height works without a specified height on the parent.

3、 Remove unnecessary HTML containers (recommended)

Is there a need for two containers around button? Why not remove .item or .item-inner, or both? Although button elements sometimes fail as flex containers, they can be flex items. Consider making button a child of .container or .item, and removing gratuitous mark-up.

Here’s an example:

Show code snippet

4、 Nested Flex Containers (recommended)

Get rid of percentage heights. Get rid of table properties. Get rid of vertical-align. Avoid absolute positioning. Just stick with flexbox all the way through.

Apply display: flex to the flex item (.item), making it a flex container. This automatically sets align-items: stretch, which tells the child (.item-inner) to expand the full height of the parent.

Important: Remove specified heights from flex items for this method to work. If a child has a height specified (e.g. height: 100%), then it will ignore the align-items: stretch coming from the parent. For the stretch default to work, the child’s height must compute to auto (full explanation).

发表评论

电子邮件地址不会被公开。 必填项已用*标注