你不知道的CSS(二)">你不知道的CSS(二)

本文首发于 我的博客

在上文《 你不知道的CSS(一) 》中,介绍了兄弟选择器美化表单, font-size:0 消除间隙, overflow 清除浮动, border 绘制三角形等7个实用技巧。由于文章长度限制,还遗留了一些技巧没有介绍,考虑到日后可能会有更多的技巧需要补充进来,便将上文改名为你不知道的CSS(一),名字其实有点浮夸,希望能完善为一个系列,也希望该系列中介绍的技巧能够帮助到更多人解决实际开发中遇到的问题。在这里感谢SegmentFault的小编在微博上的推荐。本文将 重点介绍CSS中未知高度容器的垂直居中 技巧。同样每个技巧将结合demo或者图示来说明(如果demo无法打开,请自备梯子,原因你懂得:scream_cat:)。

未知高度容器的多种垂直居中方法

在已知父子高度的情况下,实现垂直居中是很容易的事。 marginpaddingabsolute + 负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% ,然后再利用 css3transform: 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浏览器效果太差,差评:disappointed:)。

基于 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; 属性,一切就这么发生了:scream:。

.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

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; //页面中的文本不能被选中
}

参考文档

  • Centering in the Unknown
  • caret-color

本文首发于 我的博客

赞 (0) 评论 分享 ()