分类
CSS

对层叠上下文内部显示顺序的理解

这篇文章不讲述层叠上下文之间的显示顺序,而是探究在一个父层叠上下文上,子元素的显示顺序(子元素不会产生新的层叠上下文)。相同的显示等级需要考虑先来后到原则。因此本次只考虑不同的显示等级,以背景色的方式。查看覆盖情况得出显示等级。

第一等

position为非static

第二等

display:inline/inline-block

flex容器的子项

第三等

float:left/right

第四等

display:block

冲突情况

当display:inline-block和float:left/right同时存在时,显示等级为第三等,是由于inline-block失效造成的。

父元素与子元素等级不同时的显示顺序

第一个:父元素第一等,子元素第四等。第二个父元素第四等,子元素第一等

第二个的子元素显示在第一个的子元素上方。

第一个:父元素第二等,子元素第四等。第二个父元素第四等,子元素第一等

第二个的子元素显示在第一个的子元素上方

第一个:父元素第二等,子元素第四等。第二个父元素第四等,子元素第三等

第一个的子元素显示在第二个的子元素上方

第一个:父元素第四等,子元素第一等。第二个父元素第一等,子元素第四等。

第二个的子元素显示在第二个子元素的上方

结论:子元素的显示等级由子元素本身和父元素的显示等级决定,如果子元素的显示等级比父元素的显示等级高,则子元素的显示等级为自身的显示等级,如果子元素的显示等级比父元素的显示等级低,则子元素的显示等级为该层叠上下文下,等级最高的父元素的显示等级。

分类
CSS javascript

超出一行标签内打点

在移动端中,屏幕的宽度通常会不足,在这样的宽度中可能要放下几个标签,这几个标签需要在一行内显示,标签数量不确定,标签内文字数量不确定。现要求是标签尽可能的往一行内放,如果放不下一个完整的标签,那么该标签会以打点的方式在一行的最后一个。

只有一个标签,字数超出一行打点

该标签只有需要最基础的overflow:hidden;white-space:nowrap;text-overflow:ellipsis;就能实现。

两个标签,字数超出一行打点

 .line-box {
        box-sizing: border-box;
        --column-gap: 4px;
        --text-wrap-padding: 4px;
        --text-wrap-border-radius: 4px;
        --text-font-size: 12px;
        --text-color: white;
        --text-background: blue;
        width: 100px;
        height: 40px;
        resize: horizontal;
        padding: 10px;
      }
      .w {
        display: flex;
        flex-wrap: wrap;
        overflow: hidden;
      }
      .tag {
        white-space: nowrap;
        text-overflow: ellipsis;
        /* 第一个作用是使打点生效,第二个作用是作为flex子元素使得在最小尺寸由最小内容宽度决定的时候使最小尺寸失效从而可以无视最小尺寸限制去缩放 */
        overflow: hidden;
        background-color: var(--text-background);
        margin: 0 calc(var(--column-gap) / 2);
        color: var(--text-color);
        font-size: var(--text-font-size);
        border-radius: var(--text-wrap-border-radius);
        padding: var(--text-wrap-padding);
        /* 使下方的tag超出容器高度隐藏 */
        margin-bottom: 50px;
      }
      .z {
        flex: 1;
        min-width: 30px;
        display: flex;
      }
      .f1 {
        flex: 1;
      }


<!-- 两个标签超过打点 -->
    <div class="line-box w">
      <div class="tag">第一个</div>
      <div class="z">
        <div class="tag">第二个</div>
        <div class="f1"></div>
      </div>
    </div>

