每一帧耗时
1. 为了视觉上连贯,浏览器对每一帧画面的所有工作需要在16ms(1000ms / 60f ~= 16.66ms/f)内完成。 2. 渲染画面时,浏览器需要进行一些流程工作:渲染队列的管理、渲染线程与其他线程之间的切换等。因此一帧中花费在像素渲染管道(JS -> Style -> render tree)的时间要控制在10至12ms内,再余出4至6ms进行流程工作。 3. 一帧画面理想的耗时组合为:`16ms = 3~4ms的JS代码 + 7~8ms的渲染工作 + 4~6ms的流程工作`。
像素渲染管道:
CSS/JS
-> Style(计算样式)
» Render Tree(渲染树)
:Layout(布局)
-> Paint(绘制)
-> Composite(渲染层合并)
Render Tree:改变前一个步骤需要后一个步骤也做出处理,所以若能够仅处理越后面的步骤,对性能耗费越少。
CSS/JS
:
使用CSS(动画:animation-@keyframes
、transition
)或JS或Web Animation API,实现视觉变化效果。
JS动画(命令式)比CSS动画(说明式)消耗多一些资源,浏览器会对CSS动画自动进行优化。
CSS的
animation
相关事件:
animationstart
、animationend
、animationcancel
、animationiteration
CSS的
transition
相关事件:transitionend
动画其实就是按某种顺序、平滑地修改样式:如:颜色、大小、间距、
transform
等。
Style
:
根据CSS选择器,生成完整的CSSOM。
Layout
:
具体计算每个节点最终在屏幕上显示的大小和位置。
Paint
:
耗费性能最大的工作。
填充像素的过程。包括绘制文字、颜色、图像、边框、阴影等,也就是DOM所有的可视效果。一般来说,这个绘制过程是在多个层(composite layers)上完成。
Composite
:
在每个层(composite layers)上完成绘制过程后,浏览器会将所有层按照合理的顺序合并成一个图层再显示。
第一次确定节点的大小和位置是
Layout
,随后对节点大小和位置的重新计算是reflow
。同理Paint
与repaint
。
reflow
、repaint
:
CSS属性触发reflow、repaint、composite的情况:CSS Triggers。
reflow
(重排):
某个元素上执行动画时,浏览器需要每一帧都检测是否有元素受到影响,并调整它们的大小、位置,通常这种调整都是联动的。
repaint
(重绘):
浏览器还需要监听元素的外观变化,通常是背景色、阴影、边框等可视元素,并进行repaint。
composite
:
每次reflow、repaint后浏览器还需要层合并再输出到屏幕上。
那些容易忽略的能引起布局改变的样式修改,它们可能不产生动画,但当浏览器需要重新进行样式的计算和布局时,依然会产生reflow和repaint。
创建composite layers(层、渲染层、复合层),交由GPU处理(CPU不再处理):
GPU(图形处理器)是与处理和绘制图形相关的硬件,专为执行复杂的数学和几何计算而设计的,可以让CPU从图形处理的任务中解放出来,从而执行其他更多的系统任务。
强制普通元素提升到单独层的方法:
will-change: ;
(现代浏览器,最佳方式)。transform: translateZ(0);
(hack方式)。有些情况无法互相替代。
自带单独层的元素:
<video>
元素。<canvas>
元素。其他提升至单独层的方法:
transform 3D
或perspective
。z-index
比较小,则这个元素(不管是不是应用了硬件加速样式)也会被放到层中。opacity
做CSS动画或使用一个动画变换的元素。有时,虽然提升元素,却仍需要repaint。
动画性能最好、消耗最低的属性(必须自身元素已提升至单独层):
对于以下属性修改,若元素自身被提升至单独层,则仅触发composite,否则触发paint -> composite。
transform: translate(xpx, ypx);
transform: scale(x, y);
transform: rotate(xdeg);
transform: skew(xdeg,ydeg);
opacity: x;
渲染性能优化方法:
参考:渲染性能。
优化JS的执行效率
requestAnimationFrame
(或velocity动画库),避免使用Web Worker
中去做。缩小样式计算的范围和降低复杂度
降低样式选择器的复杂度、提升选择器性能。
可以使用基于class的方式,如:BEM
1. `block-name__element-name--modifier-name--modifier-val`([getbem.com](http://getbem.com/naming/)) 2. `block-name__element-name_modifier-name_modifier-val`([en.bem.info](https://en.bem.info/methodology/naming-convention/))
减少需要执行样式计算的元素的个数(随着元素递增而计算量线性递增)。
避免大规模、复杂的layout与reflow
避免强制同步布局
强制同步布局(forced synchronous layouts):使用JS强制浏览器提前执行layout。
实行先读后写原则:先批量读取元素样式属性(返回上一帧的值),再对样式属性、类名等进行写操作。
e.g.
```javascript /* bad:强制同步布局,可能产生布局抖动 */ dom.forEach(function (elem) { if (window.scrollY < 200) { // 计算读取layout elem.style.opacity = 0.5; // JS写入样式 } }); /* good:先读后写 */ if (window.scrollY < 200) { // 计算读取layout /* 批量JS写入样式 */ dom.forEach(function (elem) { elem.style.opacity = 0.5; }); } ```
避免布局抖动
布局抖动(layout thrashing):快速多次进行强制同步布局。
display: none;
再操作样式,操作完毕后恢复复显示。position: absollute/fixed;
的元素reflow开销较小。flex
布局(对于相同数量的元素、视觉外观,flex布局的时间更少)。简化绘制的复杂度、减小绘制区域
合理划分层,动静分离,可避免大面积重绘。
优先使用层(composite layers)来统一操作动画,并控制层数量
若元素仅改变composite,则将其提升至单独的层。
transform/opacity
来实现动画效果。will-change/translateZ
属性把动画元素提升到单独的层中。使用3D硬件加速提升动画性能时,最好给元素增加一个z-index
属性(改变层叠上下文的顺序),人为干扰层排序,可以有效减少Chrome创建不必要的层,提升渲染性能。
若有一个元素,它的兄弟元素在层中渲染,而这个兄弟元素的
z-index
比较小,则这个元素(不管是不是应用了硬件加速样式)也会被放到层中。
对用户输入、滚动事件进行函数防抖处理
滚动会触发高频率重新渲染,scroll事件的处理函数也会被高频率触发。
requestAnimationFrame
回调函数中修改样式属性。经验:
低性能设备(Android)优先调试。
-webkit-
等)、层叠关系(z-index
),并且要更注意渲染性能(层产生)。transform: translate
进行非整数平移时,会产生模糊(注意百分比可能会计算成非整数)。因为某些原因(参考:[如何在 Windows 上享受更棒的字体渲染 | 实用技巧](https://sspai.com/post/52557)),微软雅黑 等字体在Windows进行Hint处理会导致模糊、笔画高低不平。 |
前端解决方案(避免Hint导致以上问题):替换字体、提升font-size
、去除粗体。如:微软雅黑,≥17px的粗体,≥14的非粗体。
Hint:Windows对于低分辨率屏幕下字体显示进行的特殊处理,当屏幕分辨率过低或字太小不足以显示所有文字细节时,Windows会启动Hint让文字变得更清晰。
每个字体本身会带有一个GASP表,Windows的渲染引擎会根据这些GASP表来判断是否需要做处理。然而如果字体的GASP表不完善,就会让Hint误操作。
水平居中
内容宽度确定
.son {
width: 宽度;
margin: 0 auto;
}
内容宽度不确定
父级display: flex; justify-content: center;
;或父级display: flex;
,单子级margin: 0 auto;
。
兼容ie11+。
.father {
display: flex;
justify-content: center;
}
/* 或 */
.father {
display: flex;
.son { /* 单子级的margin左右占满父级 */
margin: 0 auto;
}
}
子级display: table; margin: 0 auto;
。
兼容ie8+。
.son {
display: table;
margin: 0 auto;
}
父级position: relative;
,子级position: absolute; left: 50%; transform: translateX(-50%);
。
兼容ie9+。
.father {
position: relative;
.son {
position: absolute;
left: 50%;
transform: translateX(-50%);
-ms-transform: translateX(-50%);
}
}
父级text-align: center;
,子级display: inline-block;
。
.father {
text-align: center;
font-size: 0;
.son {
display: inline-block;
*display: inline;
*zoom: 1;
font-size: ;
}
}
垂直居中
内容高度确定
父级position: relative;
,子级position: absolute; top: 50%; margin-top: 负一半高度;
。
内容高度不确定
父级display: flex; align-items: center;
。
兼容ie11+。
.father {
display: flex;
align-items: center;
}
父级display: table-cell; vertical-align: middle;
,子级display: inline-block;
。
.father { /* (为兼容低版本ie)不能是float或absolute,可以在外嵌套float或absolute */
display: table-cell;
vertical-align: middle;
/* ie6/7需要:height/font-size = 1.14 */
*height: 114px;
*font-size: 100px;
.son { /* (为兼容低版本ie)必须是行内元素 */
display: inline-block;
*display: inline;
*zoom: 1;
/*vertical-align: middle;*/
}
}
父级position: relative;
,子级position: absolute; top: 50%; transform: translateY(-50%);
。
兼容ie9+。
.father {
position: relative;
.son {
position: absolute;
top: 50%;
transform: translateY(-50%);
-ms-transform: translateY(-50%);
}
}
辅助参考元素display: inline-block; vertical-align: middle; height: 100%;
,子级display: inline-block; vertical-align: middle;
。
伪元素:
兼容ie8+。
.father {
font-size: 0;
&:before {
content: "";
display: inline-block;
vertical-align: middle;
height: 100%;
}
.son {
display: inline-block;
vertical-align: middle;
font-size: ;
}
}
额外元素:
<style>
.father {
font-size: 0;
}
span {
display: inline-block;
*display: inline;
*zoom: 1;
vertical-align: middle;
height: 100%;
}
.son {
display: inline-block;
*display: inline;
*zoom: 1;
vertical-align: middle;
font-size: ;
}
</style>
<div class="father">
<span></span>
<div class="son"></div>
</div>
水平、垂直居中
内容高度、宽度确定
父级position: relative;
,子级position: absolute; top: 50%; left: 50%; margin-top: 负一半高度; margin-left: 负一半宽度;
。
内容高度、宽度不确定
父级display: table-cell; text-align: center; vertical-align: middle;
,子级display: inline-block;
。
.father {
display: table-cell;
text-align: center;
vertical-align: middle;
/* ie6/7需要:height/font-size = 1.14 */
*height: 114px;
*font-size: 100px;
.son {
display: inline-block;
*display: inline;
*zoom: 1;
/*vertical-align: middle;*/
}
}
父级position: relative;
,子级position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
。
兼容ie9+。
.father {
position: relative;
.son {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
}
}
父级display: flex; justify-content: center; align-items: center;
。
兼容ie11+。
.father {
display: flex;
justify-content: center;
align-items: center;
}
flex
实现float
float
节点:可以填补在之后节点的水平margin
内(padding
内不可以);不可以填补在之前节点的水平margin
内。
中间内容自适应,两边固定(中间内容最后加载)
<style type="text/css">
.float-l {
float: left;
_display: inline;
width: 左边块宽度;
}
.float-r {
float: right;
_display: inline;
width: 右边块宽度;
}
.middle {
margin-left: 大于等于左边块宽度;
margin-right: 大于等于右边块宽度;
}
</style>
<div class="clearfix">
<div class="float-l">左边内容</div>
<div class="float-r">右边内容</div>
<div class="middle">中间内容</div>
</div>
- DOM结构不能颠倒,需要中间结构放最后;
- 节点上能设定
clear: both;
。
中间内容自适应,两边固定(中间内容最先加载)
所谓的「双飞翼布局」。
<style type="text/css">
.main-out,
.float-l,
.float-r {
float: left;
_display: inline;
}
.middle-out {
width: 100%;
}
.middle-in {
margin: 0 大于等于右边块宽度 0 大于等于左边块宽度;
}
.float-l {
width: 左边块宽度;
margin-left: -100%;
}
.float-r {
width: 右边块宽度;
margin-left: -左边块宽度;
}
</style>
<div class="clearfix">
<div class="middle-out">
<div class="middle-in">
中间内容
</div>
</div>
<div class="float-l">左边内容</div>
<div class="float-r">右边内容</div>
</div>
- DOM结构不能颠倒,需要中间结构放最前;
- 节点上能设定
clear: both;
。
中间与两边内容都自适应
<style type="text/css">
.float-l {
float: left;
_display: inline;
}
.float-r {
float: right;
_display: inline;
}
.middle {
display: table-cell;
*display: inline-block;
width: 9999px;
*width: auto;
}
</style>
<div class="clearfix">
<div class="float-l">左边内容</div>
<div class="float-r">右边内容(没有足够空间则整体换行)</div>
<div class="middle">中间内容(没有足够空间则整体换行)</div>
</div>
- DOM结构不能颠倒,需要中间结构放最后;
- 节点上能设定
clear: both;
;- 完全由内容决定布局;
- 第一块内容要给第二块内容留下足够空间,否则第二块放不下会整个换行;第一块+第二块要给第三块留下足够空间,否则第三块放不下会整个换行。
flex
优雅解决布局、自适应问题命名间隔
-
短横线隔开式(kebab-case)、小驼峰式(camelCase)、大驼峰式(PascalCase)、_
。
-
。_
。-
。JS相关:
.vue组件文件:大驼峰式或-
(且需要2个以上单词)。
页面文件(如:nuxt的pages):按照路由访问命名(习惯用
-
)。
大小写
CSS属性名和属性值:不区分大小写。
content
的属性值区分大小写。font-family
的属性值不区分大小写。
CSS选择器:
类选择器
、ID选择器
、自定义属性的属性选择器的属性值
区分大小写。HTML标签的属性名和属性值:
属性名不区分大小写;
自定义属性的属性名也不区分大小写。
class
、id
、value
、自定义属性
等的属性值区分大小写。JS相关:
attribute
不区分大小写(.attributes
、.getAttribute/setAttribute/removeAttribute/hasAttribute/toggleAttribute
)property
的属性名是固定的,不因为attributes
而改变。引号使用
HTML标签的attribute
的值、CSS样式属性的值(如:content
、font-family
、quotes
):
除了有空格之外,都允许不加引号。建议:HTML标签的
attribute
的值都添加,CSS样式属性的值都不添加。
双引号"
JS代码的字符串:
单引号'
CSS命名规范
BEM(以及变种)
block-name__element-name--modifier-name--modifier-val
is-状态
--modifier
:仅包括多种外观的不同样式,如:size、type、color、font。is-状态
:仅包括JS控制状态显示的不同样式,如:active、disabled、show。
j-
:仅给JS使用的选择器,意味着不会有样式添加到这个选择器上。其他CSS模块化理论:OOCSS、SMACSS。
</details>
经验
(标签)语义化:让机器可以读懂内容
先用纯HTML标签语义化结构,再加入CSS满足样式,最后加入交互。
<a>
不嵌套<div>
)。CSS编码规范
绝大部分同意fex-team:tyleguide。
可以设置为IDEs的Reformat Code的排版样式。
CSS注释方式
除了普通注释之外,还可以把注释内容放在根元素的伪元素中:
:root:before {
content: "author: 重构; design: 设计师; update: 更新时间;";
display: none;
}
<a>
的属性target="_blank"
,在一些浏览器中,无论href
值是什么内容(包括#
和javascript:
)都会打开新页面。在拥有target="_blank"
的<a>
中添加rel="noopener"
或rel="noreferrer"
。
没有
target="_blank"
属性的新打开的页面和原页面不存在关系。
没有添加额外的rel
属性的开启新窗口:
window.opener
访问原窗口对象,并使用window.opener.location
改变原页面导航。Chrome任务管理器展示:
![Chrome任务管理器图](/knowledge/%E7%BD%91%E7%AB%99%E5%89%8D%E7%AB%AF/HTML+CSS%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/images/chrome-task-1.png)target="_blank"
但未设置rel
添加额外的rel
属性:
rel="noopener"
的新窗口:
与原页面不在同一个进程、且window.opener
返回null
。
window.open(地址, '_blank', 'noopener')
。rel="noreferrer"
(不限于target="_blank"
):
包含
rel="noopener"
。
(不在一个进程、且window.opener
返回null
,)http请求不发送Referer
(document.referrer
返回''
)。
window.open(地址, '_blank', 'noreferrer')
。(SEO)对不想宣传的链接,在<a>
中添加rel="nofollow"
。
告诉搜索引擎「不要跟踪此网页上的链接」或「不要跟踪此特定链接」
1. 可以用于阻止在PR值高的网站上以留言等方式添加链接从而提高自身网站排名的行为,以改善搜索结果的质量,防止垃圾链接的蔓延。 2. 网站站长也可对其网页中的付费链接使用nofollow来防止该链接降低搜索排名。 3. 对一些重要度低的网页内容使用nofollow,还可以使搜索引擎以不同的优先级别来抓取网页内容。
没有设置宽度的float
元素,其宽度等于子节点宽度:
inline
、inline-block
的元素前可能有空隙(其实是行内标签前面的空白符,若拥有font-size
之后便会有高宽),通过以下办法解决:
inline
、inline-block
节点设置为block
。font-size: 0;
(可用此方法排查是否是空格造成的)。页面是按照顺序加载资源,当且仅当有使用需求时才会去加载外部资源。
已加载完成的CSS文件内有多个URL请求(background
),但仅在页面节点要引用某个URL请求时(无论节点是否隐藏),才会去请求这个资源,而不是在加载CSS文件时就加载外部资源。可以用于监控用户行为(当用户某些操作导致展示背景时加载外部资源——外部资源可以是上报接口)。
使用动态DOM加载,代替内容的display: none;
(免去构建复杂的DOM):
<script type="text/template"></script>
<template></template>
<textarea style="display:none;"></textarea>
:before/after
的就不要添加标签(但是不要在content
里加业务文字)。单选<input type="radio">
、多选<input type="checkbox">
按钮开关自定义样式:
用input:checked + 兄弟节点
操作选项选中与否的不同样式;可以隐藏<input>
,点击在<label>
上改变<input>
的:checked
状态(<label>
的for
绑定<input>
的id
),用自定义样式来制作单选框、复选框。避免使用JS。
输入框仅输入数字的:
<input type="number" pattern="[0-9]*" onchange="处理函数">
<datalist>
为<input>
的输入值添加建议(<input>
的list
绑定<datalist>
的id
)
position: relative;
(类似ie6的haslayout)。避免:
超出内容区域的内容:
用绝对定位把内容设置在外部
不要把超出内容区域的绝对定位设置在<body>
直接子级,而是设置在<body>
下拥有overflow: hidden;
的父级下。
大背景模式
CSS.supports(CSS语句)
或CSS.supports(CSS属性, 值)
判断浏览器是否支持一个给定CSS语句。
CSS.supports('--变量名', '非空任意值')
可判断是否支持CSS变量。
<img>
外嵌套一层标签,好应对可能要在图片上添加东西的需求。没有 背景内容(透明背景无效、局部背景只能在有背景处有效)、或文本、或其他内容(如:<img>
、<iframe>
等) 承载的节点无法触发鼠标事件。
RN的实现可能也会有这种效果。
可以在全区域添加背景使鼠标事件有效。
background: rgba(0, 0, 0, .002)
(小于0.002
的透明度无效)。background: url(1x1像素透明图地址) repeat;
。content
不要放业务逻辑耦合的内容(如:楼主
等业务逻辑词汇),可以放固定不变的交互逻辑的内容(如::
、展开/收起
)。border
分为上、右、下、左,每一块区域的border-width
不为0
时都是梯形(width
或height
为0
时为三角形),border-width
决定梯形(或三角形)的高。
某些边设为border-width
不为0
、border-right-color
为transparent
可以制造一些形状。
filter: drop-shadow
(图像本身形状和alpha通道的阴影)代替box-shadow
(盒阴影)overflow: hidden
无法处理position: fixed
的子孙节点。position: absolute
超出浏览器可能导致Android出现滚动条(虽然不能滚动)
尝试用position: fixed
代替。
字体高度抖动
可能和设置在父级的line-height
有关,尝试把line-height
改到设置在包裹文字的节点。
权重
优先级(从低到高):
低等级的权重值叠加再多,也无法大于高等级的权重值(一个反例)。
1级:
元素选择器(type selectors)、伪元素选择器(pseudo-elements)。
2级:
类选择器(class selectors)、伪类选择器(pseudo-classes)、属性选择器(attribute selectors)。
3级:
ID选择器(ID selectors)。
4级
内嵌样式(标签的style
属性值)。
5级
!important
。
不改变权重:
*
、关系符号(,
、
、>
、+
、~
)、:not()
。
原则:
元素应用属性值规则:
不影响应用:
元素在文档的位置、选择器间的距离。
e.g.
```html.a -> .b -> p(blue)
```.b -> .a -> p(blue)
样式相对于元素的位置。
无视样式距离元素的相对位置(外联与内联),仅取决于样式与样式之间的文档顺序。
优先级基于形式,而不是结果。
e.g.
[id=foo]
依然是属性选择器优先级(2级),而不是ID选择器优先级(3级)。
继承祖先元素的样式,优先级永远低于目标元素。
e.g.
```htmlparent(red)```son(blue)
性能
CSS选择器对性能的影响源于浏览器匹配选择器和文档元素时所消耗的时间。
样式系统从右向左进行规则匹配
从右向左解析的原因:Stack Overflow: Why do browsers match CSS selectors from right to left?:更快地判断出某选择器不匹配某DOM,从而更高效匹配完所有内容。
效率(从高到低)
+
)>
)
)*
)尽量把
元素选择器
前面的后代元素选择器
改成子元素选择器
。因为可能有很多匹配的元素选择器,会向前查找过多而影响性能。但是ID选择器
或类选择器
前面的子元素选择器
则无所谓,因为不会匹配太多选择器、不会向前查找太多次。
<link>
;避免使用display
、不滥用float
、不滥用Web字体。
- 初始值:该默认值由官方CSS规范定义(对于继承属性,初始值只能被用于没有指定值的根元素上;对于非继承属性,初始值可以被用于任意没有指定值的元素上)
- user agent stylesheet:浏览器默认样式表,不同浏览器不同。
user style sheets:用户自定义的CSS。- author style sheets:开发人员定义的CSS,内联样式(inline css)、内部样式(internal css,embedded css)、外部样式(external css)。
继承属性
若元素的一个继承属性没有指定值,则取父元素的同属性的计算值(computed value)。只有文档根元素取该属性的初始值(initial value)。
若子节点设置了某属性 且 没有语法错误(语法错误导致本行CSS设置无效),则任何情况都不会再使用父级继承属性——继承属性是在子级未设置此属性时才生效
```htmlfather```son1,若设置了属性值,则不会使用父级继承属性,尽管这个字体不存在son2,语法错误,程序删除本行错误语句。继承父级son3,继承父级
非继承属性
若元素的一个非继承属性没有指定值(user agent stylesheet也算已经指定值了),则取该属性的初始值。
特殊CSS属性(值):
inherit
将属性设置为其父元素对应属性的计算值(仅一层父级,不会再向上继承祖先级),可用于:继承属性/非继承属性
。
initial
将属性设置为其初始值(初始值不是user agent stylesheet,初始值由官方CSS规范定义)。
在继承属性上,初始值可能是意外的(因为是针对文档根元素)。应该使用
inherit/unset/revert
关键字代替。
unset
若该属性默认可继承,则值为inherit
;否则值为initial
。
revert
CSS4。
all: inherit/initial/unset/revert
将该元素所有属性(除了 、unicode-bidi
)重置为:direction
inherit/initial/unset/revert
。
每个元素都被表示为一个矩形的盒子,盒子有四个边:
外边距边(margin)、边框边(border)、内填充边(padding)、内容边(content)。
box-sizing
值:
以宽度为例。
content-box
(默认)
布局所占宽度 = width + padding左右 + border左右
border-box
布局所占宽度 = width = content + padding左右 + border左右
padding-box
(已废弃)
ie低版本盒模型比较特殊。
margin
合并W3C定义:在CSS中,两个或多个毗邻(父子元素或兄弟元素)的普通流中的块元素垂直方向上的margin会发生叠加。这种方式形成的外边距即可称为外边距叠加(collapsed margin)。
float: left/right
、positon: absolute/fixed
之外的内容,父级是flex
的节点不是普通流。产生独立的BFC结构可避免margin合并。
ie6、7触发haslayout会影响margin合并的发生。
对容器添加以下CSS属性使其成为独立的BFC
float: left / right;
overflow: hidden / auto / scroll;
display: inline-block / table-cell / table-caption / flex / inline-flex;
position: absolute / fixed;
ie6、7不支持BFC,但是有haslayout。
满足以下任意条件则形成层叠上下文:
z-index: auto;
不形成层叠上下文。
<html>
。z-index
属性值不为position: relative/absolute;
定位元素。position: fixed;
(仅限Chrome,其他浏览器遵循需要z-index
为数值)。z-index
属性值不为flex
子项(父元素display: flex/inline-flex;
)。opacity
属性值< 1
的元素。transform
属性值不为will-change
属性值指定任意CSS属性(即便没有直接指定这些属性的值)。-webkit-overflow-scrolling
属性值为touch
的元素。filter
属性值不为mix-blend-mode
属性值不为perspective
属性值不为isolation
属性值为isolate
的元素。层叠顺序(stacking order)
z-index
比较2个元素的层叠顺序:
z-index
)z-index
使用注意
z-index
的数值> 4
,否则就要考虑是否过度使用此属性。分层实践
不同层之间的层叠顺序已先确定,高z-index
层内部所有内容均会遮盖低z-index
层内部所有内容。层内部可以再继续分层。
<main class="main">
<section class="layer layer--1">
内部再进行z-index排序,不会影响外层.layer的排序(layer--1的内容永远会被layer--2层遮盖)
</section>
<section class="layer layer--2">
内部再进行z-index排序,不会影响外层.layer的排序(layer--1的内容永远会被layer--2层遮盖)
</section>
</main>
.main {
position: relative;
/* 高、宽 */
}
.layer {
position: absolute;
width: 100%;
height: 100%;
pointer-events: none; /* 父级容器鼠标事件穿透 */
> * {
pointer-events: auto; /* 子级恢复 */
}
&.layer--1 {
z-index: 1;
}
&.layer--2 {
z-index: 2;
}
}
参考:MDN:使用媒体查询。
@media
、@import
<style>
、<link>
、<source>
等的media
属性JS中window.matchMedia
(返回MediaQueryList
对象),MediaQueryList
对象的change
事件和matches
等属性
e.g.
```javascript var mql = window.matchMedia('(prefers-color-scheme: dark)') // 深色方案 mql.addEventListener('change', function () { console.log(this.matches, this) }) ```
width
auto
(默认):
换算具体值为:本元素width = 父级width - 本元素(margin + padding + border)水平值。
当块级width为默认的auto时,设置负的水平margin会使width增加。
100%
:
父级的px为自己的px。
block
的CSS设置float: left/right;
position: absolute/fixed;
意味着有以上CSS属性的行内标签可以当做块级标签使用。
单词内断字
默认效果:若此行放不下则整个单词换行,若下行也放不下则溢出(保持单词不断字)。
word-break
normal
(默认)
默认效果。
break-all
若此行放不下则直接断字。
word-wrap
或overflow-wrap
normal
(默认)
默认效果。
break-word
若此行放不下则整个单词先换行,若下行也放不下才断字。
- 对于用户输入或不确定长度的内容,建议都加上
word-wrap: break-word;
,避免内容宽度溢出。- 或直接在
<body>
上设置,让所有内容继承(ie10-使用word-wrap: break-word;
会导致无法出现text-overflow
的溢出效果,因此ie10-不要在body上全局添加)。
white-space
处理空白和内容换行。
值 | 空格和制表符 | 换行符和<br> |
到达宽度极限 |
---|---|---|---|
normal (默认) |
连续的合并为一个 | 当做空格 | 换行 |
nowrap |
连续的合并为一个 | 当做空格 | 不换行 |
pre |
保留 | 换行 | 不换行 |
pre-wrap |
保留 | 换行 | 换行 |
pre-line |
连续的合并为一个 | 换行 | 换行 |
text-overflow
溢出的样式。
clip
(默认)
截断文本。
ellipsis
省略号。
需要和
overflow: hidden;
、white-space: nowrap;
配合产生溢出。
flex-wrap
Flex容器内,一条主轴排不下的情况,如何换行。
nowrap
(默认):不换行。wrap
:换行,第一行在上方。wrap-reverse
:换行,第一行在下方。word-spacing
空白字符包裹的非空白字符的间距。
letter-spacing
字符的间距。
浏览器会把小数以及百分比换算成整数的单位(px)
RN(客户端)可以用小数点的数值,不会
取整(以具体机型的具体样式为准)。
多个子节点浮动的总宽度接近100%会表现成100%
使用rem
,因为换算成px
而四舍五入或向下取整可能导致切图问题的解决方案:
width: 100%;
。padding
,再用负margin
中和。em
、%
em
单位:
相对于节点自己的font-size的倍数(先计算出自己的font-size最终值)。
若font-size的单位为
e.g. ```css .father { font-size: 10px; } .son { font-size: 2em; /* 20px:继承的font-size * 2 */ padding: 2em; /* 40px:自己的font-size * 2 */ } ```em
,用从父级继承的font-size值乘以倍数
%
单位:
包含块(containing block)
不能简单地理解成是父元素。若是`position: static/relative;`元素,包含块是其父元素;若是`position: absolute;`元素,包含块是离它最近的`position: relative/absolute/fixed;`的祖先元素;若是`position: fixed;`元素,包含块是视口(viewport)。
乘以包含块的width
:
margin
、padding
、left
、right
、width
、max-width
、min-width
、text-indent
、grid-template-columns
、grid-auto-columns
、column-gap
乘以包含块的height
:
top
、bottom
、height
、max-height
、min-height
、grid-template-rows
、grid-auto-rows
、row-gap
乘以继承的font-size
:
font-size
乘以节点自己的font-size
:
line-height
乘以节点自己的line-height
:
vertical-align
乘以节点自己的width/height
:
x轴方向的百分比:乘以节点自己的
width
;y轴方向的百分比:乘以节点自己的height
。可以配合calc
进行动态设计,如:calc(100% - 50px)
。
border-radius
、background-size
、translate
、transform-origin
、zoom
、clip-path
、border-image-width
乘以主轴长度(flex
):
flex-basis
特殊:
background-position
百分比值会同时应用于元素和图像。
e.g.
1. `50% 50%`会把图片的(50%, 50%)这一点与框的(50%, 50%)处对齐,相当于设置了`center center`。 2. `0% 0%`相当于`left top`。 3. `100% 100%`相当于`right bottom`。
border-image-slice
相对于图片尺寸。
filter
系列函数
节点自己是position: absolute;
:
离它最近的positon: relative/absolute/fixed;
的祖先元素;若没有,则相对于视口。
节点自己是position: fixed;
:
相对于视口。
若某个元素设置了百分比的属性,则后代元素继承的是这个元素计算后具体的px值。
line-height
值的不同情况:无单位数字、带单位值、百分比、normal
其中的em
、%
、无单位数字
,都是相对于元素自身最终的font-size值的倍数。
line-height
是继承属性:
em
和%
是计算出具体px再向后继承(其子节点的line-height=父级给的具体px)。无单位数字
是直接继承系数,其子节点会分别计算(子节点的line-height=父级给的无单位数字,再继续和自身font-size相乘)。单行文本情况下:
line-height
决定。height
决定,若没有设置height
再由line-height
决定(ie6是line-height
优先决定)。元素高度表现为:
内容区域(content area) + 行间距(vertical spacing) = 行高(line-height)
- 内容区域(鼠标选中后的高度):只与
font-size
、font-family
有关,与无关。line-height
- 行间距:摇摆不定,可以为负值,仅为达成以上等式而变化。若行高小于内容区域,则行间距是负数,此时文字被裁切,上下行间部分重合。
ie6以及部分浏览器不能用line-height控制图片与文字的对齐位置,使用其他垂直居中方式(如:使用
display: flex; align-items: center;
)。
<img>
的src
属性<img>
加上背景来用作默认图,必须用其他标签来代替。<img>
设置背景(如:内容图片或头像的初始图,不要使用背景,应该使用JS延时加载-图片lazyload前的默认图),因为当图片是透明图时,会出现背景。隐藏没有src
属性或src
属性为空的<img>
:
img[src=""] { /* ie8+ */
visibility: hidden; /* 属性为空隐藏 */
}
img:not([src]) { /* ie9+ */
visibility: hidden; /* 属性不存在隐藏 */
}
style
、节点属性等无关,仅与图片资源本身有关。<img>
的地址为空或错误时,会出现浏览器默认灰色边框(和图片错误图标),无法去除,只能使用图片的error
事件替换成默认图解决:默认图组件。<img>
CSS相关特性:
设置<img>
中可替换元素的位置、拉升:object-position
、object-fit
。
类似于针对背景图的位置、拉升:
background-position
、background-size
(当background-repeat: no-repeat
时)。
<img>
的display
属性的默认值是inline
,但是它的默认分辨率是由被嵌入的图片的原始宽高来确定的,使得它就像inline-block
一样。<img>
可以设置vertical-align
来指定与其他行内元素的垂直对齐方式。
vertical-align
用来指定inline
、inline-block
、table-cell
元素的垂直对齐方式。
iOS
iPhone的安全区域(Apple: Adaptivity and Layout):一个可视窗口范围,处于安全区域的内容不受 圆角(corners)、齐刘海(sensor housing)、小黑条(Home Indicator) 影响,如下图蓝色区域。
针对iPhone X之后的全面屏:
设置viewport-fit=cover
<meta name="viewport" content="其他..., viewport-fit=cover">
使用iOS11新特性CSS变量
safe-area-inset-left
:安全区域距离左边边界距离safe-area-inset-right
:安全区域距离右边边界距离safe-area-inset-top
:安全区域距离顶部边界距离safe-area-inset-bottom
:安全区域距离底部边界距离constant(变量名)
、env(变量名)
进行使用
iOS的专属CSS方法,包括:
- iOS11~11.2:
constant
- iOS11.2+:
env
、min
、max
Android
overflow-x
和overflow-y
相同,则等同于overflow
;若不同,且其中一个值为visible
,另一个为hidden/scroll/auto
,则visible
重置为auto
。默认滚动条均来自<html>
(而不是<body>
)
因此,除去默认滚动条应在<html>
上设置overflow
值。
JS获取文档滚动高度为:
document.body.scrollTop || document.documentElement.scrollTop
$(window).scrollTop()
或$(document).scrollTop()
;Zepto:$(window).scrollTop()
滚动条会占用容器的可用高度或宽度(JS获取滚动轴宽度(或高度))。
针对右边滚动条:(除了
<html>
的)DOM的滚动条,可以设置margin-right: -某px;
(width: auto;
)使滚动条向右移动、移出此DOM容器(padding-right: 某px;
可以产生与滚动条的间隔)。
能滚动的DOM(父overflow
值非 )在iOS有额外滚动距离的效果,导致被遮盖的节点被显露:hidden
可以在父级设置overflow: hidden
阻止滚动,从而规避需要被遮盖的节点被显露。
@font-face
使用www.iconfont.cn方便生成字体图标,每个字体图标对应一个Unicode(也可用现存文字已使用的Unicode作为字体图标的Unicode)。
加载
@font-face
的src
中加载的字体地址受跨域的约束,若想跨域加载字体,则需设置CORS。加载字体时机:
@font-face
,就会去下载字体,不论实际有没有应用该字体。@font-face
且 页面有元素应用了该字体,就会去下载,不论该元素是否有文本内容。@font-face
且 页面有元素应用了该字体 且 该元素有文本内容,才会去下载字体。兼容多种浏览器的兼容写法:
参考:iconfont:代码应用。
<style>
@font-face {
font-family: "某字体族名";
src: url('iconfont.eot'); /* IE9 */
src: url('iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('iconfont.woff') format('woff'),
url('iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('iconfont.svg#某字体族名') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family: "某字体族名" !important;
}
.icon-xx:before {
content: "\e625";
}
</style>
<!-- 使用 -->
<i class="iconfont"></i>
或
<i class="iconfont icon-xx"></i>
`font-family`会[继承](https://github.com/realgeoffrey/knowledge/blob/master/网站前端/HTML+CSS学习笔记/README.md#css继承)父级,但若子级设置了`font-family`就不再向上继承(覆盖),无论子级设置的字体是否全都不可用(未找到字体)。因此无论如何,都应该在设置字体时在列表末尾添加至少一个通用字体族名(否则按照浏览器默认字体处理)。如:`font-family: 字体族名, 通用字体族名;`。 - CSS的通用字体族名: 1. `serif` 带衬线字体,笔画结尾有特殊的装饰线或衬线。 2. `sans-serif` 无衬线字体,即笔画结尾是平滑的字体。 3. `monospace` 等宽字体,即字体中每个字宽度相同。 4. `cursive` 草书字体。这种字体有的有连笔,有的还有特殊的斜体效果。因为一般这种字体都有一点连笔效果,所以会给人一种手写的感觉。 5. `fantasy` 主要是那些具有特殊艺术效果的字体。 6. `system-ui` 从浏览器所处平台处获取的默认用户界面字体。 7. `math` 针对显示数学相关字符的特殊样式问题而设计的字体:支持上标和下标、跨行括号、嵌套表达式和具有不同含义的 double struck glyph。 8. `emoji` 专门用于呈现 Emoji 表情符号的字体。 9. `fangsong` 一种汉字字体,介于宋体和楷体之间。这种字体常用于某些政府文件。
font-family
设置值时,在列表末尾应该添加至少一个通用字体族名。
加入了字体后的使用方式
CSS:
content: "\16进制数";
HTML:
进制数;
或
进制数;
HTML的字符实体(character entity):
用于显示保留字符(否则将被解释为HTML代码)和不可见字符。[官方实体清单](https://html.spec.whatwg.org/multipage/named-characters.html)。&名字;
或&#序号;
(序号:x16进制数
或10进制数
)
JS:
dom.innerHTML =
'进制数;'
或'
进制数;'
(都可省去;
);'\u4位16进制数'
或'\u{16进制数}'
或'\x2位16进制数'
或'\3位8进制数'
。
数字数量有限制:Unicode。
text-align: justify;
text-align
:定义行内内容(如:文字)如何相对它的块父元素对齐。并不控制块元素自己的对齐,只控制它的行内内容的对齐。
text-align: justify;
:文字向两侧对齐,但对最后一行无效。text-align-last
:文本中最后一行对齐规则。text-align: justify-all;
:和justify
一致,且最后一行也是文字向两侧对齐。不推荐中文的文章用这个属性值,建议用默认或者
text-align: start;
;对固定的文本可以使用这个属性,达到设计稿效果。
CSS渐变是以CSS背景图的形式展示,但没有内在尺寸(没有固定大小、也没有宽高比),其实际大小取决于其填充元素大小。
可以添加在CSS背景图能添加的地方。
如:background-image
、list-style-image
、border-image-source
、cursor
、mask-image
、shape-outside
、mask-border-source
、等。
作为CSS背景图属性的属性值
如:
background-image: linear-gradient(#e66465, #9198e5);
。
文字渐变:
background-image: linear-gradient(to right, rgb(255, 254, 184), rgb(247, 190, 61));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
clip-path
已废弃。clip
裁剪出元素的可显示区域。区域内的部分显示,区域外的隐藏。
被裁剪过的元素,其BFC占用的位置不会变化,只是把裁剪区域外的元素内容隐藏、透明了。裁剪区域外对其他元素而言是透明的,堆叠会直接显示其他元素。
object-fit
对可替换元素(如:<img>
、<video>
)的拉升,超出容器部分被裁剪掉。
background-clip
背景运用到哪里(如:背景延伸到border
、padding
、content
、文字),和裁剪无关。
table-layout
auto
(默认)
在<td>
或<th>
上设置宽度无效,各项宽度取决于内容宽度。
fixed
整个表格在首行被下载后就被解析和渲染。更快完成渲染,性能更优。
<td>
或<th>
宽度,没有设置宽度的所有项平分父级余下的宽度。
<table>
(display: table;
)各<td>
或<td>
项(display: table-cell;
)默认内容垂直居中,用vertical-align
调节垂直对齐。
- 旋转效果的节点,若要增加内嵌滚动条,则不能在此节点上增加
border-radius
,否者滚动条横竖轴颠倒。- 部分Android系统(或低端机)对内嵌的滚动条(
overflow: hidden/auto;
)支持不佳,尤其增加了旋转效果后,设置的滚动条(甚至overflow: hidden;
)会导致更多样式问题。除了去除内嵌滚动条的border-radius
,还可以尝试给兄弟节点设置z-index
。部分硬件较差的WebView对CSS3支持非常有限,无法做到旋转+内嵌滚动条(内嵌滚动条横竖轴颠倒)。
- 其他解决方案:使用按钮(控制翻页或JS滚动)代替内嵌滚动条;使用
touchmove
实现滑动页面。
媒体查询控制横竖屏添加旋转属性
@media (orientation: portrait) {
.dom {
transform: rotate(90deg);
}
}
@media (orientation: landscape) {
.dom {
}
}
旋转使用的媒体查询:
要求:页面没有滚动条,内容都在一屏视口内;设计稿只有一份,但要适应各种分辨率机型。
orientation: portrait
)根据width
,横屏(orientation: landscape
)根据height
。用JS方法控制:模拟手机旋转。
<a>
的鼠标、键盘事件pointer-events: none;
穿透<a>
的鼠标事件(包括点击和hover等,因为点击不到所以JS事件也不会触发)。href
属性,可以忽略键盘索引(tab键无法切换到)。<a style="pointer-events: none;">禁用鼠标和键盘的链接</a>
<iframe>
注意:
<iframe>
的scrolling="no"时其视口就是整个
<iframe>高宽边界,因此其内部的
position: fixed;定位不是以外层的浏览器viewport定位,而是以此
<iframe>`的边界来定位。
<link rel="apple-touch-icon" sizes="180x180" href="/favicon-180x180.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="mask-icon" href="/favicon.svg" color="#fff">
<!--<link rel="manifest" href="/site.webmanifest">--><!-- PWA -->
<!--<meta name="msapplication-TileColor" content="#2b5797">-->
<!--<meta name="theme-color" content="#ffffff">-->
完整favicon制作:https://realfavicongenerator.net/。
富文本编辑器(rich text editor):一种可内嵌于浏览器,所见即所得(what you see is what you get,WYSIWYG)的文本编辑器。
标签、样式注意:
除了要检测用户输入标签的闭合性之外,还要注意富文本编辑器的祖先元素不要用<li>
嵌套。
因为代码中若有单独的<li>
(没有嵌套<ol>
或<ul>
),则会「越级」到跟祖先级<li>
同级的内容。
<em>
、<ol>
、<ul>
等标签来表示斜体、有序序列、无序序列,因此若用CSS重置了以上标签的样式后,则要在富文本内重载开启它们的默认效果(或定制效果)。<table>
上使用cellspacing
、border
、bordercolor
属性设置表格,又因为设置了border: 0;
的表格无法重载开启以上属性作用,所以CSS重置时不要重置table,tbody,tfoot,thead,tr,th,td
的border
属性。针对contenteditable="true"
的DOM内容:
整个块级元素修改,可用:document.execCommand('formatBlock', false, '<块级标签名>')
,再设置元素的样式。
如:「小字体」的块级内容,就可以用
document.execCommand('formatBlock', false, '<h6>')
,然后设置h6
的小字体样式。
内部可以嵌入contenteditable="false"
的DOM:
<a>
,则可以跳转、hover变成鼠标手型)。插入一个不可编辑卡片的方式:
contenteditable="false"
的DOM。<img>
。实现方式:
使用原生document.execCommand
操作contenteditable="true"
的DOM内容(或document.designMode === 'on'
的整个文档、某iframe.contentDocument.designMode === 'on'
的整个<iframe>
)。
如:pell。
大部分是添加指定的几种标签
和style
的方式进行展示,因此只需定制富文本内指定的几种标签的样式。
document.execCommand
原生支持添加的标签`、``、``~`
`、`
`、等块级标签 6. `
修改、插入DOM的方式模拟实现DOM的编辑。
如:quill。
除了添加标签和style
之外,还会额外添加class
和DOM(需自定义样式)。