CSS Review

Layout & Drawing

浮动 Float

最初引入 float 属性:实现文字环绕和首字下沉。MDN

浮动元素会被移出正常文档流,后续元素会显示在其下层。若不想让剩余元素也受到浮动元素的影响,那么需要清除浮动。

  • 额外标签法 => 浮动元素后添加设置了属性 clear:both; 的空标签

  • 将包裹元素的 overflow 属性设置为除 visible 外的其他值

  • 使用 after 伪元素清除浮动

  • 双伪元素清除浮动 => 无内容;创建块格式化上下文;指定 clear 属性

.clearfix:after,.clearfix:before{ content: ""; display: flex|table|...; }
.clearfix:after{ clear: both; }
.clearfix{ *zoom: 1; }
/* 样式模块 */
.parent{ width: 400px;border: 1px solid #424242; }
.left{ width: 200px;height: 200px;background: #00B26A;float: left; }
.leftt{ width: 120px;height: 120px;background: #06B4FE;float: right; }
.footer{ width: 900px;height: 100px;background: darkslateblue; }
<!-- 模板模块 -->
<div class="parent">
    <div class="left">left</div>
    <div class="leftt">leftt</div>
</div>

额外标签法也称为隔墙法,具体是指在浮动元素的末尾添加一个空标签,并设置上属性 clear:both。不足之处在于引入了无意义的内容。

外层元素通过设置属性 overflow:hidden 产生的 BFC 无法解决需要显示溢出元素的需求。

/* 修改parent样式;此处overflow必须为hidden */
.parent{ width: 400px;border: 1px solid #424242;overflow: hidden; }

属性 overflow:hidden 作用:溢出隐藏、清除浮动、解决外边距塌陷等。

外边距塌陷也称为外边距合并:两个相邻(兄弟或父子关系)的块级元素外边距组合在了一起。只有上下外边距才会有塌陷,左右外边距不会出现这种问题。

.big{ width: 200px;height: 200px;background: #00B26A;overflow: hidden; }
.small{ width: 120px;height: 120px;background: #35393b;margin-top: 30px; }
<div class="big">
    <div class="small"></div>
</div>

after 伪元素方式:语义化较好,符合闭合浮动思想,存在兼容问题,需 zoom:1 触发 hasLayout。

/* 伪元素是行内元素 */
.clearfix:after{ display: block; clear:both; visibility: hidden; content: ""; }
.clearfix{ *zoom: 1; }

BFC

There are different types of formatting contexts. Notable among them are Block Formatting Context, Inline Formatting Context, Flex Formatting Context & Grid Formatting Context.

块格式化上下文是一个独立的渲染区域,该区域容器里的子元素不会在布局上影响外部的元素。

block-level boxes 和 blocks containing boxes 的交集在广义上称为 block boxes。

可通过设置部分属性在 box 内部创造一个 formatting context 的环境给后代元素。

布局规则:

  • 内部 box 在垂直方向逐个排列
  • box 垂直方向的距离由 margin 决定
  • 同属一个 BFC 的两个相邻 box 的 margin 会发生重叠,即使存在浮动
  • BFC 区域不会与 float box 重叠
  • 浮动元素的高度参与 BFC 的高度计算

触发条件:

  • 根元素 <html>
  • float 值非 none
  • overflow 值非 visible
  • display 取值 table、grid、flex,inline-...、table-...
  • position 取值 absolute、fixed
  • ...

作用场景:

  • 清除浮动
  • 解决因非 BFC 容器却包含了浮动元素所导致的高度塌陷
  • 自适应两栏布局:一边定宽 float,一边适应 overflow(产生 BFC)
  • 阻止外边距重叠:添加空内容且产生 BFC 的伪元素
/* 同时解决高度塌陷和外边距重叠 */
.clearfix::before, .clearfix::after{
  content: "";
  display: table;
  clear: both;
}

水平垂直居中

水平居中可选策略:

  • margin: 0 auto:通过 auto 自动占用可用空间
  • text-align: center:指定元素中的文本以何种方式开展水平对齐

垂直居中可选策略:

  • 当内外元素的宽高已知时,可直接计算 margin
  • relative 与 absolute 定位配合 margin: auto
*{ padding: 0;margin: 0; }
.box{ width: 300px; height: 300px; border: 3px solid #4e4e4e; position: relative; }
img{ width: 100px; height: 100px; position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; }
  • relative 与 absolute 定位配合 transfrom: translate(-50%,-50%)
*{ padding: 0;margin: 0; }
.box{ width: 300px; height: 300px; border: 3px solid #4e4e4e; position: relative; }
img{ width: 100px; height: 100px; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); }
  • 外层元素进行 flex 布局
*{ padding: 0;margin: 0; }
.box{ width: 300px; height: 300px; border: 3px solid #4e4e4e; display: flex; justify-content: center; align-items: center; }
img{ width: 100px; height: 100px; }
.supContainer{ display: flex }
.subContainer{ margin: auto auto auto auto; }
  • 内层元素 margin 设置为 calc(50% - 内层元素宽/2) auto
*{ padding: 0;margin: 0; }
.box{ width: 300px; height: 300px; border: 3px solid #4e4e4e;}
.box div { height: 100px; width: 100px; background-color: red; margin: calc(50% - 50px) auto }

Animation

  • animation

animation 是一个简写属性形式,由 animation-name,animation-duration,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,animation-fill-mode 和 animation-play-state 组成。

animation-name 指定应用的系列动画,每个名称代表一个由 @keyframes 定义的动画序列。

animation-duration 属性指定元素上的动画从开始到结束耗费时长。

animation-iteration-count 用以指定动画重复的次数,仅仅使用该属性就能使动画重复播放。在该例中,设该属性为 infinite 以使动画无限重复。

animation-timing-function 属性是动画的速度函数。这个属性使用贝塞尔曲线(Cubic Bezier)函数来生成或直接使用 ease、ease-in、ease-out 或 linear。

animation-direction 属性为 alternate 设置来回滑动。

  • 通过 animation 实现一个圆弧运动的球体

CSS3 的 transfrom 过渡效果可以实现元素位移、旋转、缩放。结合 animation 属性,就可以实现元素的动画效果。

球体运动可拆分成 X 和 Y 轴两个运动,X 轴将以慢 —> 快这样的速度运动;而 Y 轴的方向是以快 —> 慢这样的速度运动(从斜率方面思考);结合两个轴的运动,实现弧线效果。

.box {
  width: 400px;
  height: 400px;
  border: 5px solid #262626;
}
aside {
  width: 20px;
  height: 20px;
  border: 1px solid #222;
  animation: arc1 5s ease-in forwards;
}
/* 这个虚拟元素默认是行内元素 */
aside::after {
  content: "";
  display: block;
  width: 20px;
  height: 20px;
  -webkit-border-radius: 20px;
  -moz-border-radius: 20px;
  border-radius: 20px;
  background: #424242;
  animation: arc2 5s ease-out forwards;
}
@keyframes arc1 {
  to {
    transform: translateX(380px);
  }
}
@keyframes arc2 {
  to {
    transform: translateY(380px);
  }
}
<div class="box">
  <aside></aside>
</div>

常见绘制

半圆弧绘制 => 使用复合属性 border-radius:

width: 160px;
height: 80px;
background-color: transparent;
border-bottom-right-radius: 90px;
border-bottom-left-radius: 90px; /*增加了边框,圆角半径也要变化*/
border-left: 10px solid black; /*边框左边线*/
border-right: 10px solid black; /*边框右边线*/
border-bottom: 10px solid black; /*边框底边线*/

三角形绘制 => 宽高为零,三边透明:

width: 0;
height: 0;
border-left:100px solid transparent;  
border-top:80px solid transparent;  
border-right:40px solid transparent;  
border-bottom:70px solid #424242;

圣杯布局(左右宽度固定,中间自适应且优先加载):

* { margin: 0; padding: 0; }
html, body { height: 100%; width: 100%; }
header { width: 100%; background-color: #06b4fe; }
/* 清除浮动塌陷 */
footer { width: 100%; background-color: #ff6c37; clear: both; }
.center, .left, .right { float: left; }
.wrapper { padding: 0 100px; }
.center { width: 100%; height: 100px; background-color: lightblue; }
.left { width: 100px; height: 100px; background-color: lightgreen; margin-left: -100%; position: relative; left: -100px; }
.right { width: 100px; height: 100px; background-color: yellow; margin-left: -100px; position: relative; right: -100px; }
<header>header</header>
<!-- 优先加载 -->
<div class="wrapper">
  <div class="center">center</div>
  <div class="left">left</div>
  <div class="right">right</div>
</div>
<footer>footer</footer>

双飞翼布局(可看作圣杯布局的优化版):

.main { width: 100%; float: left; }
.middle { background-color: lightblue; margin: 0 100px; }
.leftt { width: 100px; background-color: lightgreen; float: left; margin-left: -100%; }
.rightt { width: 100px; background-color: yellow; float: left; margin-left: -100px; }
.footer { clear: both; }
<div class="header">header</div>
  <div class="main">
    <div class="middle">middle</div>
  </div>
<div class="leftt">leftt</div>
<div class="rightt">rightt</div>
<div class="footer">footer</div>

块内显示一行,超出显示省略号 & 块内显示两行或三行,超出显示省路号:

overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;

0.5px 边框常有单线和全框两种形式:

  • border + border-image + linear-gradient
  • 伪元素 + background-image
  • 定位 + 伪元素 + transform:scale

auto

auto 的效果可区分为两种,自动占用可用空间或直接设置 0 px。

对于前者,通常用于实现水平居中的效果,但若使用不当则会出现与预期存在差异的情况。

/* 水平居中 */
margin: auto;
/* 左或右边距单独设置 auto 会导致该边距占据所有可用空间 => 使元素视觉向反方向偏移 */
margin-right: auto;

auto 在浮动,内联和绝对元素中不起作用,因为这些元素已经确定了布局。对应浮动和绝对定位,由于脱离标准文档流,而 auto 是针对文档流的元素,那么自然会失效;内联会导致元素因无法设置宽高,而 auto 无法自动占用空间而失效。

对于后者的情况,块元素的宽度通常占据其整个容器,那么 margin:auto 将被设置为 0px。此外,auto 在顶部和底部边距中总是计算为 0px,这也是 w3c 规范导致 auto 仅常见于实现水平居中而不用于垂直居中的原因。

当然,也会存在一定程度上受制于垂直页面流。页面大小总在高度方面增加,相对于页面本身而言,元素垂直居中于其容器并不一定会使其显示恒为居中。

Reflow & Repaint

回流必引起重绘,重绘不一定回流。点此

文档流即是浏览器采用的流式布局 Flow Based Layout。

在 RenderTree 生成前,需先构建文档对象模型 DOM 和 CSS 对象模型 CSSOM。

重排|回流 Reflow

渲染树中元素尺寸、结构、属性的几何信息发生改变,导致浏览器重新渲染部分或全部文档。

触发重排|回流 => 视窗改变与首次渲染;添加删除和更新节点;display 属性的变更;伪类的激活与移除;查询属性和计算方法。

重绘 Repaint

页面中元素样式改变而不影响在文档流中的位置和布局时,浏览器会重新绘制此元素的外观样式。

  • visibility:hidden; (仅隐藏内容,并未脱离文档流,继续占据页面的空间)
  • color、background-color:...; (仅颜色改变)

优化与避免

尽可能的将可能引起回流和重绘的操作放入特定队列,进行批量处理。具体实现可以考虑当任务数量或时间间隔达到指定阈值时,浏览器将队列清空,进行批处理。

样式上应尽量避免页面整体使用老旧的表格布局,以及多层内联的样式设置,和样式计算表达式。

脚本方面要避免频繁的操作样式,应批量重写 style 属性,或者将样式定义为 class 进行整体更改。也可考虑开辟 DocumentFragment 再添加于文档中。

<ul id="list"></ul>
var list = document.querySelector('#list')
var fruits = ['Apple', 'Orange', 'Banana', 'Melon']
var fragment = new DocumentFragment()
fruits.forEach(function (fruit) {
  var li = document.createElement('li')
  li.innerHTML = fruit
  fragment.appendChild(li)
})
list.appendChild(fragment)
// Apple
// Orange
// Banana
// Melon
  1. 会引起元素或周围的元素位置变化则 reflow,如窗口、字体大小、元素位置改变...;不会引起位置变化,仅存在变色效果则 repaint。
  2. 回流性能消耗较重绘要高,因回流的影响也会冒泡作用于周边及父元素。
  3. display:none;因不占据物理空间,因此涉及了dom树的操作,所以会引起重绘和回流;visibility:hiden; 元素虽然不可见但是却占据物理空间,因此不影响dom树的改变,所以只会引起回流。

秋豪之末

使用空格分隔的类选择器是后代选择器,表示选择具有该类的元素及其后代元素;而无空格分隔的类选择器是并列选择器,要求在同一元素上同时具有这两个类才会生效。

7.5pt 即 10px,即 0.625em,通常会将浏览器的根元素 HTML 标签(<html>)的字体大小(font-size)设置为 62.5% 或 10px。在 CSS2.1 中,rem 的大小取决根元素的字体大小。如果同时在 <body><html> 元素上设置了 font-sizerem 单位将参考 <html> 元素上的值。

结束

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议,转载请注明出处!