首先要实现宽度超过一个标签,但是不超过两个标签时第一个标签不打点,第二个标签打点。因此第一个标签的宽度需要尽可能的不缩小,第二个标签缩小完之前不能缩小第一个标签。首先两个标签的容器是flex,flex-wrap:wrap是为了第二个标签缩小到一定程度可以换行。因此需要第一个标签的基础尺寸是标签的长度,最小尺寸是0,第二个标签的基础尺寸是0,最小尺寸是30px。并且可以占据除第一个标签外的所有空间。根据flex弹性伸缩规则,当容器的宽度大于子元素的基础尺寸之和,子元素不会出现宽度小于基础尺寸的情况。因此会出现先缩小基础尺寸是0的元素,当容器的宽度比基础尺寸小时,再根据弹性缩放规则是子元素的宽度缩放的比基础尺寸还小。由于第二个标签与第一个标签所拥有的属性应该是一致的,所以需要给第二个标签套一个容器来实现第二个标签所需要的额外功能。该容器就是z,z所具有的功能是让第二个标签占据除第一个标签外的所有宽度,且具有最小尺寸,如果小于最小尺寸,第二个标签会被换到下一行去,这样就看不见了。并且让第二个标签的基础尺寸是0(flex:1 = flex: 1 1 0%;),如果宽度足够宽第二个标签也不会占据太大宽度。因为标签本身的属性是基础宽度为不换行的文本宽度,且不会弹性扩大。

三个标签字数超过一行打点

<div class="line-box w">
      <div class="w">
        <div class="tag">第一个</div>
        <div class="z">
          <div class="tag">第二个</div>
        </div>
      </div>
      <div class="z">
        <div class="tag">第三个</div>
      </div>
    </div>

我们已经知道两个标签超过一行打点的方法。这个方法我们直接借用。那么还需要一个标签做成三个标签字数超过一行打点。由数学归纳法得,三个标签超过一行打点=两个标签超过一行打点+一个标签超过一行打点。因此还是需要一个容器,yoi容器的左侧是两个标签的容器,右侧是一个标签的容器。左侧的容器的基础宽度是两个标签不换行的宽度,右侧标签容器的基础宽度是0。因此右侧标签的实现与二个标签超出一行打点的第二个标签的实现是一致的。需要改变的是给两个标签超出一行打点加一个基础宽度是不换行宽度,最小尺寸是0,因此容器作为flex子元素,flex默认值就是0 1 auto。基础宽度是达标的。加入overflow:hidden是为了让最小尺寸变为0;加入flex-wrap:wrap;是为了保持原有的标签宽度太小就换行不显示的功能。

n个标签超过一行打点

现在我们已经找出规律

n个标签超过一行打点 = 容器w_line-box(容器w((n-1)个标签超出一行点) +容器z(标签) )

使用递归得

const fac = (n, arr) => {
        if (n <= 0) {
          return ''
        }
        if (n === 1) {
          return `<div class="w"><div class="tag">${arr[n]}</div></div>`
        }
        const len = arr.length
        return `<div class="w${n === len ? ' line-box' : ''}"><div class="w">${fac(
          n - 1,
          arr,
        )}</div><div class="z"><div class="tag">${arr[len - n]}</div></div></div>`
      }
      const arr = [
        '塑料科技',
        'sdkjfhdsf',
        '莱克斯顿',
        '塑料科技',
        'sdkjfhdsf',
        '莱克斯顿',
        '塑料科技',
        'sdkjfhdsf',
        '莱克斯顿',
      ]
      const fragment = document.createDocumentFragment()
      document.getElementById('container').innerHTML = fac(arr.length, arr)
分类
CSS

CSS语法解析系列~Background

background

