本文作为 Flex 布局进阶,不对基础做详细介绍,关于 Flex 基础知识请到阮一峰老师的Flex 布局教程:语法篇
看过基础,或者已经使用 Flex 布局的朋友可以根据本文试着动手写一写,先不急着开工,看看其它大型框架怎么实现的。
Bootstrap 框架
相信大家都用过 Bootstrap 框架,目前最受欢迎的响应式布局框架,在 Github 上 10w+ 的 star
而其中的栅格系统深入人心,针对不同尺寸的屏幕提供一套完整布局方案,不了解栅格系统的可以看中文官方文档栅格系统
对于新人概念有点多,跳跃性挺强,不过跟着跳转链接一步一步摸索很快就能入门,这里给的都是中文链接。
给出一段栅格系统的代码片段
<div class="row">
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
<div class="col-md-1">.col-md-1</div>
</div>
<div class="row">
<div class="col-md-8">.col-md-8</div>
<div class="col-md-4">.col-md-4</div>
</div>
<div class="row">
<div class="col-md-4">.col-md-4</div>
<div class="col-md-4">.col-md-4</div>
<div class="col-md-4">.col-md-4</div>
</div>
<div class="row">
<div class="col-md-6">.col-md-6</div>
<div class="col-md-6">.col-md-6</div>
</div>
效果如下
这里栅格系统将屏幕水平均分成 12 份。通过加对应的 class 调整布局。语法也通俗易懂不过多解释。
再来看另一个列偏移的例子
<div class="row">
<div class="col-md-4">.col-md-4</div>
<div class="col-md-4 col-md-offset-4">.col-md-4 .col-md-offset-4</div>
</div>
<div class="row">
<div class="col-md-3 col-md-offset-3">.col-md-3 .col-md-offset-3</div>
<div class="col-md-3 col-md-offset-3">.col-md-3 .col-md-offset-3</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">.col-md-6 .col-md-offset-3</div>
</div>
效果如下
使用 .col-md-offset-*
类可以将列向右侧偏移。这些类实际是通过使用 *
选择器为当前元素增加了左侧的边距(margin)。例如,.col-md-offset-4
类将 .col-md-4
元素向右侧偏移了4个列(column)的宽度。
看到这里大家感觉这个方案很完美,既有相应布局又有布局的偏移,但我的项目需求是这样的
这里单选按钮和票的名称居左,而票价居右,左右给相同的 padding
后,单选按钮和票价分别在左右处于临界状态,我并不知道右侧的票价占几个栅格,也不知道左侧的偏移到底给多少合适(因为票价是变量,可能 10 位数,当然可能性为 0)
了解 flex 基础的一眼识破,不是有 space-between
嘛,对就是它,不了解的朋友继续转到文章开头的链接温习一下。
下文我们去找设计灵感
Angular Material 框架
What is Angular Material?
For developers using AngularJS, Angular Material is both a UI Component framework and a reference implementation of Google's Material Design Specification. This project provides a set of reusable, well-tested, and accessible UI components based on Material Design.
用过 AngularJS 的人应该多少有所耳闻,没听说的也没关系。我们学习的是设计思想而不是研讨一门框架。
这里的案例来源于:https://material.angularjs.or...
上面链接是 Angular Material 框架布局部分的 API 文档,文档下方有单选按钮组合来呈现不同的布局实现。
先给出基本代码
<div layout="row" layout-align="center center">
<div>one</div>
<div>two</div>
<div>three</div>
</div>
效果如下
其它属性如下,
进入上方链接可以在线感受一下,所有布局效果,这里不一一截图
同样也支持栅格系统不过这里更精密一些,是 100 份的均分,官网例子给的特别全面,链接: https://material.angularjs.or...
这里给大家选出一个比较通用的例子,代码如下
<div layout="row" layout-wrap>
<div flex="30">
[flex="30"]
</div>
<div flex="45">
[flex="45"]
</div>
<div flex="25">
[flex="25"]
</div>
<div flex="33">
[flex="33"]
</div>
<div flex="66">
[flex="66"]
</div>
<div flex="50">
[flex="50"]
</div>
<div flex>
[flex]
</div>
</div>
效果如下
代码简洁易懂,layout="row"
表示在水平方向分布,最后的 flex
不带参数表明自动填充,将不带 flex
属性的元素之前的空间填满。
下面我们回到需求,针对需求给出 html 结构的设想
<div layout="row">
<div flex>单选按钮和票的名称</div>
<div>票价</div>
</div>
或者干脆
<div layout="row" layout-align="space-between center">
<div>单选按钮和票的名称</div>
<div>票价</div>
</div>
好,有的朋友说使用 float
或者 text-align
也可以满足需求的啊,干嘛写这么长篇幅的文章解释这个案例?
问的好,首先 flex 布局优势特别明显,弹性布局,不存在兼容问题,也不用清除浮动。
设想一下项目复杂度再大一点呢,守旧的方案还能不能保持清晰的 html 文档结构?css 又该从哪里下手?
既然我们出发点是对的,接下来选择一下设计模式。
简单说两种模式
class 属性为代表的 Bootstrap 框架
自定义属性为代表的 Angular Material 框架
我个人认为 class 过多导致布局和样式混在一起不好分辨,后期维护较困难,决定采用 Angular Material 框架的设计模式。
首先大家要了解 css 属性选择器,常用的有 class选择器,id选择器,tag选择器,属性选择器还是比较少用的。
下面给 w3school 的截图,子串匹配属性选择器的语法
简单易懂,下面直接上写好的代码 layout.scss
[layout] {
display: flex;
}
[flex] {
flex: 1;
}
[layout-wrap] {
flex-wrap: wrap;
}
[layout="row"] {
flex-direction: row;
}
[layout-wrap] {
flex-wrap: wrap;
}
[layout="column"] {
flex-direction: column;
}
[layout-align="start start"],
[layout-align="start center"],
[layout-align="start end"] {
justify-content: flex-start;
}
[layout-align="center start"],
[layout-align="center center"],
[layout-align="center end"] {
justify-content: center;
}
[layout-align="end start"],
[layout-align="end center"],
[layout-align="end end"] {
justify-content: flex-end;
}
[layout-align="space-between start"],
[layout-align="space-between center"],
[layout-align="space-between end"] {
justify-content: space-between;
}
[layout-align="space-arround start"],
[layout-align="space-arround center"],
[layout-align="space-arround end"] {
justify-content: space-arround;
}
[layout-align="start start"],
[layout-align="center start"],
[layout-align="end start"],
[layout-align="space-between start"],
[layout-align="space-arround start"] {
align-items: flex-start;
}
[layout-align="start center"],
[layout-align="center center"],
[layout-align="end center"],
[layout-align="space-between center"],
[layout-align="space-arround center"] {
align-items: center;
}
[layout-align="start end"],
[layout-align="center end"],
[layout-align="end end"],
[layout-align="space-between end"],
[layout-align="space-arround end"] {
align-items: flex-end;
}
好,到这为止我们的 flex 框架已经实现了,效果语法和 Angular Material 框架是一样的。大家自行尝试。
细心的朋友发现这里 orange 并没有实现栅格系统,因为现实需求中栅格系统布局的实用价值不是很大(各元素宽度根据内容变化,手机端在元素宽度不变的情况可以通过相同的 rem 值针对不同屏幕适配,而 n 等分可以通过 space-arround
属性实现),而且本文把开发的重点放在了 flex 的封装上。
总结
在现代复杂 css 样式的开发中,尽量避免重复书写相同的布局代码,除非特殊需求(真对相应的 class 给样式),这样既满足模块化思想又保证了代码复用,项目中只需引入 layout.scss
即可。如果你针对 css 代码模块化有不同的想法欢迎留言交流。
欢迎关注 orange 的 个人博客 http://orangexc.xyz/