HTML训练

60 阅读18分钟

HTML DOCTYPE的含义?什么是HTML的标准模式与混杂模式?

doctype,HTML的文档类型声明,写在第一行,说明这个页面是用什么来编写的

HTML5有哪些语义化标签及特征?HTML元素有哪些分类与特性?

语义化标签可以让我们根据结构化的内容,选择合适的标签

  • 对seo有利
  • 代码可读性更好
  • 标签上加上alt、title,方便一些其他设备进行解析,accessibility(可访问性),如盲人设备

image.png

image.png

image.png

如何检测浏览器是否支持HTML5特性?

  • canvas
  • video、audio
  • 本地缓存的文件:localStorage、worker
  • articel、footer、header
  • form:calender、date
  • esm(es module):模块化规范,可以在script代码里去import,而不是用require,script是不再需要type="moudle"属性了

检测方式:

(1)检查特定的属性和方法:

!!navigator.geolacation
!!window.localStorage
!!window.Worker

(2)创建一个元素,看看特定元素,有没有属性和方法

document.createElement('canvas').getContext()
document.createElement('video').canPlayType

(3)第三方库:

modernizr.cn/

HTML中meta的作用?

meta标签的组成: meta标签共有两个属性,它们分别是http-equiv属性和name属性,不同的属性又有不同的参数值,这些不同的参数值就实现了不同的网页功能。

(1)name属性主要用于描述网页,与之对应的属性值为content,content中的内容主要是便于搜索引擎机器人查找信息和分类信息用的

<meta name="参数" content="具体的参数值">

参数主要有:

  • Keywords(关键字):用来告诉搜索引擎你网页的关键字是什么
  • description(网站内容描述):用来告诉搜索引擎你的网站主要内容
  • robots(机器人向导):用来告诉搜索机器人哪些页面需要索引,哪些页面不需要索引
  • author(作者):标注网页的作者
  • generator:代表说明网站的采用的什么软件制作
  • COPYRIGHT:代表说明网站版权信息

(2)http-equiv属性:相当于http的文件头作用,它可以向浏览器传回一些有用的信息,以帮助正确和精确地显示网页内容,与之对应的属性值为content,content中的内容其实就是各个参数的变量值

<meta http-equiv="参数" content="具体的参数值">

http-equiv属性主要参数:

  • Expires(期限):可以用于设定网页的到期时间。一旦网页过期,必须到服务器上重新传输(必须使用GMT的时间格式)
  • Pragma(cache模式):禁止浏览器从本地计算机的缓存中访问页面内容
  • Refresh(刷新):自动刷新并指向新页面
  • Set-Cookie(cookie设定):如果网页过期,那么存盘的cookie将被删除
  • Window-target(显示窗口的设定):强制页面在当前窗口以独立页面显示,用来防止别人在框架里调用自己的页面
  • content-Type(显示字符集的设定)
  • content-Language(显示语言的设定)
  • http-equiv="imagetoolbar":指定是否显示图片工具栏,当为false代表不显示,当为true代表显示
  • Content-Script-Type:W3C网页规范,指明页面中脚本的类型

HTML的标签有哪些可以优化SEO?

  • 保证页面是SSR的,SEO能抓取到页面内容

  • 增加meta中相关属性,方便索引 <meta name="author" content="xxx.com"> <meta name="description" content="xxx, xxx 系统"> <meta name="keywords" content="xxx, xxx 系统">

  • 使用语义化标签:title、meta、header、nav、article、aside、footer,以一些结构化的为主

DOM和BOM有什么区别?

JavaScript在浏览器环境下,一般由三部分构成 (1) ECMAScript核心:描述了JS的语法和基本对象 (2) DOM:文档对象模型,顶级对象是document,有一些API,可以操作文档

image.png

image.png (3) BOM:浏览器对象模型,browser,顶级对象是window,有一些API,可以操作浏览器(浏览器屏幕)

  • window.location:用于获取当前页面的URL,编写代码时不可使用window这个前缀

image.png

image.png

  • window.navigator:包含有关访问者浏览器的信息,常用于导航,操作浏览器,编写代码时不可使用window这个前缀

image.png

image.png

  • window.history:记录了浏览器的访问历史,为了保护用户隐私,对JavaScript访问该对象的方法做出了限制

image.png

image.png

如何实现移动端适配?

(1)百分比布局:也叫流式布局,效果:宽度自适应,高度固定;是一种比较老的解决方案,现在基本上是作为辅助使用

(2)Flex弹性布局:是一种浏览器提倡的布局模型,布局网页更简单、灵活、避免浮动脱标的问题,是目前比较流行的一种方式

(3)rem:等比缩放布局,rem是相对单位,相对于HTML标签的字号计算结果,是目前多数企业在用的解决方案,屏幕宽度不同,网页元素尺寸不同(等比缩放)效果