background = [<bg-layer>#,]? <final-bg-layer>

<bg-layer>

bg-layer = <bg-img> || <bg-position> [ / <bg-size>]? || <repeat-style> || <attachment> || <box> || <box>

<final-bg-layer>

final-bg-layer= <background-color> || <bg-image> || <bg-position> [/ <bg-size>]? || <repeat-style> || <attachment> || <box> || <box>

<attachment>

这是背景图单独属性 background-attachment,它的默认值是scroll,表现为在根滚动条下,滚动的时候图片也会滚动,但是如果在元素中,这个背景就会固定住不会随内容滚动。这与local的区别是,local在元素中有滚动条的话,背景会随元素的内容滚动。还有一个值是fixed,它就像贴在根元素上一样,但是显示的大小还是根据元素决定,可以使用padding-top实现高度与宽度与图片比例一致,但总体来说整个可视区域的高度都可以显示到,在移动端适合高比宽大的图片background-size取100% auto,但是两侧显示不到。在PC端适合宽比高大的图片background-size取auto 100%,但是上下显示不全。这已是最大化显示内容的方案,我认为显示不全这一缺点也是这种技术不是非常流行的原因

<box>

box=border-box | padding-box | content-box

它的默认值为border-box,但是对于color来说,它确实是真正的border-box,但是对于图片来说它的初始值是padding-box。

它的属性值是background-clip,但是background-clip中还有一个text的属性,这个属性能够把背景裁剪到字体。

<bg-image>

<bg-image>=<image> | none

<image> = <url> | <gradient>

它的属性名叫做background-image,默认值是none

<bg-position>

它的属性名是background-position,默认值是0% 0%,

bg-position = [top | left | right | bottom | <length-percentage>]

| [left | center | right | <length-percentage>] [top | center | bottom | <length-percentage>]

| [center | [left | right] <length-percentage>] [center | [top | bottom] <length-percentage>]

这里可以找到一种不常用的用法,background-position:right 20px bottom 20px

<bg-size>

属性名是background-size,默认值 auto,代表源图片大小

bg-size=[<length-percentage [0,+无穷]> | auto]{1,2} | cover | contain

<repeat-style>

repeat-style的属性名是background-repeat,默认值是repeat

repeat-style = repeat-x | repeat-y | [repeat | no-repeat | round | space]{1,2}

当有两个值是第一个代表水平方向,第二个代表垂直方向

使用round,如果background-size是15% 15%,它铺六个是90%,铺七个是105,则会铺设7个然后缩小一点,并全部铺完。

如果background-size是16% 16%,它铺六个是96%,铺七个是112%,则他会铺六个,然后撑开一点。

使用space,保持原本的大小,会留出空隙

分类
CSS

CSS语法解析系列~mask-image

mask-image

mask-image = <mask-reference>#

#

标识1个或多个,如果是多个需要用逗号分割

mask-reference

mask-reference = none | <image> | <mask-source>

<image>

image = <url> | <gradient>

<gradient>

gradient = <linear-gradient()> | <repeating-linear-gradient()> | <radial-gradient()> | <repeating-radial-gradient()>

linear-gradient()

linear-gradient() = linear-gradient([angle | to <side or corner>]?, <color-stop-list>)

<color-stop-list>

color-stop-list = <linear-color-stop>,[<linear-color-hint>?,<linear-color-stop>]#

<linear-color-hint>

linear-color-hint = <length-percentage>

linear-color-hint的作用应该是延续上一段的颜色

repeating-linear-gradient()

属性值与linear-gradient相同,但是会循环

radial-gradient

radial-gradient() = radial-gradient([<ending-shape> || <size>]?[at <position>]?,<color-stop-list>)

<size>

closest-side

最近的边

farthest-side

最远的边

closest-corner

最近的角

farthest-corner

最远的角

分类
CSS

CSS语法解析系列~border-image

border-image = <‘border-image-source’> || <‘border-image-slice’> [ / <‘border-image-width’> | / <‘border-image-width’>? / <‘border-image-outset’> ]? || <‘border-image-repeat’>

||

或组合符,各部分必须出现一个但是可以不按顺序出现,比如说有三个,则最少要出现1个,在这个例子中,<border-image-source>和<border-image-slice>只要要有一个出现。

<>

尖括号内的东西叫做数据类型,它的作用是表明里面的东西是一个数据类型

[]

分组,通常需要使用限定词时会顺带使用分组,比如分组中的内容会同时出现一次或0次,则要在分组的右边加入?

|

互拆组合符,标识多个部分只能取一个

限定词,标识1个或0个

/

当出现该符号时说明左右两边具有相同或部分相同的数据结构,当然在简写时该符号是需要保留的,这是与其他大部分标识符的不同之处

<border-image-source>

border-image-source = none | <image>

<border-image-slice>

border-image-slice = [<number [0,∞]> | <percentage [0,∞]>]{1,4} && fill?

&&

各部分必须出现,但是可以不按顺序出现

<border-image-width>

border-image-width=[ <length-percentage [0,∞]> | <number [0,∞]> | auto ]{1,4}

其中border-image-slice与border-image-width在一起时是无法分清属性值是属于哪个属性的,所以border-image-width需要加上/

<border-image-outset>

border-image-outset=[ <length [0,∞]> | <number [0,∞]> ]{1,4}

该属性的属性值又与border-image-slice,border-image-width冲突所以可能会出现这样的border-image值

border-image:20% // 2px repeat

border-image-repeat

border-image-repeat = [ stretch | repeat | round | space ]{1,2}

分类
CSS 总结

css技术沉淀

基础理论

元素的显示与隐藏

根据不同的需求选择隐藏方案

如果希望元素不可见,同时不占据空间,辅助设备无法访问,同时不渲染,使用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造成影响

?code=NTM0ZWY4ZWFhYTIxMjY0Yzk5MTljNGJhZjBjZmU5NDVfMEdiYnF1emVmcGxNcERWTkloWmwxMUlKVVlJWmhCOUpfVG9rZW46Ym94Y254ZGFjOFc1aGNWQ0dvV1piUWx0T3hmXzE2NDQxMjA3MTM6MTY0NDEyNDMxM19WNA - css技术沉淀
?code=ZjgwMGMyYzY0MmYzMDFmOTNhNzVlMmUzN2ZkYTBkNTdfYTA2eGlYdzFpMzFZUThYdGRoekVnRGJBdjhvTlR6OVBfVG9rZW46Ym94Y25oTFlpMU1SUTRZWHJHWkdNTE1mQ2RlXzE2NDQxMjA3MTM6MTY0NDEyNDMxM19WNA - css技术沉淀

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:连续的空白符被合并,文本内的换行符无效(<br>有效) pre:连续的空白符会被保留,在遇到换行符或者<br>元素时才会换行 pre-wrap:连续的空白符会被保留,在遇到换行符或者<br>元素,或者为了填充行框盒子(line-box)时才会换行 pre-line:连续的空白符会被合并,在遇到换行符或者<br>元素,或者为了填充行框盒子(line-box)时才会换行

line-break

中文标点的换行规则,比如是避首标点,是避尾标点,通过此属性控制CJK文本标点的换行规则 auto:使用默认的换行规则。 loose: 使用限制性最小的换行规则分隔文本。通常用于短行,如在报纸上。 normal:使用最普通的换行规则。 strict: 使用最严格的换行规则。 anywhere:任意位置都可以作为换行点,包括任意的标点。

<wbr>

这是html元素,宽度不够,在我这里换行;宽度足够,还是一行显示

光标属性cursor

https://developer.mozilla.org/en-US/docs/Web/CSS/cursor

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元素的宽度,最多可以收缩至元素最小尺寸。

最终尺寸计算规则-总结

  • 如果没有弹性收缩或增长,则元素在最大尺寸和最小尺寸范围内使用基础尺寸
  • 如果元素能够弹性增长或收缩,在容器宽度足够的情况下使用弹性增长规则,在容器宽度不足的情况下使用弹性收缩规则,同一行只可能应用一种规则

选择器

选择器优先值计算

选择器计算值计算细则
* {}01个0级统配选择器,优先级数值为0
dialog {}11个1级标签选择器,优先级数值为1
ui > li {}22个1级标签选择器,1个0级选择器,优先级数值为2
li > ol + ol {}33个1级标签选择器,2个0级选择器,优先级数值为3
.foo {}101个2级类名选择器,优先级数值为10
a:not([rel=nofollow]) {}111个2级属性选择器,1个1级标签选择器,1个0级否定伪类,优先级数值为11
a:hover {}111个1级标签选择器,1个2级伪类,优先级数值为11
ol li.foo {}122个1级标签选择器,1个2级类名选择器,优先级数值为12
li.foo.bar {}211个1级标签选择器,2个2级类名选择器,优先级数值为21
#foo {}1001个3级ID选择器,优先级数值为100
#foo .bar p {}1111个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;
}

