Flexbox格局技术研究

Flexbox布局技术研究

写在前面

Flexbox即弹性盒子模型,它在css中的定义和标记非常简单,通过媒体查询的方式就可适配和响应变化,不需要清除浮动,不需要使用额外的框架,也不需要使用大量冗余的代码来实现栅格布局。

Flexbox究竟是什么

简单地说,我们可以在一个flex容器中标记一些flex子元素,通过css来定义布局。flexbox有很多属性来定义布局。

  • flex-direction: 通过这个属性,我们能指定flex容器的子元素是按行显示还是按列显示。
    可以通过这个属性定义元素按升序显示还是按降序显示。
  • justify-content: 通过这个属性,可以声明浏览器如何分配元素以外的可用空间。比如有3个节点,它们组合起来一共占据了容器50%的空间,我们能够指定元素集中在左边、右边还是中间。或者是均匀地从左往右分布,或许其他的一些方式。
  • flex-wrap: 通过这个属性,我们能够指定当flex子元素的总宽度超出了容器的空间时,是否换行。

flex属性值和用途

栅格系统

目前,栅格系统在页面的布局管理中占据了很重要的地位。默认盒模型的行为导致在布局中通常会使用 float和inline-block等hacks方式来实现。而Flexbox能让我们仅仅是用很少的几行css代码就能轻松实现一套功能强大、可拓展的栅格系统。

简单的栅格布局

在传统的栅格系统中,我们必须用某种方式说明在一行中包含多少个内容节点,然后给每个内容节点设置相应的宽度。通过Flexbox,我们可以在一行中放置任意数目的项目,而且这些项目的宽度可以根据容器的宽度自动分配。换句话说,在css中,我们可以通过一些标记来达到目的,而不用关心一行中放置多少个内容节点。代码如下:

    <div class="grid">
        <div class="grid-row">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
        </div>
        <div class="grid-row">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
        </div>
        <div class="grid-row">
            <div class="grid-item">1</div>
            <div class="grid-item">2</div>
            <div class="grid-item">3</div>
            <div class="grid-item">4</div>
        </div>
    </div>

对应的css代码如下(为了美观,添加了简单的样式):

    .grid {
        boder: solid 1px #e7e7e7;
    }
    .grid-row {
        display: flex;
    }
    .grid-item {
        flex: 1;
        padding: 12px;
        border: 1px solid #f7f7f7;
    }

    .grid--row {
        display: flex;
        flex-direction: column;
    }

接着,我们就可以看到神奇的自适应栅格效果。

简单的栅格布局

响应式栅格布局

在上面的基础上,如果要实现类似bootstrap的响应式布局要怎么处理呢?使用Flexbox,我们同样不需要设置宽度节点,直接添加媒体查询即可。对上面的代码稍作修改:

<div class="grid">
    <h2>列布局</h2>
    <div class="grid--row grid--row-sm">
        <div class="grid-item">1</div>
        <div class="grid-item">2</div>
        <div class="grid-item">3</div>
        <div class="grid-item">4</div>
    </div>
    <div class="grid--row grid--row-md">
        <div class="grid-item">1</div>
        <div class="grid-item">2</div>
        <div class="grid-item">3</div>
        <div class="grid-item">4</div>
        <div class="grid-item">5</div>
        <div class="grid-item">6</div>
        <div class="grid-item">7</div>
    </div>
    <div class="grid--row grid--row-lg">
        <div class="grid-item">1</div>
        <div class="grid-item">2</div>
        <div class="grid-item">3</div>
    </div>
</div>

对应的css如下:

    .grid {
        boder: solid 1px #e7e7e7;
     }
     .grid-row {
         display: flex;
     }
     .grid-item {
         flex: 1;
         padding: 12px;
         border: 1px solid #f7f7f7;
     }
     .grid--row {
         display: flex;
         flex-direction: column;
     }
     @media screen and (min-width:480px) {
         .grid--row-sm {
             display: flex;
             flex-direction: row;
         }
     }
     @media screen and (min-width:720px) {
         .grid--row-md {
             display: flex;
             flex-direction: row;
         }
     }

     @media screen and (min-width:960px) {
         .grid--row-lg {
             display: flex;
             flex-direction: row;
         }
     }

这样响应式的栅格布局就完成了。下图:

在大屏显示的效果:
在大屏显示的效果

屏幕在960px~720px
屏幕在960px~720px

屏幕在480px~720px
屏幕在480px~720px

有了这样的栅格系统,我们就可以自由地进行嵌套使用了,它的适应性非常强。

垂直居中

在传统的css中,垂直对齐的实现非常糟糕。有时候我们可以给节点设置inline-box能解决这个问题,也有人使用绝对定位的hack来实现,还有人使用过时的table布局(在语意化的今天,这是不符合要求的)。而Flexbox能够轻松地处理这个问题。

