深度了解bootstrap源码之sass篇(五)

前言

这一章主要学习button-group。目的是学习扩展按钮组件的写法,需要先了解前一篇的知识:深度了解bootstrap源码之sass篇(四)

研究对象

button组件(按钮)的扩展:button-group。分_button-group.scss和一些简单常用的方法(border-radius,clearfix,等)

使用方法和效果

按钮组的样式和功能很丰富,我先将所有的按钮组效果过一遍再看sass,促进消化。官网文档 → 按钮组
总结如下:

  • 功能类
    • loading状态下的效果
      1. 实现过程:新增属性data-loading-text,调用bootstrap.js中的button属性实现动态效果。
      2. 实现方法:$("#domId").button('loading')获取动态文本,...button('reset')插入。
      3. 从 v3.3.5 版本开始,此特性不再建议使用,并且已经在 v4 版本中删除了。
    • checked/radio状态下的效果
      1. 你必须手动添加.active样式在你的label表单内。
      2. 实现方法:调用button属性方法。
    • toggle状态下的效果
      1. 通过.active样式改变的效果。
      2. 实现方法:调用button属性方法。
    • 功能类实例图
  • 效果类
    • 普通效果
      • 所有的按钮组,父元素的class必须有.btn-group,子元素必须继承.btn

    • 工具栏样式的效果
    • 不同尺寸的效果
    • 下拉菜单嵌套的效果
    • 垂直排列的效果
    • 两端对齐排列的效果
      • 即为横向排列的按钮组,占据文档流的一行。

_clearfix.scss

源文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 清除浮动
// 用于现代浏览器
// 1 避免来自opera浏览器中contenteditable属性带来相关bug;
// 2 解决文档流错位bug;
// 3 使用table属性而不是block能克制子元素的top-margin。
// 源代码注释给的相关链接 → Source: http://nicolasgallagher.com/micro-clearfix-hack/
@mixin clearfix() {
&:before,
&:after {
content: " "; // 1
display: table; // 2
}
&:after {
clear: both;
}
}

border-radius.scss

源文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 单面边框半径
//border-radius用于边框四角的弧度,此方法写的分别是上下左右单面的边框半径,用处比较多,代码也易读就不多解释了。border-radius:50%时此元素刚好是个圆形,但是要保证该元素的子元素没有内容。
@mixin border-top-radius($radius) {
border-top-right-radius: $radius;
border-top-left-radius: $radius;
}
@mixin border-right-radius($radius) {
border-bottom-right-radius: $radius;
border-top-right-radius: $radius;
}
@mixin border-bottom-radius($radius) {
border-bottom-right-radius: $radius;
border-bottom-left-radius: $radius;
}
@mixin border-left-radius($radius) {
border-bottom-left-radius: $radius;
border-top-left-radius: $radius;
}

button-group.scss