输入体验优化

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:被低估的一个属性值,设置了该属性的图文内容都会被选中,案例:点击内容复制全部内容,github的链接

?code=NjgzOTg4ZTFiNTE0N2EwZTllNDY1ZmI2NWUyMTQyN2VfRFo5OERxTFRqWEN5UldiU0d3a1FVQ0ZoNnU3UVhBNW9fVG9rZW46Ym94Y25NT0xpZjBRNjZhUUdqZG9HaWxSQk1oXzE2NDQxMjA3MTM6MTY0NDEyNDMxM19WNA - css技术沉淀

::selection

被选中时伪类,全局设置时可设置品牌颜色为背景,合适颜色为字体颜色

::selection {
    color: hunlijiColor;
    background: hunlijuBackgroundColor;
}

打印行为体验优化

控制打印样式的媒体查询

@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

查看合成层

?code=ODdmMWM5MzQzMzczYjY0ZmJhZmQ3OWVlOTY5Y2M0ODBfbHo2eVFtRVNHUDRuZXZkNTdXcHFTQ2ZUbUhNRWVndUxfVG9rZW46Ym94Y25Pb0xNRHR0RDhTc0lDOUs0SlVrWmhjXzE2NDQxMjA3MTM6MTY0NDEyNDMxM19WNA - css技术沉淀