1rem=1html字号(基准根字号)大小;目前rem布局方案中,将网页等分为10份,HTML标签的字号为视口宽度的十分之一,如:设计稿为375px,1rem=1html字号=37.5px

手机屏幕大小不同,如何设置不同的HTML标签字号:使用媒体查询检测视口宽度,编写差异化的CSS样式

媒体查询不能定义每个手机尺寸,可以使用flexible.js,这是手机淘宝团队开发的用来适配移动端的js框架,核心原理就是根据不同的视口宽度给网页中html根节点设置不同的font-size值

(4)vw 、vh:也是一个相对单位:

vw:viewport width;1vm=1/100 视口宽度

vh:viewport height;1vh=1/100 视口高度

如设计图为375px;1vm=3.75px;如果盒子大小是75px,那么75/3.75=20vm;width:75px就可以写为width:20vw;

开发中vw和vh不要混用,要么全用vw,要么全用vh,混用可能会导致盒子变形

设备像素比:window.devicePixslRatio

1px问题:CSS样式里的px和物理像素并不是相等的,CSS中的像素只是一个抽象的单位,在不同的设备或不同的环境中,CSS中的1px所代表的物理像素是不同的,在PC端,CSS的1px一般对应着电脑屏幕的1个物理像素,但在移动端,CSS的1px等于几个物理像素

  • 伪元素+transform:构建一个伪元素,border为1px,再以transform缩放到50%,
  • viewport+rem:通过设置对应的viewport的rem基准值,这种方式就可以像以前一样写1px了
  • 设置border-image或者background-image

如何禁用页面中的右键、打印、另存为、复制等功能?

// 禁用右键
document.onmousedown=function(event){
    if(event.button===2){
        return false
    }
}
document.oncontextmenu=function(event){
    return false
}
// 禁用复制
<body oncopy="nocopy()">
function nocopy(event){
    event.returnValue=false
}
// 禁用f12
document.onkeydown=function(event){
    if(window.event && window.event.keyCode===123){
        window.event.returnValue=false
    }
}

href="javascript:void(0)" 和 href="#"区别是什么?

href="#":锚点默认是#top,会让网页往上走到最上面

javascript:void(0) :阻止事件,是一个固定死链接

对target="_blank" 的理解?有什么安全性问题,如何防范?

打开新的子页面,类似于windoe.open,子页面会拿到当前的句柄(window.opener),就能操作上一个页面的一些信息

if(window.opener){
    window.opener.location.href="bad.html"
}

可以修改为

<a .... rel="noopener noreferer">
var otherWindow = window.open('xxx')
otherWindow.opener = null

简述页面测存储区别,什么是本地存储?怎么做离线存储?

(1)cookie:每个cookie不能超过4kb,每个域只能有20个

(2)localStorage:永久存在,大小5M

(3)sessionStorage:会话存储,大小5M

(4)indexDB:离线存储,浏览器数据库

什么是canvas?什么时候需要使用canvas?

画布:浏览器端的绘图工具

常见的动画方案:

css+div:普通网页使用

svg:和传统的html差别不大,html处理矢量绘图能力不足

cavans:比较方便的绘制图形

数据量比较大,动画渲染比较复杂的时候使用cavans

什么是PWA?

渐进式网页应用:一般简单的应用会使用PWA,类似于网页小程序

核心技术:

  • app manifest
  • service worker(客户端代理)
  • web push

什么是Shadow DOM?

shadow dom直译过来就是影子dom,可以理解为DOM中的DOM,因为它能够为Web组件中的DOM和CSS提供封装,实际上是在浏览器渲染文档的时候会给指定的DOM结构插入编写好的DOM元素,但是插入的Shadow DOM会与主文档的DOM保持分离,也就是说Shadow DOM不存在于主DOM树上

Shadow DOM封装出来的DOM元素是独立的,外部的配置不会影响到内部,内部的配置也不会影响到外部

iframe有哪些应用?

  • 最常见的一种微前端手段
  • ajax上传文件
  • 广告
  • 解决跨域

如何处理iframe通信?

<body>
    <h2>A页面</h2>
    <button id="btn">post</button>
    <iframe src="http://localhost:8102" id="iframe"></iframe>
</body>
<script>
    window.onload = function() {
        document.getElementById('btn').addEventListener('click', function() {
            var iframe = document.getElementById('iframe');
            iframe.contentWindow.postMessage('xxxxx', '*');
        })
    }
    window.addEventListener('message', function(event) {
        console.log(event);
    })
</script>
<body>
    B
    <script>
        window.addEventListener('message', function(event) {
            console.log(event);
            event.source.postMessage('i am b ', "*")
        })
    </script>
