本文首发于我的博客
在上文《你不知道的CSS(一)》中,介绍了兄弟选择器美化表单,font-size:0
消除间隙,overflow
清除浮动,border
绘制三角形等7个实用技巧。由于文章长度限制,还遗留了一些技巧没有介绍,考虑到日后可能会有更多的技巧需要补充进来,便将上文改名为你不知道的CSS(一),名字其实有点浮夸,希望能完善为一个系列,也希望该系列中介绍的技巧能够帮助到更多人解决实际开发中遇到的问题。在这里感谢SegmentFault的小编在微博上的推荐。本文将重点介绍CSS中未知高度容器的垂直居中技巧。同样每个技巧将结合demo或者图示来说明(如果demo无法打开,请自备梯子,原因你懂得?)。
未知高度容器的多种垂直居中方法
在已知父子高度的情况下,实现垂直居中是很容易的事。margin
, padding
,absolute + 负margin
, 甚至于 line-height
都是可行的方案。这里不再展开,文章主要来介绍在父容器高度固定,自容器高度自适应的情况下,来实现其垂直居中于父级盒子的几种方案。为了使案例更真实,我们来模拟一个垂直居中于页面中的弹出层(modal
)。
先运行下Demo 过过瘾?……
定义如下模态框的基本样式(部分样式使用bootstrap
)
.vh-modal {
height: 640px;
border: 1px solid #ccc;
position: relative;
.vh-modal-content {
min-width: 50%;
max-width: 80%;
background: #fff;
border: 1px solid rgba(0, 0, 0, .2);
box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
}
.vh-modal-title {
padding: 20px;
font-size: 20px;
border-bottom: 1px solid #ccc;
text-align: left;
margin: 0;
}
.vh-modal-body {
padding: 20px;
text-align: left;
}
.vh-modal-foot {
text-align: right;
padding: 20px;
border-top: 1px solid #ccc;
}
}
(伪)元素占位方案 推荐
利用(伪)元素和display:inline-block
的方案来实现垂直居中是我个人常用的也是推荐大家使用的方法。
.vh-modal-1 {
text-align: center; //水平居中
font-size: 0; //消除空隙, 见 https://smohan.net/blog/6gr77h
&::before,
>.vh-modal-content {
display: inline-block;
vertical-align: middle;
font-size: 14px;
}
&::before {
content: '';
height: 100%;
}
}
<div class="vh-modal vh-modal-1">
<div class="vh-modal-content">
<h3 class="vh-modal-title">模态框</h3>
<div class="vh-modal-body">...</div>
<div class="vh-modal-foot">
<button class="btn btn-primary">确定</button>
</div>
</div>
</div>
如上图中的::before
你也可以使用一个真实的元素代替。
absolute + transform方案
使用absolute
绝对定位子元素,并且设置其top:50%; left:50%
,然后再利用css3
的transform: translate(-50%, -50%);
设置负值偏移回来也是一种有效的垂直居中方案,但要注意其兼容性以及不要将子容器置于父容器半个像素的位置上(如500.5px),否则子容器会出现模糊。
.vh-modal-2 {
>.vh-modal-content {
//尽可能的不要让该元素的宽度或者高度出现奇数,否则可能会导致模糊
display: inline-block; //为了自适应宽度,可以固定宽度
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
transform
法还有一个缺点,就是当子容器高度超出视窗高度的时候,它会被直接截断(如下图),而不是想象中的随着浏览器滚动到顶部而滚动显示完全(模态框的头部被截掉了)。
table-cell方案
使用div来模拟table
的行为也可以实现垂直居中。缺点是要在子容器外层再包裹一个父元素vh-modal-cell
用来模拟table-cell
。
.vh-modal-3 {
display: table;
width: 100%;
.vh-modal-cell {
display: table-cell;
vertical-align: middle;
text-align: center;
}
.vh-modal-content {
display: inline-block;
}
}
<div class="vh-modal vh-modal-3">
<div class="vh-modal-cell">
<div class="vh-modal-content">
...
</div>
</div>
</div>
<!--
模拟了table布局
<table style="width: 100%;">
<tr>
<td style="text-align: center; vertical-align: middle;">
类似于直接使用table布局
</td>
</tr>
</table>
-->
基于flex的方案 强烈推荐
毫无疑问,flex
盒模型是最佳的实践方案。目前几乎所有现代浏览器都支持flex
布局,尤其是移动端(部分机型UC浏览器效果太差,差评?)。
基于flex
盒模型的水平垂直居中有如下两种方案:
<div class="vh-modal vh-modal-4(5)">
<div class="vh-modal-content">
...
</div>
</div>
align-items & justify-content方案
.vh-modal-4 {
display: flex;
align-items: center;
justify-content: center;
>.vh-modal-content {}
}
flex + margin方案
这个方案是最神奇的,仅仅给子元素设置了margin:auto;
属性,一切就这么发生了?。
.vh-modal-5 {
display: flex;
margin: 0;
>.vh-modal-content {
margin: auto;
}
}
用counter
来模拟/装饰有序清单
就如截图中圈出的那样,类似这种多层级的数字,我们大概第一反应是使用JavaScript
循环列表,利用其index
拼接而成的。事实上,仅仅使用css的counter
属性也可以实现该功能,甚至实现起来更高效。博客的【热门文章】栏目的索引就是使用counter
属性实现的。
ol {
counter-reset: decimal;
list-style-type: none; //去掉默认的list-style
li {
&::before {
counter-increment: decimal;
content: counters(decimal, '.') ' ';
}
}
}
就像图上那样,我们很早就已经将counter
属性用在真实项目中了,而这仅仅只是counter
属性一个简单的使用场景,它甚至可以帮助你完成一个简单的购物车计费场景(如图,当然,真实项目中没有人这么干)。
CSS计数器是CSS2.1中自动计数编号部分的实现。作为由CSS维护的变量
,counter
属性还有很多有趣的使用场景,具体就不展开了。请参考MDN上的使用CSS计数器章节。
用table-layout
来控制表格单元格宽度
你也许遇到过给表格设置了宽度,但是不起作用的问题。这是因为单元格的宽度是根据其内容进行调整的。刨根揭底,是因为表格有个叫做table-layout
的属性,其浏览器默认值是auto
在作怪。当我们把这个值设置为fixed
的时候,我们给th/td
标签设置的宽度就起作用了。用法很简单:
table {
table-layout: fixed;
width: 100%;
}
截图是设置table-layout: fixed;
前后对比图,左边用蓝色标注的是默认行为的表格,右边是设置了table-layout: fixed;
后的样式。显而易见的,默认情况下,单元格宽度受其内容约束。而设置了table-layout: fixed;
后,其单元格宽度变得可控了。预览demo
用caret-color
来自定义光标的样式
在文本框中input/textarea
中如果要改变光标的颜色,可以通过设置文本的颜色color:#f00
来搞定。但是假如我们只想改变光标的颜色,而不想改变文本的颜色的话,caret-color
属性是一个实现方案。预览demo
input,
textarea,
[contenteditable] {
caret-color: red;
}
用user-select
来禁用文本选中
在远古时代,如果你不想让别人选中你页面的内容,JavaScript
是不可或缺的。而在文明社会中,只需要一句user-select:none
的CSS样式就可以解决。IE6-9不支持
该属性,可以通过给body
添加 onselectstart="return false;"
的内联JavaScript
语句搞定。
body{
user-select: none; //页面中的文本不能被选中
}
参考文档
本文首发于我的博客
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。