避免隐式创建合成层及优化

合成层比较占用内存,假如一个合成层的宽高为100px * 100px,则合成层占用内存的计算方式为100*100*3 = 30000Byte = 30KB 当元素交叠,处在下方的元素成为了合成层,上方的元素隐式变成了合成层

?code=OTU5N2U1YTIzZmFjOTY4YzQyODNiMmI2OWMzZmIyZWJfWDhhaHFTMTZYNFRtZGZiVjV2ekxRcldiNU4wRllJNXVfVG9rZW46Ym94Y25rdjYyUXZNMzJsVE9KZXV5a2F4VklZXzE2NDQxMjA3MTM6MTY0NDEyNDMxM19WNA - css技术沉淀
  • 可以将必须合成层的层级提升至较高层级,则其他交叠层级没有该层级高就不会隐式创建合成层
  • 动画使用transform实现,一方面如果不涉及到translateZ则不会创建合成层,一方面生成层叠上下文不会影响到别的层叠上下文渲染
  • 通过减少宽高再进行scale放大的方式可以有效减少合成层使用的内存

很少用的属性

将中文简体转换为繁体

苹方字体有效,老老实实做i18n吧哈哈

font-variant-east-asian: traditional;
分类
CSS

合成层(CompositingLayer)

合成层带来的好处

  • 合成层的位图会交由GPU合成,比CPU处理要快得多
  • 当需要repaint时,只需要repaint本身,不会影响其他层
  • 元素提升为合成层后,transform和opacity不会触发repaint,如果不是合成层则依旧会触发repaint

合成层可能会带来的坏处

  • 绘制的图层必须传输到GPU,这些层的数量和大小达到一定量级后会导致传输非常慢,进而导致一些低端或中端设备上出现闪烁
  • 隐式合成,每个合成层都会占用额外的内存,使用过多内存会导致浏览器崩溃,从而导致性能优化适得其反

