每天10个前端小知识 <Day 18>

前端面试基础知识题

1.如何实现单行/多行文本溢出的省略样式?

在日常开发展示页面,如果一段文本的数量过长,受制于元素宽度的因素,有可能不能完全显示,为了提高用户的使用体验,这个时候就需要我们把溢出的文本显示成省略号
对于文本的溢出,我们可以分成两种形式:

  • 单行文本溢出
  • 多行文本溢出
实现方式

单行文本溢出省略

理解也很简单,即文本在一行内显示,超出部分以省略号的形式展现
实现方式也很简单,涉及的css属性有:

  • text-overflow:规定当文本溢出时,显示省略符号来代表被修剪的文本
  • white-space:设置文字在一行显示,不能换行
  • overflow:文字长度超出限定宽度,则隐藏超出的内容

overflow设为hidden,普通情况用在块级元素的外层隐藏内部溢出元素,或者配合下面两个属性实现文本溢出省略

white-space:nowrap,作用是设置文本不换行,是overflow:hiddentext-overflow:ellipsis生效的基础

text-overflow属性值有如下:

  • clip:当对象内文本溢出部分裁切掉
  • ellipsis:当对象内文本溢出时显示省略标记(…)

text-overflow只有在设置了overflow:hiddenwhite-space:nowrap才能够生效的

举个例子

<style>
    p{
        overflow: hidden;
        line-height: 40px;
        width:400px;
        height:40px;
        border:1px solid red;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
</style>
<p 这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本</p >

效果如下:

img

可以看到,设置单行文本溢出较为简单,并且省略号显示的位置较好

多行文本溢出省略

多行文本溢出的时候,我们可以分为两种情况:

  • 基于高度截断
  • 基于行数截断

基于高度截断

伪元素 + 定位

核心的css代码结构如下:

  • position: relative:为伪元素绝对定位
  • overflow: hidden:文本溢出限定的宽度就隐藏内容)
  • position: absolute:给省略号绝对定位
  • line-height: 20px:结合元素高度,高度固定的情况下,设定行高, 控制显示行数
  • height: 40px:设定当前元素高度
  • ::after {} :设置省略号样式

代码如下所示:

<style>
    .demo {
        position: relative;
        line-height: 20px;
        height: 40px;
        overflow: hidden;
    }
    .demo::after {
        content: "...";
        position: absolute;
        bottom: 0;
        right: 0;
        padding: 0 20px 0 10px;
    }
</style>

<body>
    <div class='demo'>这是一段很长的文本</div>
</body>

实现原理很好理解,就是通过伪元素绝对定位到行尾并遮住文字,再通过 overflow: hidden 隐藏多余文字

这种实现具有以下优点:

  • 兼容性好,对各大主流浏览器有好的支持
  • 响应式截断,根据不同宽度做出调整

一般文本存在英文的时候,可以设置word-break: break-all使一个单词能够在换行时进行拆分

基于行数截断

css实现也非常简单,核心的css代码如下:

  • -webkit-line-clamp: 2:用来限制在一个块元素显示的文本的行数,为了实现该效果,它需要组合其他的WebKit属性)
  • display: -webkit-box:和1结合使用,将对象作为弹性伸缩盒子模型显示
  • -webkit-box-orient: vertical:和1结合使用 ,设置或检索伸缩盒对象的子元素的排列方式
  • overflow: hidden:文本溢出限定的宽度就隐藏内容
  • text-overflow: ellipsis:多行文本的情况下,用省略号“…”隐藏溢出范围的文本
<style>
    p {
        width: 400px;
        border-radius: 1px solid red;
        -webkit-line-clamp: 2;
        display: -webkit-box;
        -webkit-box-orient: vertical;
        overflow: hidden;
        text-overflow: ellipsis;
    }
</style>
<p>
    这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本
    这是一些文本这是一些文本这是一些文本这是一些文本这是一些文本
</p >

可以看到,上述使用了webkitCSS属性扩展,所以兼容浏览器范围是PC端的webkit内核的浏览器,由于移动端大多数是使用webkit,所以移动端常用该形式

需要注意的是,如果文本为一段很长的英文或者数字,则需要添加word-wrap: break-word属性

