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

最近在学习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>
发布了43 篇原创文章 · 获赞 50 · 访问量 68万+

猜你喜欢

转载自blog.csdn.net/supergao222/article/details/78434077
今日推荐