Chrome Devtools如何查看合成层

20220111 160129 - 合成层(CompositingLayer)

合成层与层叠上下文的关系及如何产生

20220111 163802 - 合成层(CompositingLayer)

合成层在层叠上下文的基础上创建

隐式创建的合成层-造成内存爆炸的原因

当元素交叠,处在下方的元素成为了合成层,上方的元素隐式变成了合成层

20220111 170814 - 合成层(CompositingLayer)
safari浏览器合成层现状,chrome浏览器会进行层压缩优化
 .x {
        width: 100px;
        height: 100px;
        background-color: red;
        position: absolute;
        will-change: opacity;
      }
      .y {
        width: 100px;
        height: 100px;
        margin: 50px 0 0 50px;
        background-color: blue;
        position: absolute;
        z-index: 1;
      }
<body>
  <div class="x"></div>
  <div class="y"></div>
      ...
  <div class="y"></div>
</body>

合成层优化

动画使用transform实现

一方面如果不涉及到translateZ则不会创建合成层,一方面生成层叠上下文不会影响到别的层叠上下文渲染

减少隐式合成创建

可以将必须合成层的层级提升至较高层级,则其他交叠层级没有该层级高就不会隐式创建合成层

减小合成层大小

通过减少宽高再进行scale放大的方式可以有效减少合成层使用的内存

分类
CSS

内联盒模型-关于line-box的探究(二)

探究一链接

本次内容:图片与文字同时存在时的渲染规则

灰色区域:line-box

背景1:文字行高:normal,fontSize:14px,图片宽500px,高10px

image - 内联盒模型-关于line-box的探究(二)

解析:图片是inline元素,他所处的底部与基线一致,基线是小写x的下方x端所处的位置,此时x的virsual area(x的line-height所占据空间)构成了line-box

背景2:文字行高:normal,fontSize:14px,图片宽500px,高40px

image 2 - 内联盒模型-关于line-box的探究(二)

解析:图片的基线是图片的底部,文字的基线是小写x的下端,此时内联元素中各个元素的基线不同,因此要找出一个公共的基线,于是让每个元素的content-area往顶部排列,图片的content-area高度为当前图片的高度,文字元素的content-area与font-size和font-family有关,与line-height无关,于是公共的基线为图片的底部,文字的基线需要与公共的基线重合。于是line-box由图片和文字共同组成

背景3:文字行高:0,fontSize:14px,图片宽500px,高10px

image 3 - 内联盒模型-关于line-box的探究(二)

解析:由背景二的解析可知,现在公共的基线是x元素下端,而x没有content-area,图片的content-area为10px,line-box由图片决定

背景4:文字行高:0,fontSize:100px,图片宽500px,高10px

image 4 - 内联盒模型-关于line-box的探究(二)

解析:x没有content-area但line-box还是变大了,这是由于x字体比较大时,字体的content-area的中线也会参与到line-box的构建中,因此line-box变大了

背景5:文字行高:0,fontSize:100px,图片宽500px,高10px但是不放文字

image 5 - 内联盒模型-关于line-box的探究(二)

解析:图片的外层是div块状和模型,里面只有img一个元素,当块状盒模型内部有内联元素时会自动创建一个幽灵子节点,相当于在内部添加了一个没有宽度的x,会影响line-box

总结

  1. 图片的基线是图片的底部,与公共的基线平齐(vertical-align会影响)
  2. 文字的基线和content-area的中线都会参与到line-box的构建中去
  3. line-box就是内联盒模型的文档流占据的空间
  4. 在盒模型中存在内联元素会自动创建幽灵子节点
分类
CSS

grid布局细节

grid-auto-flow和grid中的auto-flow

grid-auto-flow:流动方向,可以设定row或column,类似于flex-direction。

auto-flow:可以在grid中设置缩写

