基础理论
元素的显示与隐藏
根据不同的需求选择隐藏方案
如果希望元素不可见,同时不占据空间,辅助设备无法访问,同时不渲染,使用script标签隐藏
<script type="text/html">
<img src="./img/55.png" />
</script>
获取数据的方法使用 document.querySelector('script').innerHTML
如果希望元素不可见,同时不占据空间,辅助设备无法访问,但资源有加载,DOM可访问,则可以直接使用display:none隐藏
.dn{
display:none;
}
如果希望元素不可见,同时不占据空间,辅助设备无法访问,但显隐的时候可以有transition淡入淡出效果
.hidden {
position: absolute;
visibility: hidden;
}
如果希望元素不可见,不能点击,辅助设备无法访问,但占据空间保留则可以使用visibility:hidden
隐藏
.vh {
visibility: hidden;
}
如果希望元素不可见,不能点击,不占据空间,但键盘可访问,则可以使用clip裁剪隐藏
.clip {
position: absolute;
clip: rect(0 0 0 0);
}
案例:1.请帖生成封面。2.键盘使用快捷键但不显示按钮(使用 accesskey
)
如果希望元素不可见,不能点击,但占据空间,且键盘可访问,则可以使用relative隐藏。如果条件允许,也就是上一层层叠上下文之间设置了背景色,则可以使用更友好的z-index负值隐藏
.out {
position: relative;
left:-999em;
}
.lower {
position: relative;
z-index: -1;
}
如果希望元素不可见,但可以点击,而且不占据空间,则可以使用透明度
.opacity {
position: absolute;
opacity: 0;
}
如果希望元素不可见,但位置保留,依然可以点可以选,则直接让透明度为0
.opacity{
opacity: 0;
}
如果希望元素在显示时有一个 transition
动画,可以使用 max-height
进行隐藏
.hidden {
max-height: 0;
overflow: hidden;
}
display与元素的显隐
基础了解:无法点击,无法使用屏幕阅读器等辅助设备访问,占据空间消失
深层了解:img标签上或父元素设置 display:none
都会加载资源。但是 background-image
请求的资源在该标签上或父元素设置 display:none
都不会加载资源(safari和chrome验证),在计数中设置了display:none的元素不被计入。会对 IntersectionObserver
造成影响
visibility与元素的显隐
基础了解:无法点击,无法使用屏幕阅读器等辅助设备访问,占据空间不消失
深层了解:visibility
具有继承性,父级设置 visibility:hidden
后子级可以设置 visibility:visible
显示子元素。设置了 visibility:hidden
的元素会加载img资源也会加载 background-image
资源。同时也会被纳入计数。visibility
属性被纳入 transition
的范围内,因此可利用该属性展示元素从隐藏到显示的过渡效果。但是该属性不会对 IntersectionObserver
造成影响,也就是说如果弹窗是从隐藏到显示使用了该属性的话,对它进行埋点是无效的。
文本的换行
word-break
当行尾放不下一个单词时,决定单词内部该怎么摆放(决定不断行单词的长度)
nomal:默认值,默认的换行规则(CJK文本断行,英文单词不断行,空格断行)
break-all:对于non-CJK(中日韩)文本,可在任意地方断行
keep-all:CJK文本不断行,non-CJK文本表现形式如同nomal
word-wrap
是用来说明当一个不能被分开的字符串太长而不能填充其包裹盒时,为防止其溢出,浏览器是否允许这样的单词断词(没有换行点的单词在句尾放不下时,决定单词是否断词)
nomal:默认值,行只能在正常的单词断点处中断。(例如两个单词之间的空格)。
break-word:表示如果行内没有多余的地方容纳该单词到结尾,则那些正常的不能被分割的单词会被强制分割换行。
white-space
如何处理元素中的空白
nomal:默认值,连续的空白符被合并,换行符被当做空白符处理
nowrap:连续的空白符被合并,文本内的换行符无效(
有效)
pre:连续的空白符会被保留,在遇到换行符或者
元素时才会换行
pre-wrap:连续的空白符会被保留,在遇到换行符或者
元素,或者为了填充行框盒子(line-box)时才会换行
pre-line:连续的空白符会被合并,在遇到换行符或者
元素,或者为了填充行框盒子(line-box)时才会换行
line-break
中文标点的换行规则,比如。是避首标点,《是避尾标点,通过此属性控制CJK文本标点的换行规则
auto:使用默认的换行规则。
loose: 使用限制性最小的换行规则分隔文本。通常用于短行,如在报纸上。
normal:使用最普通的换行规则。
strict: 使用最严格的换行规则。
anywhere:任意位置都可以作为换行点,包括任意的标点。
<wbr>
这是html元素,宽度不够,在我这里换行;宽度足够,还是一行显示
实现原理
wbr::after{
content: '\00200B'
}
光标属性cursor
https://developer.mozilla.org...
flex子项最终尺寸计算规则
一个flex子项的最终尺寸是基础尺寸(或内容尺寸),弹性增长或收缩,最大最小尺寸共同作用的结果
最终尺寸计算的优先级是:
最大最小尺寸限制 > 弹性增长或收缩 > 基础尺寸
- 基础尺寸有
flex-basis
属性或width
属性,以及box-sizing
盒模型共同决定 - 内容尺寸指最大内容宽度,当没有设置基础尺寸时会顶替基础尺寸的角色
- 弹性增长指的是
flex-grow
属性,弹性收缩指的是flex-shrink
属性 - 最大尺寸主要受
max-width
属性显示;最小尺寸受最小内容宽度,width
属性和min-width
属性共同影响
flex容器:
flex-wrap:nowrap;
flex-direction:row;
justify-content:flex-start;
align-items:stretch;为默认值flex: 0 1 auto 这是flex子项的默认值,代表flex-grow:0,flex-shrink:1,flex-basis: auto
最小尺寸计算规则
- 如果
min-width
属性值不是auto
,则元素的最小尺寸就是就是min-width
的属性值,此时width
属性无法影响最小尺寸,哪怕width
的属性值大于min-width
的属性值。 - 比较
width
的属性的计算值和最小内容宽度的大小,较小的值就是元素的最小尺寸。 - 如果
width
的属性值和min-width
的属性值均为auto
,则元素的最小尺寸就是最小内容宽度。 - 如果flex子项设置了
overflow:hidden
,且最小尺寸是由是否最小内容宽度决定的,则最小尺寸无效。
基础尺寸计算规则
- 如果
flex-basis
属性和width
属性同时设置了具体的数值,width
属性值会被忽略,优先使用flex-basis
作为基础尺寸。 - 如果
flex-basis
的属性值是初始值auto
,则会使用width
属性设置的长度值作为基础尺寸。 - 如果
flex-basis
和width
的属性值都是auto
,则会使用flex子项的最大内容宽度作为基础尺寸
弹性增长或收缩何时作用
- 如果容器尺寸足够并且子元素的属性值包含
flex-grow
不为0则启用弹性增长规则 - 容器尺寸足够:在容器
flex-wrap:wrap
状态下,n个子元素的基础尺寸相加宽度少于容器宽度,n+1个子元素的基础尺寸相加大于容器,且这n个子元素中具有flex-grow
不为0的元素,则这n个子元素具备弹性增长的条件。在容器flex-wrap:nowrap
状态下,所有子元素基础尺寸相加宽度少于容器宽度。 - 如果容器尺寸不足并且子元素的属性值包含
flex-shrink
不为0则启用弹性收缩规则 - 容器尺寸不足:在容器
flex-wrap:wrap
状态下,子元素的基础尺寸大于容器宽度,且子元素的flow-shrink
不为0,则这个子元素具备弹性收缩条件。在容器flex-wrap:nowrap
状态下,所有子元素的基础宽度少于容器宽度,且至少有一个子元素的flex-shrink
不为0,则flex-shrink
不为0的子元素具备弹性收缩条件。 - 弹性增长,增长的部分是可分配空间,计算规则是容器宽度-元素基础尺寸
- 弹性收缩,收缩的部分是有
flex-shrink
不为0元素的宽度,最多可以收缩至元素最小尺寸。
最终尺寸计算规则-总结
- 如果没有弹性收缩或增长,则元素在最大尺寸和最小尺寸范围内使用基础尺寸
- 如果元素能够弹性增长或收缩,在容器宽度足够的情况下使用弹性增长规则,在容器宽度不足的情况下使用弹性收缩规则,同一行只可能应用一种规则
选择器
选择器优先值计算
选择器 | 计算值 | 计算细则 |
---|---|---|
* {} | 0 | 1个0级统配选择器,优先级数值为0 |
dialog {} | 1 | 1个1级标签选择器,优先级数值为1 |
ui > li {} | 2 | 2个1级标签选择器,1个0级选择器,优先级数值为2 |
li > ol + ol {} | 3 | 3个1级标签选择器,2个0级选择器,优先级数值为3 |
.foo {} | 10 | 1个2级类名选择器,优先级数值为10 |
a:not([rel=nofollow]) {} | 11 | 1个2级属性选择器,1个1级标签选择器,1个0级否定伪类,优先级数值为11 |
a:hover {} | 11 | 1个1级标签选择器,1个2级伪类,优先级数值为11 |
ol li.foo {} | 12 | 2个1级标签选择器,1个2级类名选择器,优先级数值为12 |
li.foo.bar {} | 21 | 1个1级标签选择器,2个2级类名选择器,优先级数值为21 |
#foo {} | 100 | 1个3级ID选择器,优先级数值为100 |
#foo .bar p {} | 111 | 1个3级ID选择器,1个2级类名选择器,1个1级标签选择器,优先级数值为111 |
相同计算值下遵循后来居上原则,后面的优先级更高
命名灵感
从HTML标签寻找灵感
.cs-module-header {}
.cs-module-body {}
.cs-module-aside {}
.cs-module-main {}
.cs-module-nav {}
.cs-module-section {}
.cs-module-content {}
.cs-module-summary {}
.cs-module-detail {} // 详情
.cd-module-option {}
.cs-module-img {}
.cs-module-footer {}
.cs-module-ui {}
.cs-module-li {} // 列表子项
.cs-module-a {} // 链接
.cs-module-g {} // 组
.cs-module-desc {} // 描述
.cs-module-x {} // 容器盒子
从HTML特定属性值中寻找灵感
.cs-radio {}
.cs-checkbox {}
.cs-range {}
.cs-tspan-email {}
.cs-tspan-number {}
.cs-tspan-color {}
.cs-tspan-tel {}
.cs-tspan-date {}
.cs-tspan-url {}
.cs-tspan-time {}
.cs-tspan-file {}
从无障碍访问的role属性值中寻找灵感
.cs-grid {}
.cs-grid-cell {}
.cs-log {}
.cs-menu {}
.cs-menu-bar {}
.cs-menu-item {}
.cs-region {} // 不能被其他role描述,但是很重要的部分
.cs-banner {} // 横幅广告
.cs-slider {}
.cs-tab {}
.cs-tab-list {}
.cs-tab-pannel {}
.cs-tooltip {}
.cs-tree {}
从CSS伪类和HTML布尔属性中寻找灵感
.active {}
.disabled {}
.selected {}
.checked {}
.invalid {} // 出错状态
体验优化
图片加载失败体验优化
<img src="xxx.png" alt="图片封面" onerror="this.classList.add('error');">
img.error {
display: inline-block;
transform: scale(1);
content: '';
color: transparent;
}
/* 替换图片 */
img.error::before {
content: '';
position: absolute;
left: 0; top: 0;
width: 100%; height: 100%;
background: #f5f5f5 url(break.svg) no-repeat center / 50% 50%;
}
/* alt 提示 */
img.error::after {
content: attr(alt);
position: absolute;
left: 0; bottom: 0;
width: 100%;
line-height: 2;
background-color: rgba(0,0,0,.5);
color: white;
font-size: 12px;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
点击体验优化
移动端按钮可点击范围放大
.mobi-btn {
border: 8px solid transparent;
}
键盘体验优化
可访问性-焦点控制
tabindex = "-1"
元素可以被鼠标或JS focus但不能被键盘focus
tabindex = "0"
最后一个被focus的元素
tabindex >= "1"
越小优先级越高
若进入网页没有点击则按照1,2,...,0
若点击则定位到点击的主体,按下tab寻找到第一个有focus的元素,再次按下根据该元素的tabindex寻找下一个焦点
:focus-visible
让我们知道元素的聚焦行为是键盘触发还是鼠标触发
// 鼠标触发
:focus:not(:focus-visible) {}
// 键盘触发
:focus:focus-visible {}
当前获得焦点的元素
document.activeElement
检测文档是否获取了焦点
document.hasFocus()
滚动体验优化
overscroll-behavior
overscroll-behavior: [ contain | none | auto ]{1,2}
当只有一个值时代表水平垂直方向都是该值,有两个值时第一个代表水平方向第二个代表垂直方向
auto:滚动到边缘后继续滚动外部的可滚动容器
contain:默认的滚动溢出行为只会表现在当前元素的内部,不会对相邻的滚动区域进行滚动。
none:相邻的滚动区域不会发生滚动,并且会阻止默认的滚动溢出行为。
scroll-behavior
在可滚动的容器上使用,常用于到达顶部
auto:默认值
smooth:平滑滚动,与 ant-design
的 scrollToFirstError
搭配效果佳
overflow-anchor
auto: 默认值,该行为会调整位置以最大程度的减少内容偏移(例如上方图片的突然加载会无感知)
none:退出浏览器滚动锚定行为
隐藏滚动条,同时元素可滚动
.scroll-none {
scrollbar-width: none;
}
// chrome 私有方法
.scroll-none::-webkit-scrollbar {
width:0; height:0;
}
跳转体验优化
PC端跳转同一个地址不创建新的tab页
<a href="https://www.baidu.com" target="bd">点击进入百度</a>
target相同时会指向同一个tab页
输入体验优化
cater-color属性改变插入光标颜色
cater-color: red
移动端唤起数字键盘
验证码:<input inputmode="numeric">
拉伸行为体验优化
rezize
none: 默认值,没有拉伸效果,可以用来种植 textarea
元素默认的拉伸行为
both:既可以水平方向拉伸,也可以垂直方向拉伸
horizontal:仅可以水平方向上拉伸
vertical:仅可以垂直方向上拉伸
生效条件
块级元素且 overflow
的属性值不是 visible
限制拉伸范围
使用 max-width,max-height,min-width,min-height
属性
选择行为体验优化
user-select
text:默认值,文字和图片可以被选中
none:禁止图文被选中
all:被低估的一个属性值,设置了该属性的图文内容都会被选中
::selection
被选中时伪类,全局设置时可设置品牌颜色为背景,合适颜色为字体颜色
::selection {
color: hunlijiColor;
background: hunlijuBackgroundColor;
}
刷新体验优化
刷新时滚动条回到顶部
if (history.scrollRestoration) {
history.scrollRestoration = 'manual';
}
打印行为体验优化
控制打印样式的媒体查询
@media print {
header{
display:none;
}
}
是否进行精确打印
color-adjust
economy:默认值,可能会将背景不打印
exact:精确打印
table{
-webkit-print-color-adjust: exact;
color-adjust: exact;
}
使该元素另起一页打印
break-before:page
性能优化
will-change
will-change
的作用有两个,一个是创建合成层,一个在真正的行为触发之前告诉浏览器:“我要变化了,你要做好准备”
如何正确的使用
will-change
不应该被设置在默认状态中且需要及时销毁,理想中的应用场景应该是 hover
状态下
// good
.will-change-parent:hover .will-change{
will-change:transform;
}
.will-change {
transition: transform 0.3s;
}
.will-change:hover {
transform: scale(1.5)
}
// bad
.will-change {
transition: transform 0.3s;
}
.will-change:hover{
will-change: transform;
transform: scale(1.5);
}
如果点击按钮,某个元素执行动画,先执行的是 mousedown
事件,之后执行的是 click
事件
dom.onmousedown = function() {
target.style.willChange = 'transform'
}
dom.onclick = function() {
// target元素执行动画
}
target.onanimationend = function() {
// 动画结束,用回调函数移除will-change属性
this.style.willChange = 'auto'
}
创建合成层
无法复制加载中的内容
- 合成层的位图会交由
GPU
合成,比CPU
处理要快得多 - 当需要
repaint
时,只需要repaint
本身,不会影响其他层 - 元素提升为合成层后,
transform
和opacity
不会触发repaint
,如果不是合成层则依旧会触发repaint
避免隐式创建合成层及优化
合成层比较占用内存,假如一个合成层的宽高为100px 100px,则合成层占用内存的计算方式为100100*3 = 30000Byte = 30KB
当元素交叠,处在下方的元素成为了合成层,上方的元素隐式变成了合成层
- 可以将必须合成层的层级提升至较高层级,则其他交叠层级没有该层级高就不会隐式创建合成层
- 动画使用
transform
实现,一方面如果不涉及到translateZ
则不会创建合成层,一方面生成层叠上下文不会影响到别的层叠上下文渲染 - 通过减少宽高再进行
scale
放大的方式可以有效减少合成层使用的内存
SEO
H1标签一个页面只能用一个
同一网页通过多个网址访问指定规范网址
<link rel="canonical" href="http://www.hunliji.com/merchant/detail_1378">
关键词
<meta data-hid="keywords" name="keywords" content="关键词1,关键词2">
详细描述
<meta data-hid="description" name="description" content="描述内容,字数在0-200字为佳">
不需要抓取的链接nofollow
<a href="www.baidu.com" rel="nofollow">
指定为外部链接external
<a href="www.baidu.com" rel="external nofollow">
指定页面图标
<link rel="icon" type="image/png" href="/path/to/icons/favicon-16x16.png" sizes="16x16">
<link rel="icon" type="image/png" href="/path/to/icons/favicon-32x32.png" sizes="32x32">
很少用的属性
将中文简体转换为繁体
苹方字体有效,老老实实做i18n吧哈哈
font-variant-east-asian: traditional;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。