</body>

浏览器渲染和布局逻辑是什么?

  • 解析时,DOM树的构建
  • CSSOM 规则树
  • DOM树和CSS规则树,构建成render渲染树
  • 页面布局
  • 页面绘制

页面的重绘和回流是什么?

回流:又称重排,指改变集合属性的渲染,可以理解为对整个网页填白,对内容重新渲染一次

回流意味着节点的几何属性发生变化,需要重新计算并生成渲染树,导致渲染树的全部或部分发生变化

引起回流的一起场景:

  • 页面的初始加载
  • 浏览器窗口更改大小
  • 元素字体大小变化
  • 元素内容发生变化
  • js删除或增加元素
  • 功能性伪类触发
  • 涉及到的一些代码有以下属性或方法:offsetTop、offsetLeft、offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() 、currentStyle()

重绘:指改变外观属性而不影响几何属性的渲染,相比回流,重绘在两者中会温和一些,回流对浏览器性能的消耗高于重绘

回流一定伴随着重绘,重绘不一定伴随回流

引起重绘的场景:

  • color、background 相关属性: background-color、background-image等。
  • outline 相关属性: outline-color、 outline-width 、text-decoration
  • border-radius、 visibility、 box-shadow

outline是css属性,用于设置元素的外边框样式,包括颜色、样式和宽度。外边框是一个在元素周围的轮廓,类似于边框(border),但不会占用空间,并且不会影响布局

如何避免回流和重绘

(1)CSS:

1、避免使用table布局。

2、尽可能在DOM树的最末端改变class。

3、避免设置多层内联样式。

4、将动画效果应用到position属性为absolute或fixed的元素上。

5、避免使用CSS表达式(例如:calc())。

(2)JavaScript:

1、避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。

2、避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。

3、也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。

4、避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。

5、对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

怎么计算首屏和白屏的时间?长统计的页面性能数据指标包括?

window.performance:在埋点的数据分析里,有一项是分析网站性能的,他包含了网站加载时间(含各项事务占比)、dom渲染时间、接口请求响应时间等等。这个涉及到的api就是window.performance

PerformanceObserver:可用于获取性能相关的数据,如,首帧fp、首屏fcp、首次有意义的绘制fmp等

cls监听元素是否回流

页面上有哪些领域可以做进一步的性能优化?

尽量不要引发重绘、回流

  • display:none-->visibility:hidden
  • 避免使用table布局
  • 避免层级过多
  • 操作dom insert时,尽量使用fragment,构造完成后一起插入
  • 关键动画,使用requestIdelCallback
  • 避免首屏加载东西过多

浏览器之间的线程调度是怎样的?

image.png

最新的Chrome浏览器包括:1个浏览器主进程,1个GPU进程,1个网络进程,多个渲染进程,和多个插件进程

  • 浏览器进程:负责控制浏览器除标签页外的界面,包括地址栏、书签、前进后退按钮等,以及负责与其他进程的协调工作,同时提供存储功能
  • GPU进程:负责整个浏览器界面的渲染。Chrome刚开始发布的时候是没有GPU进程的,而使用GPU的初衷是为了实现3D CSS效果,只是后面网页、Chrome的UI界面都用GPU来绘制,这使GPU成为浏览器普遍的需求,最后Chrome在多进程架构上也引入了GPU进程
  • 网络进程:负责发起和接受网络请求,以前是作为模块运行在浏览器进程一时在面的,后面才独立出来,成为一个单独的进程
  • 插件进程:主要是负责插件的运行,因为插件可能崩溃,所以需要通过插件进程来隔离,以保证插件崩溃也不会对浏览器和页面造成影响
  • 渲染进程:负责控制显示tab标签页内的所有内容,核心任务是将HTML、CSS、JS转为用户可以与之交互的网页,排版引擎Blink和JS引擎V8都是运行在该进程中,默认情况下Chrome会为每个Tab标签页创建一个渲染进程

浏览器的渲染进程的线程总共有五种:

(1)GUI渲染线程

负责渲染浏览器页面,解析HTML、CSS,构建DOM树、构建CSSOM树、构建渲染树和绘制页面;当界面需要重绘或由于某种操作引发回流时,该线程就会执行

注意:GUI渲染线程和JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。

(2)JS引擎线程

JS引擎线程也称为JS内核,负责处理Javascript脚本程序,解析Javascript脚本,运行代码;JS引擎线程一直等待着任务队列中任务的到来,然后加以处理,一个Tab页中无论什么时候都只有一个JS引擎线程在运行JS程序

注意:GUI渲染线程与JS引擎线程的互斥关系,所以如果JS执行的时间过长,会造成页面的渲染不连贯,导致页面渲染加载阻塞

(3)事件触发线程