gird: <grid-template-rows> / [auto-flow && dense?] <grid-auto-columns>
grid: <auto-flow && dense?> <grid-auto-rows> / <grid-template-rows>

在左侧说明是row,在右侧说明是column,与grid-auto-flow有相同的作用。

例如

grid:auto-flow dense 300px/200px 1fr

上述代码说明有两列为200px和1fr,然后稠密的向下流动,只有匿名单元格,匿名单元格的高度为300px。

grid-column-start

计数以1开始,包括边缘线,就是说如果水平有6块,则计数可以从1~7,可以是负数-1是右侧边缘线,可以从-7~-1

grid-column-start 与 grid-column-end 不需要考虑前者的数字比后者大或小。

分类
CSS

内联盒模型-关于line-box的探究(多图预警)

涉及到内联盒模型,应该是css世界中最复杂,最难以理解的模型,本次仅仅探索涉及到内联盒模型的line-box的一些让人难以理解的现象,找到本质原因之后一定会让你足够惊喜。

参考文献(理论基础):https://www.cnblogs.com/10yearsmanong/p/13084706.html

首先看例子

qi ye wei xin jie tu 16145161258073 - 内联盒模型-关于line-box的探究(多图预警)

html

<body>
<div class="z"></div>
<div class="x">
    <span class="a">x</span>
    <span class="b">哇</span>
    <span class="c">移</span>
</div>
<div class="y"></div>
</body>

css

 .z{
            height:100px;
            background:yellow;
        }
        .x{
            font-size:0;
            line-height:0;
        }
        .a{
            font-size:200px;
        }
        .b{
            display: inline-block;
            font-size:20px;
        }
        .c{
            font-size:20px;
        }
        .y{
            height:10px;
            background-color: red;
        }

问题1:line-box是哪个区块?

是红色与黄色之间的白色块,我们可以通过定义证明,vertical-align:top/bottom的定义为与line-box的顶部或底部对齐。于是我们设置.b与.c的vertical-align分别为top和bottom。

qi ye wei xin jie tu 16145168104716 - 内联盒模型-关于line-box的探究(多图预警)

我们确实能够看到‘哇’和‘移’在白色块的上边和下边,但为什么是两字的中间对齐line-box的上边缘与下边缘呢?

问题2:为什么是‘哇’字中间对齐上边缘?

首先我们可以看到‘哇’对应的属性是line-height:0;font-size:20;这个line-height为什么是0呢,就要从该属性说起,line-height是可以继承的,当它是数字的时候,子元素继承的也是数字,当它是百分比或者说数值(12px,1em,1rem,等)它会根据当前font-size的大小计算得出一个具体值然后继承下去(比如font-size:20px;line-height:200%,继承下去的是line-heignt:40px;),因此‘哇’的visual-area的顶部对齐了line-box的顶部。

问题3:什么是visual-area?

就是该内联元素的line-height,既然有了visual-area那就引申出content-area。

3720408019 5a3b79af7559e articlex - 内联盒模型-关于line-box的探究(多图预警)
1496711390 5a3b79b00736d articlex - 内联盒模型-关于line-box的探究(多图预警)

以Baseline基线为0,content-area=fontSize*(ascender-descender+lineGap)/emSquare

其中ascender,descender,lineGap是一款字体定义的属性。

137665312 5a3b79af2f6be articlex - 内联盒模型-关于line-box的探究(多图预警)

基于此line-height:normal也可以计算

line-height:normal=(ascender-descender+lineGap)/emSquare。

因此我们知道content-area只会受font-family和font-size影响。当visual-area大于content-area时,会产生leding,1/2的leading分别加到content-area的上方与下方所以content-area总是处于visual-area中间,当visual-area为0时(line-height:0)就能看到‘哇’字的中间处于line-box上边缘。

问题4:line-box是如何产生的?

首先内联盒模型会产生line-box,它的触发条件时块状盒子内部只有内联元素(inline-block也算)。

