未知高度容器的多种垂直居中方法
在已知父子高度的情况下, 实现垂直居中是很容易的事. margin , padding,absolute + 负 margin , 甚至于 line-height 都是可行的方案. 这里不再展开, 文章主要来介绍在父容器高度固定, 自容器高度自适应的情况下, 来实现其垂直居中于父级盒子的几种方案. 为了使案例更真实, 我们来模拟一个垂直居中于页面中的弹出层(modal).
先运行下 Demo 过过瘾......
Run 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 法还有一个缺点, 就是当子容器高度超出视窗高度的时候, 它会被直接截断(如下图), 而不是想象中的随着浏览器滚动到顶部而滚动显示完全(模态框的头部被截掉了).
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 来模拟 / 装饰有序清单
待补充
用 table-layout 来控制表格单元格宽度
你也许遇到过给表格设置了宽度, 但是不起作用的问题. 这是因为单元格的宽度是根据其内容进行调整的. 刨根揭底, 是因为表格有个叫做 table-layout 的属性, 其浏览器默认值是 auto 在作怪. 当我们把这个值设置为 fixed 的时候, 我们给 th/td 标签设置的宽度就起作用了. 用法很简单:
- table {
- table-layout: fixed;
- width: 100%;
- }
没有对比就没有伤害
截图是设置 table-layout: fixed; 前后对比图, 左边用蓝色标注的是默认行为的表格, 右边是设置了 table-layout: fixed; 后的样式. 显而易见的, 默认情况下, 单元格宽度受其内容约束. 而设置了 table-layout: fixed; 后, 其单元格宽度变得可控了. 预览 demo
Run demo
用 caret-color 来自定义光标的样式
在文本框中 input/textarea 中如果要改变光标的颜色, 可以通过设置文本的颜色 color:#f00 来搞定. 但是假如我们只想改变光标的颜色, 而不想改变文本的颜色的话, caret-color 属性是一个实现方案. 预览 demo
- input,
- textarea,
- [contenteditable] {
- caret-color: red;
- }
自定义光标颜色
Run demo
用 user-select 来禁用文本选中
在远古时代, 如果你不想让别人选中你页面的内容, JavaScript 是不可或缺的. 而在文明社会中, 只需要一句 user-select:none 的 CSS 样式就可以解决. IE6-9 不支持该属性, 可以通过给 body 添加 onselectstart="return false;" 的内联 JavaScript 语句搞定.
- body{
- user-select: none; // 页面中的文本不能被选中
- }
参考文档
- Centering in the Unknown
- caret-color
年初整理了一批 web 前端教程, 帮助想要成为 Web 前端程序员的人. 从零基础到各种框架的教程都有. 只需要加入到 Web 前端学习 qun:296,212,562. 即可免费领取, 学习过程中有任何问题可以在里面问. 种一颗树最好的时间是十年前, 其次是现在. 只要想学习, 不存在早晚.
来源: http://www.jianshu.com/p/d7bfe6fab242