时间触发线程属于浏览器而不是JS引擎,用来控制事件循环;当JS引擎执行代码块如setTimeOut时(也可是来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件触发线程中;当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理

注意:由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)

(4)定时器触发进程

定时器触发进程即setInterval与setTimeout所在线程;浏览器定时计数器并不是由JS引擎计数的,因为JS引擎是单线程的,如果处于阻塞线程状态就会影响记计时的准确性;因此使用单独线程来计时并触发定时器,计时完毕后,添加到事件队列中,等待JS引擎空闲后执行,所以定时器中的任务在设定的时间点不一定能够准时执行,定时器只是在指定时间点将任务添加到事件队列中

注意:W3C在HTML标准中规定,定时器的定时时间不能小于4ms,如果是小于4ms,则默认为4ms

(5)异步http请求线程

XMLHttpRequest连接后通过浏览器新开一个线程请求;检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将回调函数放入事件队列中,等待JS引擎空闲后执行

JS事件循环(Event Loop)

JS是单线程,只有一个线程存在,同一时间只能做一件事,这可能会导致JS在处理某些长时间运行的操作(如网络请求、文件系统访问等)时出现阻塞,从而影响用户体验,为了解决单线程运行阻塞问题,JS用到了计算机系统的一种运行机制,即事件循环

在JS中,所有的任务都可以分为:

  • 同步任务:立即执行的任务,指的就是前一个任务结束之后再执行后一个任务,程序执行的顺序与任务排序的顺序是一样的,保持同步的,同步任务会直接进入到主线程中执行
  • 同步任务在主线程里执行,当浏览器第一遍过滤html文件的时候可以执行完(在当前作用域可以直接执行的所有内容,包括执行的方法、new出来的对象)
  • 异步任务:与同步任务是相对的,异步任务不按照任务排序的顺序执行,也可以理解为异步是从主线程中发出一个子线程来完成任务,不进入主线程,直接进入任务队列,只有任务队列通知主线程某个异步任务可以执行的时候,该任务才会进入主线程执行
  • 异步任务比较耗费时间与性能,浏览器执行到这些的时候会将其丢到异步任务队列中,不会立即执行

JS中常用的异步任务:setTimeout、setInterval、Promise、Ajax异步请求、DOM事件(click、热size、onload)

image.png

同步任务进入主线程,即主执行栈,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行,不断重复上述过程就是事件循环

异步任务又可以划分为微任务与宏任务

宏任务是由宿主发起的,而微任务由JavaScript自身发起。

在ES3以及以前的版本中,JavaScript本身没有发起异步请求的能力,也就没有微任务的存在。在ES5之后,JavaScript引入了Promise,这样,不需要浏览器,JavaScript引擎自身也能够发起异步任务了。

微任务:一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前

常见的微任务

  • Promise.then
  • MutaionObserver
  • Object.observe(已废弃,Proxy对象替代)
  • process.nextTick(Nodejs)

宏任务:时间粒度比较大,执行的事件间隔不能精确控制,对一些高实时性的需求不太适合

常见的宏任务

  • srcipt(可以理解为外层同步代码)
  • setTimeout、setInterval
  • UI rendering、UI事件
  • postMessage、MessageChannel
  • setImmediate、I/O(Nodejs)

image.png

执行一个宏任务,如果遇到微任务,就将它放到微任务的事件队列中,当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完

async、await

async是异步的意思,await可以理解为等待,async函数返回一个promise对象,下面这两种方法是等效的

image.png

正常情况下,await命令后面是一个Promise对象,返回该对象的结果,如果不是Promise对象,就直接返回对应的值

image.png

await会阻塞下面的代码(即加入微任务队列,先执行async外面的同步代码,同步代码执行完,再回到async函数中,执行之前阻塞的代码)

输出结果为:1、fn2、3、2

流程分析:

image.png

  • 执行整段代码,遇到 console.log(‘script start’) 直接打印结果,输出 script start
  • 遇到定时器了,它是宏任务,先放着不执行
  • 遇到 async1(),执行 async1 函数,先打印 async1 start,下面遇到await怎么办?先执行 async2,打印 async2,然后阻塞下面代码(即加入微任务列表),跳出去执行同步代码
  • 跳到 new Promise 这里,直接执行,打印 promise1,下面遇到 .then(),它是微任务,放到微任务列表等待执行
  • 最后一行直接打印 script end,现在同步代码执行完了,开始执行微任务,即 await 下面的代码,打印 async1 end
  • 继续执行下一个微任务,即执行 then 的回调,打印 promise2
  • 上一个宏任务所有事都做完了,开始下一个宏任务,就是定时器,打印 settimeout
  • 最后结果:script start、async1 start、async2、promise1、script end、async1 end、promise2、settimeout