问题5:为什么白色区块是line-box?

qi ye wei xin jie tu 16145161258073 - 内联盒模型-关于line-box的探究(多图预警)

首先我们得了解line-box的意义,它决定了一行内联元素所占据文档流的高度,若超出一行,则会重新生成一行line-box。所以每一行line-box的高度可能是不同的。每一行line-box会生成一个宽度为0,font-size为父元素font-size的幽灵子节点(strut)。

要解决这个问题,首先要知道base-line的位置是由什么决定的。

问题6:base-line的位置由什么决定?

若只有一个元素,base-line的位置由ascender与descender共同决定(小写x底部位置),若有多个元素,则由最下方的base-line决定

qi ye wei xin jie tu 16145210404958 - 内联盒模型-关于line-box的探究(多图预警)

首先‘x’,‘哇’,‘移’的line-height均为0,因此他们的实际高度也为0,于是从黄色块下边缘依次排布,content-area在中间位置,得出base-line为‘x’的x下边缘(在所有base-line的最下方)。

而base-line是所有的内联元素共同决定的。它是怎么得出的呢?看下图。

qi ye wei xin jie tu 16145221431830 - 内联盒模型-关于line-box的探究(多图预警)
多个元素决定line-box高度

也许有小伙伴对x的line-height所处位置存疑,请看下图。

qi ye wei xin jie tu 16145225721799 - 内联盒模型-关于line-box的探究(多图预警)
qi ye wei xin jie tu 16145226212275 - 内联盒模型-关于line-box的探究(多图预警)

2021/03/01更新

我们基于最开始的代码,进行一点变更继续探索,首先变更的地方为

  .x{
            font-size:1px;
        }
qi ye wei xin jie tu 16145637328073 - 内联盒模型-关于line-box的探究(多图预警)

问题7:红块为什么会上移?

首先我们将.x元素的font-size设置为1px后,我们在chrome上进行调试,chrome的font-size在1-12px之间时,统一为12px。因此可以有这样一张图。

qi ye wei xin jie tu 16145641934716 - 内联盒模型-关于line-box的探究(多图预警)

因为幽灵字节的的font-size从0上升至12px,因此幽灵字节点的line-height位置由在baseline处往上抬了当前字体在12px时所生成的该x的baseline到该x的1/2content-area的距离。因为在目前line-box中还是幽灵子节点的font-size最小,因此还是取幽灵子节点的line-height位置为最下方,并生成line-box。

问题8:transform对内联元素的影响?

transform属性对display:inline的元素无任何作用,对inline-block的元素有样式上的影响,但对他本身占据的文档流的位置和大小无任何影响。

qi ye wei xin jie tu 16145659814958 1024x403 - 内联盒模型-关于line-box的探究(多图预警)

问题9:vertical-align:text-top/text-bottom对齐的是谁。

幽灵子节点的content-area。以下是证明

qi ye wei xin jie tu 16145665543453 1024x555 - 内联盒模型-关于line-box的探究(多图预警)
qi ye wei xin jie tu 16145666932449 1024x484 - 内联盒模型-关于line-box的探究(多图预警)

问题10:vertical-align:text-top/text-bottom与line-height有关吗?

无关,以下是证明

qi ye wei xin jie tu 16145687882171 1024x484 - 内联盒模型-关于line-box的探究(多图预警)

问题11:为何经过上方设置后,line-box变这么大?

  • 通过各元素的content-area比较得出最下方的baseline为最大的X(幽灵子节点content-area为0)
  • 幽灵子节点加入战场,它的line-height为200px,所处位置为baseline处,但它的visual-area比其他子元素都要大于是由它决定了line-box
qi ye wei xin jie tu 16145692985085 1024x410 - 内联盒模型-关于line-box的探究(多图预警)

问题12:inline-block对line-box有何影响?

inline-block元素的padding,margin,border,height共同组成content-area,inline-block的content-area等于visual-area。