第一个例子:左侧是用户头像,右侧是用户的名字和一些信息。我们将使用Flexbox来使得用户头像在区域中垂直居中。

        <div class="user">
            <div class="user-avatar"></div>
            <div class="user-desc">
                <h2 class="user-username">John Doe</h2>
                <p class="user-excerpt">
                    Hello! I'm John Doe. Nice to meet you!
                </p>
            </div>
        </div>
        <div class="user">
            <div class="user-avatar"></div>
            <div class="user-desc">
                <h2 class="user-username">John Doe</h2>
                <p class="user-excerpt">
                    Hello! I'm John Doe. Nice to meet you!Hello! I'm John Doe. Nice to meet you!Hello! I'm John Doe. Nice to meet you!Hello! I'm John Doe. Nice to meet you!Hello! I'm John Doe. Nice to meet you!Hello! I'm John Doe. Nice to meet you!Hello! I'm John Doe. Nice to meet you!Hello! I'm John Doe. Nice to meet you!
                </p>
            </div>
        </div>

对应的css如下:

            .user {
                display: flex;
                align-items: center;
                margin-bottom: 20px;
            }

            .user:last-child {
                margin-bottom: 0;
            }

            .user-avatar {
                flex: 0 0 96px;
                width: 96px;
                height: 96px;
                background-color: #e7e7e7;
            }

            .user-desc {
                flex: 1;
                margin-left: 24px;
                padding: 12px;
                border: solid 1px #e7e7e7;
            }

注意:align-items这个属性能够让flex项目垂直于flex基准线方向队列显示。换句话说,如果flex基准线沿着水平方向,我们能够让每个项目基于这个水平线排列。因此这里我们只要设置了align-items:center 就可以了。
然后我们见证奇迹的一刻:

头像始终垂直居中

第二个例子:在一个宽度固定、高度可变的容器中,如何实现元素始终处于容器中心(水平和垂直都居中)

让我们想象一下,在所有的节点标记中最上面的是banner,这个banner中有一些标题文本。在小屏幕中,banner的高度是180px,它将通过设置两个端点将高度变为480px。每次变化后,我们都希望标题文本仍处在banner的中心,无论是水平方向还是垂直方向。下面是标记节点:

    <div class="banner">
         <div class="banner-content">
              <h2 class="banner-title">Sysmetrical Perfection</h2>
              <span class="banner-sub">A beautiful sight, achieved with flexbox.</span>
         </div>
    </div>

这次我们使用 justify-content 属性。这个属性的作用是定义项目周围沿着flex基准线的空间如何显示。下面是css代码:

           .banner {
                display: flex;
                align-items: center;
                justify-content: space-around;
                height: 180px;
                background-color: #e7e7e7;
            }

            .banner-content {
                text-align: center;
            }

            .banner-title, .banner-sub {
                margin: 0;
                padding: 0;
                line-height: 1.5;
            }

            @media screen and (min-width:480px) {
                .banner {
                    height: 240px;
                }
            }

            @media screen and (min-width:720px) {
                .banner {
                    height: 360px;
                }
            }

            @media screen and (min-width:960px) {
                .banner {
                    height: 480px;
                }
            }

这样一来,无论banner的高度是多少,内容总会保持在水平和垂直方向的中心位置,这就是Flexbox的强大之处!

banner的内容始终保持居中

在React Native中使用Flexbox

下面以栅格系统为例,简单介绍一下如何把Web中的布局 转换到 React Native上。

/**
 * @desc 将web中的布局转换到React Native上
**/

import React, {
    AppRegistry,
    StyleSheet,
    Component,
    Text,
    View
} from 'react-native';

const styles = StyleSheet.create({
    grid: {
        padding: 30,
        marginTop: 65,
        borderColor: '#e7e7e7',
    },
    grid_row: {
        flex: 1,
        flexDirection: 'row',
        padding: 5,
    },
    grid_item: {
        flex: 1,
        backgroundColor: '#e7e7e7',
        height: 30,
        textAlign: 'center',
    }
});

class SimpleApp extends React.Component {
    render() {
        return (
            <View style={styles.grid}>
                <View style={styles.grid_row}>
                    <Text style={styles.grid_item}>1</Text>
                    <Text style={styles.grid_item}>2</Text>
                </View>
                <View style={styles.grid_row}>
                    <Text style={styles.grid_item}>1</Text>
                    <Text style={styles.grid_item}>2</Text>
                    <Text style={styles.grid_item}>3</Text>
                </View>
                <View style={styles.grid_row}>
                    <Text style={styles.grid_item}>1</Text>
                    <Text style={styles.grid_item}>2</Text>
                    <Text style={styles.grid_item}>3</Text>
                    <Text style={styles.grid_item}>4</Text>
                </View>
            </View>
        )
    }
}

AppRegistry.registerComponent('SimpleApp', () => SimpleApp);

推荐一个详细的教程 http://caibaojian.com/flexbox-guide.html

相关内容推荐