源文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
// 按钮组基本样式
.btn-group,
.btn-group-vertical {
//使用relative用于下拉菜单组件(dropdown)的定位
position: relative;
display: inline-block;
vertical-align: middle; //按钮(.btn)与字体对准的hack
> .btn {
position: relative;
float: left;
// 将.active设置z-index前面防止样式重叠
&:hover,
&:focus,
&:active,
&.active {
z-index: 2;
}
&:focus {
// 下拉菜单(dropdown)关闭后移除focus的效果。
outline: 0;
}
}
}
// 按钮相邻时防止双边框(2个border),
.btn-group {
.btn + .btn,
//这是一个自定义设置,官网demo用于有下拉菜单式按钮的按钮组。
.btn + .btn-group,
.btn-group + .btn,
.btn-group + .btn-group {
margin-left: -1px;
}
}
// 可选的:工具栏状态下的按钮组,嵌套在`.btn-group`外。这种样式通常用于菜单栏,一行内多组菜单。
.btn-toolbar {
margin-left: -5px; // 偏移第一个子元素的margin属性
@include clearfix;// 调用clearfix函数,clearfix:清除浮动。
.btn-group,
.input-group {
//看到这里明白为什么官方说btn-toolbar是可选的样式,基本按钮组样式可以实现大部分需求,当文档流的一行存在多个按钮组时使用.btn-toolbar使代码更有可读性,也方便框架统一。不过从css渲染,性能的角度上可以使用更少的代码实现此需求,但这种优化微乎其微。bootstrap真的很赞,适合缺少css架构师的团队使用,方便易读快速成型。
float: left;
}
> .btn,
> .btn-group,
> .input-group {
margin-left: 5px;
}
}
// 初始化所有按钮组内按钮(不包含第一个和最后一个)的边框圆角为0px(按钮样式(.btn)默认初始边框圆角为5px,如果不记得可以看第四篇。)
.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
border-radius: 0;
}
/*
* ①
// 设置按钮组的第一个子元素,右上和右下的边框圆角为0px。因为存在按钮组只有一个按钮的情况,因此同时设置:not(:last-child)属性保证元素的正确匹配。所以这一段可以这么理解:当元素为第一个且不为最后一个,或元素样式不为dropdown-toggle时调用函数border-right/left-radius。不为dropdown-toggle是因为有dropdown-toggle样式的元素必须单独被btn-group裹一层。这是一个不错的css技巧,赶紧get!
.btn-group > .btn:first-child {
margin-left: 0;
&:not(:last-child):not(.dropdown-toggle) {
@include border-right-radius(0);
}
}
.btn-group > .btn:last-child:not(:first-child),
.btn-group > .dropdown-toggle:not(:first-child) {
@include border-left-radius(0);
}
*
*/
// 自定义设置(按钮组嵌套按钮组)
.btn-group > .btn-group {
float: left;
}
.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
border-radius: 0;
}
.btn-group > .btn-group:first-child {
> .btn:last-child,
> .dropdown-toggle {
@include border-right-radius(0);
}
}
.btn-group > .btn-group:last-child > .btn:first-child {
@include border-left-radius(0);
}
// 当按钮选中时,不显示outline,这也是清除了.btn的默认样式。
.btn-group .dropdown-toggle:active,
.btn-group.open .dropdown-toggle {
outline: 0;
}
// 按钮组尺寸
// 按钮组的尺寸样式继承.button.scss里的.btn的尺寸样式,.btn的尺寸详情看第四篇(其实也是调用了button-size方法)这种简写更方便修改。
.btn-group-xs > .btn { @extend .btn-xs; }
.btn-group-sm > .btn { @extend .btn-sm; }
.btn-group-lg > .btn { @extend .btn-lg; }
// 下拉菜单式按钮
// ----------------------
// 要注意的是,官网demo的下拉菜单状态式按钮单独裹一层btn-group。原因我认为一来保持dom结构的整洁,二来在下拉菜单出现时避免错误定位(btn-group有relative属性),如果忽略了这一点,会使标记①处的代码段失效。
//这里重置默认尺寸和最大尺寸的内间距,仅在下拉菜单式按钮中生效,这种间距设计属于boots,至于为啥这么设计,防止<span class="caret"></span>导致内边距加长可能是其中之一的原因,如果去掉这两段间距重置的代码视觉上会有些不对称。
.btn-group > .btn + .dropdown-toggle {
padding-left: 8px;
padding-right: 8px;
}
.btn-group > .btn-lg + .dropdown-toggle {
padding-left: 12px;
padding-right: 12px;
}
// 下拉菜单激活状态
// 调用了box-shadow方法覆盖渐变和阴影样式,统一为当前场景的颜色。
.btn-group.open .dropdown-toggle {
@include box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
// 按钮为链接按钮时调用box-shadow方法达到清除阴影和背景渐变的效果
&.btn-link {
@include box-shadow(none);
}
}
// 调整caret样式位置,官网用词是Reposition caret。
// caret是利用inline-block,boder和transparent实现的倒三角
.btn .caret {
margin-left: 0;
}
// 设置其它按钮尺寸下的caret样式
.btn-lg .caret {
border-width: $caret-width-large $caret-width-large 0;
border-bottom-width: 0;
}
// 颠倒.caret → ▲。官网demo用于向上弹出式菜单
.dropup .btn-lg .caret {
border-width: 0 $caret-width-large $caret-width-large;
}
// 垂直按钮组
// ----------------------
.btn-group-vertical {
> .btn,
> .btn-group,
> .btn-group > .btn {
display: block;
float: none;
width: 100%;
max-width: 100%;
}
// 清除浮动,避免多个下拉菜单错位
> .btn-group {
@include clearfix;
> .btn {
float: none;
}
}
> .btn + .btn,
> .btn + .btn-group,
> .btn-group + .btn,
> .btn-group + .btn-group {
margin-top: -1px;
margin-left: 0;
}
}
// 原理同代码段①
.btn-group-vertical > .btn {
&:not(:first-child):not(:last-child) {
border-radius: 0;
}
&:first-child:not(:last-child) {
border-top-right-radius: $border-radius-base;
@include border-bottom-radius(0);
}
&:last-child:not(:first-child) {
border-bottom-left-radius: $border-radius-base;
@include border-top-radius(0);
}
}
.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
border-radius: 0;
}
.btn-group-vertical > .btn-group:first-child:not(:last-child) {
> .btn:last-child,
> .dropdown-toggle {
@include border-bottom-radius(0);
}
}
.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
@include border-top-radius(0);
}
// 两端对齐按钮组
// ----------------------
.btn-group-justified {
display: table;
width: 100%;
table-layout: fixed;//表格布局:列宽由表格宽度和列宽度设定。
border-collapse: separate;//合并表格边框,使用该属性建议页面规定 !DOCTYPE
> .btn,
> .btn-group {
float: none;
display: table-cell;
width: 1%; // width决定浏览器计算列宽的方式,如想深入了解。详看注②
}
> .btn-group .btn {
width: 100%;
}
> .btn-group .dropdown-menu {
left: auto; // 初始化下拉菜单的定位,其实在.dropdown-menu中left值本来就是0。不过这样可避免.dropdown-menu对left值的修改影响按钮组嵌套下拉菜单按钮组件的定位。
}
}
// 当单复选择按钮遇上下拉菜单
// 此处为了支持浏览器表单验证功能反馈, 由于`display: none;` or `visibility: hidden;`仍然会隐藏菜单的弹出所以不能使用,于是使用了clip,通过剪辑的方式隐藏。同时屏蔽input点击事件,这样一来能确保下拉菜单能正常弹出
// 源代码注释给的相关链接 ↓
// See https://github.com/twbs/bootstrap/pull/12794 and
// https://github.com/twbs/bootstrap/pull/14559 for more information.
[data-toggle="buttons"] {
> .btn,
> .btn-group > .btn {
input[type="radio"],
input[type="checkbox"] {
position: absolute;
clip: rect(0,0,0,0);//w3c:clip属性剪裁绝对定位元素。看示例:注④
pointer-events: none; //元素永远不会成为鼠标事件的target,但是,当其后代元素的pointer-events属性指定其他值时,鼠标事件可以指向后代元素,在这种情况下,鼠标事件将在捕获或冒泡阶触发父元素的事件侦听器。详看注③
}
}
}

相关说明