最近在学习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>
网友评论