还能通过使用javascript实现配合css,实现代码如下所示:

css结构如下:

p {
    position: relative;
    width: 400px;
    line-height: 20px;
    overflow: hidden;

}
.p-after:after{
    content: "..."; 
    position: absolute; 
    bottom: 0; 
    right: 0; 
    padding-left: 40px;
    background: -webkit-linear-gradient(left, transparent, #fff 55%);
    background: -moz-linear-gradient(left, transparent, #fff 55%);
    background: -o-linear-gradient(left, transparent, #fff 55%);
    background: linear-gradient(to right, transparent, #fff 55%);
}

javascript代码如下:

$(function(){
 //获取文本的行高,并获取文本的高度,假设我们规定的行数是五行,那么对超过行数的部分进行限制高度,并加上省略号
   $('p').each(function(i, obj){
        var lineHeight = parseInt($(this).css("line-height"));
        var height = parseInt($(this).height());
        if((height / lineHeight) >3 ){
            $(this).addClass("p-after")
            $(this).css("height","60px");
        }else{
            $(this).removeClass("p-after");
        }
    });
})

2.flexbox(弹性盒布局模型)是什么,适用什么场景?

Flexible Box` 简称 `flex`,意为”弹性布局”,可以简便、完整、响应式地实现各种页面布局 
 采用Flex布局的元素,称为`flex`容器`container` 
 它的所有子元素自动成为容器成员,称为`flex`项目`item

img 容器中默认存在两条轴,主轴和交叉轴,呈90度关系。项目默认沿主轴排列,通过flex-direction来决定主轴的方向
每根轴都有起点和终点,这对于元素的对齐非常重要

属性

关于flex常用的属性,我们可以划分为容器属性和容器成员属性

容器属性有:

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content

flex-direction

决定主轴的方向(即项目的排列方向)

.container {   
    flex-direction: row | row-reverse | column | column-reverse;  
} 

属性对应如下:

  • row(默认值):主轴为水平方向,起点在左端
  • row-reverse:主轴为水平方向,起点在右端
  • column:主轴为垂直方向,起点在上沿。
  • column-reverse:主轴为垂直方向,起点在下沿

如下图所示:

img

flex-wrap

弹性元素永远沿主轴排列,那么如果主轴排不下,通过flex-wrap决定容器内项目是否可换行

.container {  
    flex-wrap: nowrap | wrap | wrap-reverse;
}  

属性对应如下:

  • nowrap(默认值):不换行
  • wrap:换行,第一行在上方
  • wrap-reverse:换行,第一行在下方

默认情况是不换行,但这里也不会任由元素直接溢出容器,会涉及到元素的弹性伸缩

flex-flow

flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

.box {
  flex-flow: <flex-direction> || <flex-wrap>;
}

justify-content

定义了项目在主轴上的对齐方式

.box {
    justify-content: flex-start | flex-end | center | space-between | space-around;
}

属性对应如下:

  • flex-start(默认值):左对齐
  • flex-end:右对齐
  • center:居中
  • space-between:两端对齐,项目之间的间隔都相等
  • space-around:两个项目两侧间隔相等

效果图如下:

img

align-items

定义项目在交叉轴上如何对齐

.box {
  align-items: flex-start | flex-end | center | baseline | stretch;
}

属性对应如下:

  • flex-start:交叉轴的起点对齐
  • flex-end:交叉轴的终点对齐
  • center:交叉轴的中点对齐
  • baseline: 项目的第一行文字的基线对齐
  • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度

align-content

定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用

.box {
    align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

属性对应如吓:

  • flex-start:与交叉轴的起点对齐
  • flex-end:与交叉轴的终点对齐
  • center:与交叉轴的中点对齐
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍
  • stretch(默认值):轴线占满整个交叉轴

效果图如下:

img

容器成员属性如下:

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self

order

定义项目的排列顺序。数值越小,排列越靠前,默认为0

.item {
    order: <integer>;
}

flex-grow

上面讲到当容器设为flex-wrap: nowrap;不换行的时候,容器宽度有不够分的情况,弹性元素会根据flex-grow来决定

定义项目的放大比例(容器宽度>元素总宽度时如何伸展)

默认为0,即如果存在剩余空间,也不放大

.item {
    flex-grow: <number>;
}

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)

img

如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍

img

弹性容器的宽度正好等于元素宽度总和,无多余宽度,此时无论flex-grow是什么值都不会生效

flex-shrink

定义了项目的缩小比例(容器宽度<元素总宽度时如何收缩),默认为1,即如果空间不足,该项目将缩小

.item {
    flex-shrink: <number>; /* default 1 */
}

如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小
如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小

img

在容器宽度有剩余时,flex-shrink也是不会生效的

flex-basis

设置的是元素在主轴上的初始尺寸,所谓的初始尺寸就是元素在flex-growflex-shrink生效前的尺寸
浏览器根据这个属性,计算主轴是否有多余空间,默认值为auto,即项目的本来大小,如设置了width则元素尺寸由width/height决定(主轴方向),没有设置则由内容决定

.item {
   flex-basis: <length> | auto; /* default auto */
}

当设置为0的是,会根据内容撑开
它可以设为跟widthheight属性一样的值(比如350px),则项目将占据固定空间

flex

flex属性是flex-grow, flex-shrinkflex-basis的简写,默认值为0 1 auto,也是比较难懂的一个复合属性

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

一些属性有:

  • flex: 1 = flex: 1 1 0%
  • flex: 2 = flex: 2 1 0%
  • flex: auto = flex: 1 1 auto
  • flex: none = flex: 0 0 auto,常用于固定尺寸不伸缩

flex:1flex:auto 的区别,可以归结于flex-basis:0flex-basis:auto的区别

当设置为0时(绝对弹性元素),此时相当于告诉flex-growflex-shrink在伸缩的时候不需要考虑我的尺寸
当设置为auto时(相对弹性元素),此时则需要在伸缩时将元素尺寸纳入考虑
注意:建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值

align-self

允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性
默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch

.item {
    align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

效果图如下:

img

应用场景

在以前的文章中,我们能够通过flex简单粗暴的实现元素水平垂直方向的居中,以及在两栏三栏自适应布局中通过flex完成,这里就不再展开代码的演示
包括现在在移动端、小程序这边的开发,都建议使用flex进行布局

3.em/px/rem/vh/vw 这些单位有什么区别?

传统的项目开发中,我们只会用到px%em这几个单位,它可以适用于大部分的项目开发,且拥有比较良好的兼容性
CSS3开始,浏览器对计量单位的支持又提升到了另外一个境界,新增了remvhvwvm等一些新的计量单位
利用这些新的单位开发出比较良好的响应式页面,适应多种不同分辨率的终端,包括移动设备等

单位

css单位中,可以分为长度单位、绝对单位,如下表所指示

CSS单位
相对长度单位em、ex、ch、rem、vw、vh、vmin、vmax、%
绝对长度单位cm、mm、in、px、pt、pc

这里我们主要讲述px、em、rem、vh、vw

px

px,表示像素,所谓像素就是呈现在我们显示器上的一个个小点,每个像素点都是大小等同的,所以像素为计量单位被分在了绝对长度单位中
有些人会把px认为是相对长度,原因在于在移动端中存在设备像素比,px实际显示的大小是不确定
这里之所以认为px为绝对单位,在于px的大小和元素的其他属性无关

em

em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸(1em = 16px
为了简化 font-size 的换算,我们需要在css中的 body 选择器中声明font-size= 62.5%,这就使 em 值变为 16px*62.5% = 10px
这样 12px = 1.2em, 10px = 1em, 也就是说只需要将你的原来的 px 数值除以 10,然后换上 em 作为单位就行了

特点:

  • em 的值并不是固定的
  • em 会继承父级元素的字体大小
  • em 是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸
  • 任意浏览器的默认字体高都是 16px

举个例子

<div class="big">
    我是14px=1.4rem
    <div class="small">我是12px=1.2rem</div>
</div>

样式为

<style>
html {font-size: 10px;  } /*  公式16px*62.5%=10px  */  
.big{font-size: 1.4rem}
.small{font-size: 1.2rem}
</style>

这时候.big元素的font-size为14px,而.small元素的font-size为12px

rem

rem,相对单位,相对的只是HTML根元素font-size的值
同理,如果想要简化font-size的转化,我们可以在根元素html中加入font-size: 62.5%

html {font-size: 62.5%;  } /*  公式16px*62.5%=10px  */ 

这样页面中1rem=10px、1.2rem=12px、1.4rem=14px、1.6rem=16px;使得视觉、使用、书写都得到了极大的帮助

特点:

  • rem单位可谓集相对大小和绝对大小的优点于一身
  • 和em不同的是rem总是相对于根元素,而不像em一样使用级联的方式来计算尺寸

vh、vw

vw ,就是根据窗口的宽度,分成100等份,100vw就表示满宽,50vw就表示一半宽。(vw 始终是针对窗口的宽),同理,vh则为窗口的高度
这里的窗口分成几种情况:

  • 在桌面端,指的是浏览器的可视区域
  • 移动端指的就是布局视口

vwvh,比较容易混淆的一个单位是%,不过百分比宽泛的讲是相对于父元素:
对于普通定位元素就是我们理解的父元素

  • 对于position: absolute;的元素是相对于已定位的父元素
  • 对于position: fixed;的元素是相对于 ViewPort(可视窗口)
总结

px:绝对单位,页面按精确像素展示

em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算,整个页面内1em不是一个固定的值

rem:相对单位,可理解为root em, 相对根节点html的字体大小来计算

vh、vw:主要用于页面视口大小布局,在页面布局上更加方便简单

4.CSS 垂直居中有哪些实现方式?

我们在布局一个页面时,通常都会用到水平居中和垂直居中,处理水平居中很好处理,不外乎就是设定margin:0 auto;或是text-align:center;,就可以轻松解决掉水平居中的问题,但一直以来最麻烦对齐问题就是「垂直居中」,以下将介绍几种单纯利用CSS垂直居中的方式,只需要理解背后的原理就可以轻松应用。

下面为公共代码:

<div class="box">
    <div class="small">small</div>
</div>

.box {
    width: 300px;
    height: 300px;
    background: #ddd;
}
.small {
    background: red;
}

absolute + margin实现

方法一:

.box {
    position: relative;
}
.small {
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -50px 0 0 -50px;
    width: 100px;
    height: 100px;
}

方法二:

.box {
    position: relative;
}
.small {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    margin: auto;
    width: 100px;
    height: 100px;
}

absolute + calc 实现

.box {
    position: relative;
}
.small {
    position: absolute;
    top: calc(50% - 50px);
    left: calc(50% - 50px);
    width: 100px;
    height: 100px;
}

absolute + transform 实现

.box {
    position: relative;
}
.small {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate3d(-50%,-50%,0);
    width: 100px;
    height: 100px;
}

转行内元素

.box {
    line-height: 300px;
    text-align: center;
    font-size: 0px;
}
.small {
    padding: 6px 10px;
    font-size: 16px;
    display: inline-block;
    vertical-align: middle;
    line-height: 16px;
}

table-cell

.box {
    display: table-cell;
    text-align: center;
    vertical-align: middle;
}
.small {
    padding: 6px 10px;
    display: inline-block;
}

flex

方法一:

.box {
    display: flex;
    justify-content: center;
    align-items: center;
}

方法二:

.box {
    display: flex;
    justify-content: center;
}
.small {
    align-self: center;
}

08 grid

网格布局(Grid)是最强大的 CSS 布局方案。

它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局。以前,只能通过复杂的 CSS 框架达到的效果,现在浏览器内置了。

下面是4种使用grid实现水平垂直居中的例子。

方法一:

.box {
    display: grid;
    justify-items: center;
    align-items: center;
}

方法二:

.box {
    display: grid;
}
.small {
    justify-self: center;
    align-self: center;
}

方法三:

.box {
    display: grid;
    justify-items: center;
}
.small {
    align-self: center;
}

方法四:

.box {
    display: grid;
    align-items: center;
}
.small {
    justify-self: center;
}

5.css加载会造成阻塞吗?

先说下结论:

  • css加载不会阻塞DOM树的解析
  • css加载会阻塞DOM树的渲染
  • css加载会阻塞后面js语句的执行

为了避免让用户看到长时间的白屏时间,我们应该尽可能的提高css加载速度,比如可以使用以下几种方法:

  • 使用CDN(因为CDN会根据你的网络状况,替你挑选最近的一个具有缓存内容的节点为你提供资源,因此可以减少加载时间)
  • 对css进行压缩(可以用很多打包工具,比如webpack,gulp等,也可以通过开启gzip压缩)
  • 合理的使用缓存(设置cache-control,expires,以及E-tag都是不错的,不过要注意一个问题,就是文件更新后,你要避免缓存而带来的影响。其中一个解决防范是在文件名字后面加一个版本号)
  • 减少http请求数,将多个css文件合并,或者是干脆直接写成内联样式(内联样式的一个缺点就是不能缓存)

原理解析

浏览器渲染的流程如下:

  • HTML解析文件,生成DOM Tree,解析CSS文件生成CSSOM Tree
  • 将Dom Tree和CSSOM Tree结合,生成Render Tree(渲染树)
  • 根据Render Tree渲染绘制,将像素渲染到屏幕上。

从流程我们可以看出来:

  • DOM解析和CSS解析是两个并行的进程,所以这也解释了为什么CSS加载不会阻塞DOM的解析。
  • 然而,由于Render Tree是依赖于DOM Tree和CSSOM Tree的,所以他必须等待到CSSOM Tree构建完成,也就是CSS资源加载完成(或者CSS资源加载失败)后,才能开始渲染。因此,CSS加载是会阻塞Dom的渲染的。
  • 由于js可能会操作之前的Dom节点和css样式,因此浏览器会维持html中css和js的顺序。因此,样式表会在后面的js执行前先加载执行完毕。所以css会阻塞后面js的执行。

6.怎么触发BFC,BFC有什么应用场景?

文档流

在介绍BFC之前,需要先给大家介绍一下文档流。
我们常说的文档流其实分为定位流浮动流普通流三种。

绝对定位(Absolute positioning)

如果元素的属性 positionabsolutefixed,它就是一个绝对定位元素。
在绝对定位布局中,元素会整体脱离普通流,因此绝对定位元素不会对其兄弟元素造成影响,而元素具体的位置由绝对定位的坐标决定。
它的定位相对于它的包含块,相关CSS属性:topbottomleftright
对于 position: absolute,元素定位将相对于上级元素中最近的一个relative、fixed、absolute,如果没有则相对于body;
对于 position:fixed,正常来说是相对于浏览器窗口定位的,但是当元素祖先的 transform 属性非 none 时,会相对于该祖先进行定位

浮动 (float)

在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。

普通流 (normal flow)

普通流其实就是指BFC中的FC。FC(Formatting Context),直译过来是格式化上下文,它是页面中的一块渲染区域,有一套渲染规则,决定了其子元素如何布局,以及和其他元素之间的关系和作用。
在普通流中,元素按照其在 HTML 中的先后位置至上而下布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行。块级元素则会被渲染为完整的一个新行。
除非另外指定,否则所有元素默认都是普通流定位,也可以说,普通流中元素的位置由该元素在 HTML 文档中的位置决定。

BFC 概念

先看下MDN上关于BFC的定义:

块格式化上下文(Block Formatting ContextBFC) 是Web页面的可视CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。

具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。
通俗一点来讲,可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。

除了 BFC,还有:

  • IFC(行级格式化上下文)- inline 内联
  • GFC(网格布局格式化上下文)- display: grid
  • FFC(自适应格式化上下文)- display: flexdisplay: inline-flex

注意:同一个元素不能同时存在于两个 BFC 中。

BFC的触发方式

MDN上对于BFC的触发条件写的很多,总结一下常见的触发方式有(只需要满足一个条件即可触发 BFC 的特性):

  • 根元素,即 <html>
  • 浮动元素:float 值为 leftright
  • overflow 值不为 visible,即为 autoscrollhidden
  • display 值为 inline-blocktable-celltable-captiontableinline-tableflexinline-flexgridinline-grid
  • 绝对定位元素:position 值为 absolutefixed

BFC的特性

  • BFC 是页面上的一个独立容器,容器里面的子元素不会影响外面的元素。
  • BFC 内部的块级盒会在垂直方向上一个接一个排列
  • 同一 BFC 下的相邻块级元素可能发生外边距折叠,创建新的 BFC 可以避免外边距折叠
  • 每个元素的外边距盒(margin box)的左边与包含块边框盒(border box)的左边相接触(从右向左的格式的话,则相反),即使存在浮动
  • 浮动盒的区域不会和 BFC 重叠
  • 计算 BFC 的高度时,浮动元素也会参与计算

应用

  • 自适应两列布局
  • 防止外边距(margin)重叠
  • 父子元素的外边距重叠
  • 清除浮动解决令父元素高度坍塌的问题

具体描述请点击此链接

7.为何CSS不支持父选择器?

这个问题的答案和“为何CSS相邻兄弟选择器只支持后面的元素,而不支持前面的兄弟元素?”是一样的。

浏览器解析HTML文档,是从前往后,由外及里的。所以,我们时常会看到页面先出现头部然后主体内容再出现的加载情况。

但是,如果CSS支持了父选择器,那就必须要页面所有子元素加载完毕才能渲染HTML文档,因为所谓“父选择器”,就是后代元素影响祖先元素,如果后代元素还没加载处理,如何影响祖先元素的样式?于是,网页渲染呈现速度就会大大减慢,浏览器会出现长时间的白板。加载多少HTML就可以渲染多少HTML,在网速不是很快的时候,就显得尤为的必要。比方说你现在看的这篇文章,只要文章内容加载出来就可以了,就算后面的广告脚本阻塞了后续HTML文档的加载,我们也是可以阅读和体验。但是,如果支持父选择器,则整个文档不能有阻塞,页面的可访问性则要大大降低。

有人可能会说,要不采取加载到哪里就渲染到哪里的策略?这样子问题更大,因为会出现加载到子元素的时候,父元素本来渲染的样式突然变成了另外一个样式的情况,体验非常不好。

“相邻选择器只能选择后面的元素”也是一样的道理,不可能说后面的HTML加载好了,还会影响前面HTML的样式。

所以,从这一点来讲,CSS支持“父选择器”或者“前兄弟选择器”的可能性要比其他炫酷的CSS特性要低,倒不是技术层面,而是CSS和HTML本身的渲染机制决定的。当然,以后的事情谁都说不准,说不定以后网速都是每秒几个G的,网页加载速度完全就忽略不计,说不定就会支持了。

8.js和css是如何影响DOM树构建的?

先做个总结,然后再进行具体的分析:

CSS不会阻塞DOM的解析,但是会影响JAVAScript的运行,javaSscript会阻止DOM树的解析,最终css(CSSOM)会影响DOM树的渲染,也可以说最终会影响渲染树的生成。

接下来我们先看javascript对DOM树构建和渲染是如何造成影响的,分成三种类型来讲解:

JavaScript脚本在html页面中

<html>
  <body>
    <div>1</div>
    <script>
      let div1 = document.getElementsByTagName('div')[0]
      div1.innerText = 'time.geekbang'
    </script>
    <div>test</div>
  </body>
</html>

两段div中间插入一段JavaScript脚本,这段脚本的解析过程就有点不一样了。

当解析到script脚本标签时,HTML解析器暂停工作,javascript引擎介入,并执行script标签中的这段脚本。

因为这段javascript脚本修改了DOM中第一个div中的内容,所以执行这段脚本之后,div节点内容已经修改为time.geekbang了。脚本执行完成之后,HTML解析器回复解析过程,继续解析后续的内容,直至生成最终的DOM。

html页面中引入javaScript文件

//foo.js
let div1 = document.getElementsByTagName('div')[0]
div1.innerText = 'time.geekbang'

<html>
  <body>
    <div>1</div>
    <script type="text/javascript" src='foo.js'></script>
    <div>test</div>
  </body>
</html>

这段代码的功能还是和前面那段代码是一样的,只是把内嵌JavaScript脚本修改成了通过javaScript文件加载。

其整个执行流程还是一样的,执行到JAVAScript标签时,暂停整个DOM的解析,执行javascript代码,不过这里执行javascript时,需要现在在这段代码。这里需要重点关注下载环境,因为javascript文件的下载过程会阻塞DOM解析,而通常下载又是非常耗时的,会受到网络环境、javascript文件大小等因素的影响。

优化机制:

谷歌浏览器做了很多优化,其中一个主要的优化就是预解析操作。当渲染引擎收到字节流之后,会开启一个预解析线程,用来分析HTML文件中包含的JavaScript、CSS等相关文件,解析到相关文件之后,会开启一个预解析线程,用来分析HTML文件中包含的javascprit、css等相关文件、解析到相关文件之后,预解析线程会提前下载这些文件。

再回到 DOM 解析上,我们知道引入 JavaScript 线程会阻塞 DOM,不过也有一些相关的策略来规避,比如使用 CDN 来加速 JavaScript 文件的加载,压缩 JavaScript 文件的体积。

另外,如果 JavaScript 文件中没有操作 DOM 相关代码,就可以将该 JavaScript 脚本设置为异步加载,通过 async 或 defer 来标记代码,使用方式如下所示:

<script async type="text/javascript" src='foo.js'></script>
<script defer type="text/javascript" src='foo.js'></script>

async和defer区别:

  • async:脚本并行加载,加载完成之后立即执行,执行时机不确定,仍有可能阻塞HTML解析,执行时机在load事件派发之前。
  • defer:脚本并行加载,等待HTML解析完成之后,按照加载顺序执行脚本,执行时机DOMContentLoaded事件派发之前。

html页面中有css样式

//theme.css
div {color:blue}

<html>
<head>
    <style src='theme.css'></style>
</head>
<body>
  <div>1</div>
  <script>
      let div1 = document.getElementsByTagName('div')[0]
      div1.innerText = 'time.geekbang' // 需要 DOM
      div1.style.color = 'red' // 需要 CSSOM
  </script>
  <div>test</div>
</body>
</html>

该示例中,JavaScript 代码出现了 div1.style.color = ‘red’ 的语句,它是用来操纵 CSSOM 的,所以在执行 JavaScript 之前,需要先解析 JavaScript 语句之上所有的CSS 样式。所以如果代码里引用了外部的 CSS 文件,那么在执行 JavaScript 之前,还需要等待外部的 CSS 文件下载完成,并解析生成 CSSOM 对象之后,才能执行 JavaScript 脚本。

而 JavaScript 引擎在解析 JavaScript 之前,是不知道 JavaScript 是否操纵了 CSSOM的,所以渲染引擎在遇到 JavaScript 脚本时,不管该脚本是否操纵了 CSSOM,都会执行CSS 文件下载,解析操作,再执行 JavaScript 脚本。所以说 JavaScript 脚本是依赖样式表的,这又多了一个阻塞过程。

总结:通过上面三点的分析,我们知道了 JavaScript 会阻塞 DOM 生成,而样式文件又会阻塞js的执行。

9.Js 动画与 CSS 动画区别及相应实现

  • CSS3 的动画的优点
    • 在性能上会稍微好一些,浏览器会对 CSS3 的动画做一些优化
    • 代码相对简单
  • 缺点
    • 在动画控制上不够灵活
    • 兼容性不好

JavaScript 的动画正好弥补了这两个缺点,控制能力很强,可以单帧的控制、变换,同时写得好完全可以兼容 IE6,并且功能强大。对于一些复杂控制的动画,使用 javascript 会比较靠谱。而在实现一些小的交互动效的时候,就多考虑考虑 CSS 吧

10.html和css中的图片加载与渲染规则是什么样的?

Web浏览器先会把获取到的HTML代码解析成一个DOM树,HTML中的每个标签都是DOM树中的一个节点,包括display: none隐藏的标签,还有JavaScript动态添加的元素等。浏览器会获取到所有样式,并会把所有样式解析成样式规则,在解析的过程中会去掉浏览器不能识别的样式。

浏览器将会把DOM树和样式规则组合在一起(DOM元素和样式规则匹配)后将会合建一个渲染树(Render Tree),渲染树类似于DOM树,但两者别还是很大的:渲染树能识别样式,渲染树中每个节点(NODE)都有自己的样式,而且渲染树不包含隐藏的节点(比如display:none的节点,还有内的一些节点),因为这些节点不会用于渲染,也不会影响节点的渲染,因此不会包含到渲染树中。一旦渲染树构建完毕后,浏览器就可以根据渲染树来绘制页面了。

简单的归纳就是浏览器渲染Web页面大约会经过六个过程:

  • 解析HTML,构成DOM树
  • 解析加载的样式,构建样式规则树
  • 加载JavaScript,执行JavaScript代码
  • DOM树和样式规则树进行匹配,构成渲染树
  • 计算元素位置进行页面布局
  • 绘制页面,最终在浏览器中呈现

是不是会感觉这个和我们图像加载渲染没啥关系一样,事实并非如此,因为img、picture或者background-image都是DOM树或样式规则中的一部分,那么咱们套用进来,图片加载和渲染的时机有可能是下面这样:

  • 解析HTML时,如果遇到img或picture标签,将会加载图片
  • 解析加载的样式,遇到background-image时,并不会加载图片,而会构建样式规则树
  • 加载JavaScript,执行JavaScript代码,如果代码中有创建img元素之类,会添加到DOM树中;如查有添加background-image规则,将会添加到样式规则树中
  • DOM树和样式规则匹配时构建渲染树,如果DOM树节点匹配到样式规则中的backgorund-image,则会加载背景图片
  • 计算元素(图片)位置进行布局
  • 开始渲染图片,浏览器将呈现渲染出来的图片

上面套用浏览器渲染页面的机制,但图片加载与渲染还是有一定的规则。因为,页面中不是所有的<img>(或picture)元素引入的图片和background-image引入的背景图片都会加载的。那么就引发出新问题了,什么时候会真正的加载,加载规则又是什么?

先概括一点:

Web页面中不是所有的图片都会加载和渲染!

根据前面介绍的浏览器加载和渲染机制,我们可以归纳为:

  • <img>picture和设置background-image的元素遇到display:none时,图片会加载但不会渲染
  • <img>picture、和设置background-image的元素祖先元素设置display:none时,background-image不会渲染也不会加载,而img和picture引入的图片不会渲染但会加载
  • <img>picture、和background-image引入相同路径相同图片文件名时,图片只会加载一次
  • 样式文件中background-image引入的图片,如果匹配不到DOM元素,图片不会加载
    式规则树
  • 加载JavaScript,执行JavaScript代码
  • DOM树和样式规则树进行匹配,构成渲染树
  • 计算元素位置进行页面布局
  • 绘制页面,最终在浏览器中呈现

是不是会感觉这个和我们图像加载渲染没啥关系一样,事实并非如此,因为img、picture或者background-image都是DOM树或样式规则中的一部分,那么咱们套用进来,图片加载和渲染的时机有可能是下面这样:

  • 解析HTML时,如果遇到img或picture标签,将会加载图片
  • 解析加载的样式,遇到background-image时,并不会加载图片,而会构建样式规则树
  • 加载JavaScript,执行JavaScript代码,如果代码中有创建img元素之类,会添加到DOM树中;如查有添加background-image规则,将会添加到样式规则树中
  • DOM树和样式规则匹配时构建渲染树,如果DOM树节点匹配到样式规则中的backgorund-image,则会加载背景图片
  • 计算元素(图片)位置进行布局
  • 开始渲染图片,浏览器将呈现渲染出来的图片

上面套用浏览器渲染页面的机制,但图片加载与渲染还是有一定的规则。因为,页面中不是所有的<img>(或picture)元素引入的图片和background-image引入的背景图片都会加载的。那么就引发出新问题了,什么时候会真正的加载,加载规则又是什么?

先概括一点:

Web页面中不是所有的图片都会加载和渲染!

根据前面介绍的浏览器加载和渲染机制,我们可以归纳为:

  • <img>picture和设置background-image的元素遇到display:none时,图片会加载但不会渲染
  • <img>picture、和设置background-image的元素祖先元素设置display:none时,background-image不会渲染也不会加载,而img和picture引入的图片不会渲染但会加载
  • <img>picture、和background-image引入相同路径相同图片文件名时,图片只会加载一次
  • 样式文件中background-image引入的图片,如果匹配不到DOM元素,图片不会加载
  • 伪类引入的background-image,比如:hover,只有当伪类被触发时,图片才会加载
  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值