美文网首页
CSS Flex垂直排列时的容器宽度问题

CSS Flex垂直排列时的容器宽度问题

作者: 切糕糕 | 来源:发表于2017-11-03 11:48 被阅读44次

    最近在学习Flex布局,想模仿小米首页的商品Tab页效果:

    小米官网Tab页效果

    仔细推敲可以发现,图中商品的陈列方式并不是一行一行的,而是一列一列的。当第一列排满后,剩下的一项“彩虹7号电池”会被排到第二列。

    DOM的文档流通常是从左到右、自上而下横向排列元素的。像这种列式排列的,可以用JavaScript实现。但如果想用纯CSS实现,就会有些难度。

    你可能首先会想到使用Flex布局,把主轴方向设置为垂直方向。虽然这样商品竖着排列了,但是你会发现,随着商品列数的增加,外层的容器并不会自动变宽

    Flex外层容器不会自动变宽

    这是Flex布局设计上的一个问题,可以参考这个StackOverflow提问。这里还有个DEMO更直观地阐述了这个问题:jsFiddle链接

    解决这个问题的办法有不少,对比下来最巧妙的办法就是:完全不考虑用Flex布局,利用writing-mode属性就能搞定。writing-mode是个平时用得很少的属性,原本是用来方排版竖向的文字,如中国古诗词。对writing-mode的历史感兴趣的话可以阅读 张鑫旭大神的文章

    writing-mode既然能让文字竖着排,也就能让容器内的元素竖着排。给商品列表的外层容器加上writing-mode属性,就能解决容器宽度的问题:

    .tab-pane {
        // lr可理解为left to right,即垂直方向上从左到右
        writing-mode: vertical-lr; 
    }
    
    image.png

    似乎不太对,容器内的所有元素都继承了竖向排版,没关系,把容器内的元素writing-mode重置成通常文档流的方向:

    .tab-pane-items {
        // tb可理解为top to bottom,即水平方向自上而下
        writing-mode: horizontal-tb;
    }
    
    最终效果图

    这样就完美了。:-)

    附完整例子代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
      <script src="https://cdn.bootcss.com/vue/2.4.4/vue.min.js"></script>
      <style>
      .list-group-item {
        cursor: pointer;
        border-radius: 0;
        border: none;
        background: rgba(0,0,0,.8);
        color: white;
        margin: 0;
        position: static;
      }
      .tabs {
        position: relative;
        background: #eee;
      }
      .tabs .list-group {
        width: 20rem;
        margin-bottom: 0;
      }
      .tab-pane {
        box-shadow: 0 5px 20px gray;
        background: white;
        padding: 2rem;
        position: absolute;
        left: 20rem;
        height: 100%;
        top: 0;
        writing-mode: vertical-lr;
      }
      .tab-pane-items {
        display: inline-block;
        margin: 1rem 3rem 1rem 1rem;
        color: black;
        writing-mode: horizontal-tb;
      }
      span.image {
        padding: 10px 20px;
        margin-right: 1rem;
        background: #ccccff;
      }
      </style>
      <title>Document</title>
    </head>
    <body style="padding-top: 2rem;">
      <div class="container" id="app">
        <div class="tabs">
          <ul class="list-group">
            <li :class="['list-group-item', index==menu.active?'active':'']" 
              v-for="(item,index) in menu.items" @mouseover="menu.active=index" 
              @mouseleave="menu.active=-1" :key="index">{{item}}
              <div v-show="menu.active==index" class="tab-pane">
                <div v-for="n in (((index+1)*31)%19)" class="tab-pane-items">
                  <span class="image"></span>
                  <a href="#">iPhone手机</a>
                </div>
              </div>
            </li>
          </ul>
        </div>
      </div>
      <script>
      new Vue({
        el: '#app',
        data: {
          menu: {
            active: 1,
            items: [
              '手机 电话卡',
              '笔记本',
              '电视 盒子',
              '路由器 智能硬件',
              '移动电源 电池 插线板',
              '耳机 音箱',
              '保护套 贴膜',
              '线材 支架 储存卡',
              '箱包 服饰 鞋 眼镜',
              '生活周边'
            ]
          }
        }
      });
      </script>
    </body>
    </html>
    

    相关文章

      网友评论

          本文标题:CSS Flex垂直排列时的容器宽度问题

          本文链接:https://www.haomeiwen.com/subject/kweouxtx.html