HTML:你想知道的都在这里

349 阅读20分钟

基础

简介

html(HyperText Markup Language)是一门超文本标记语言,用于定义网页的结构和内容。一个完整的网页结构是通过各种标记(标签)组成的。

html5与html

html5是html的第五个版本,是html的最新标准。设计的目的是为了能够支持多媒体等新特性。

声明方式不同

html声明需要对DTD进行引用

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

html5声明只需要声明!DOCTYPE HTML即可

<!DOCTYPE html>
说明:HTML是基于SGML的,隐藏需要对DTD进行引用,才能告知浏览器文档所使用的文档类型。
     HTML5不基于SGML,因此不需要对DTD进行引用,但是需要doctype来规范浏览器的行为。
补充:Doctype的作用,<!Doctype>声明位于文档种的最前面,用于告知浏览器的解析器,用什么样的文档类型规范来解析这个文档,
严格模式下的排版和JS运作模式是以该浏览器支持的最高标准运行的,在混杂模式中,页面以宽松的向后兼容的方法显示,
模拟老式浏览器的行为防止站点无法正常工作,DOCTYPE不存在或者格式不正确会导致文档以混杂模式呈现。     

结构语言方面

hmtl没有结构语义化的标签,通常声明声明结构是是通过其他方式来区分的,如通过增加id属性

<div id = "header">这里是页面的头部</div>

html新增了很多语义化的标签,可以直接使用这些标签来定义网页结构

<header>这里是页面的头部</header>

更多的语义化标签,如下

  • header 页面头部部分

  • nav 导航连接部分

  • article 用于定义独立的内容区域

  • section 用于定义文档中的节,比如章节,页眉,页脚等

  • aside 用于定义主区域之外的内容,如侧边栏

  • footer 用于描述文档的底部区域

  • h1-h6 用于表示文档标题

      补充:
      为什么需要语义化:为了更好的描述页面结构,在没有css的情况下,也能够呈现出很好的内容结构
      好处有哪些:1. 有利于SEO(搜索引擎优化),爬虫依赖标签来确定关键字的权重,语义化的标签可以帮助爬虫快速抓取
      更多的有效信息。
      2. 便于团队发开和维护,语义化的标签使得代码更具有可读性,其他团队成员更容易理解你的html结构。
      3. 提高用户体验,如title和ait可以用于进行名词或者是图片信息的解释。
      4. 方便其他设备解析,如屏幕阅读器,移动设备等。
      
    

新增API

  • 新增选择器:document.querySelector、document.querySelectorAll
  • 绘图方面:html5新增canvassvg,可以使用canvas在网页上绘制图像,可以控制画布每一个像素

image.png

image.png

补充:canvas是基于像素进行渲染的,通过javascript进行绘制,绘制出来的是一整张标量图,拉伸会失真,并且不会绑定事件。
svg是一致可伸缩的矢量图形,它基于xml格式,不会失真,可以通过css和js控制,支持绑定事件。
可以通过html2canvas实现将html元素转换为canvas,然后通过canvas的toDataURL来转换为图片,或者是toBlob转换为流来
与后台交互。
  • 音频与视频的支持:html只有使用flash播放器才支持音频和视频,但是html5新增了audio与video两个标签来支持音频和视频。相关的浏览器支持性检测:用js动态创建video和audio检测特定函数是否存在
//!!是将类型转换为boolean类型
const canUseVideo = !!(document.createElement('video'),canPlayType)
//判断地理位置服务是否可用
if('geolocation' in navigator){
    navigator.geolocation.getCurrentPosition(function(position){
        console.log(position.coords.latitude,position.coords,longitude)
    })
}

也可以监听用户位置变化

//watchPosition监听用户位置变化,返回一个监听id
const watchID = navigator.geolocation.watchPosition(function(position) {
  console.log(position.coords.latitude, position.coords.longitude);
})
//清除监听
navigator.geolocation.clearWatch(watchID);
  • 新增webSockets:websockets可以实现客户端与服务器双向通信。 http请求只能由客户端发起,然后服务器给予响应,但是websocket可以实现客户端和服务器相互推送数据,会建立长久的链接。可以用在实时性要求比较高得场所。

  • 新增表单元素类型:比如tel,email,url,search,number等

  • 新增拖放相关得API:draggable属性设置元素是否可拖拽,拖放事件(dratstart,drag,dragenter,dragleave,dragover,drap,dragend)

  • 新增webWorker,js是单线程的,webworker可以为js创造多线程环境,允许主线程创建worker线程,将一些任务分配给worker执行,两者同时执行,载worker执行完成之后会把结果告诉主线程,因此通常可以用它来做一些比较复杂得计算工作。但是worker一旦建立就会一直允许,会比较消耗资源,虽然有利于响应主线程得通信,但是最后还是应该使用完就关闭。

  • storage API:新增本地存储的两种方式,localStorage和sessionStorage

      三种本地存储方式的比较:
      cookie:由服务器生成,可以设置失效时间,如果是浏览器生成的cookie则会在关闭浏览器时失效,大小只有4k左右,
      每次都会载http头种携带。domain(域名)一致的页面可以共享cookie,如果只是端口号不同,想要共享本地存储数据的话可以考虑使用
      localStorage:除非被清除,否则会一直存在,一般为5m,只会载客户端存储,不会主动发送给服务器。
      sessionStorage:仅载当前会话下有效,也就是一个标签页一个session,关闭网页时会被清除,一般来5m大,也不会参与服务器通信。
      应用场景:一个项目,多个页面需要维护自己的本地数据时。
    
  • 离线应用:manifest

    离线应用:在用户没有链接网络时,可以访问站点或应用,在用户链接网络时,更新用户机器上的缓存文件
    原理:HTML5的离线存储时基于一个.appcache文件的缓存机制,通过这个文件上的解析清单离线存储资源,当网络处于
    离线状态下的时候,浏览器会通过被离线存储的数据进行页面展示。
    管理方式:在线的情况下,浏览器发现html头部有minifest属性,它会请求manifest文件,如果是第一次访问app,那么浏览
    器会根据manifest文件的内容下载相应的资源并且进行离线存储,如果已经访问过了并且资源已经离线存储了,那么浏览器就
    会使用离线的资源加载页面,然后浏览器会对比新旧manifest文件,如果文件没有发送改变,就不任何操作,如果改变了,
    那么就会重新下载文件中的资源并进行离线存储。
    离线的情况下直接使用离线存储的资源
    
    

移除了一些元素

纯表现得元素:basefont,big,center,font,s,strike,tt,u等用css来代替 部分浏览器支持的元素:applet,bgsound,blink,marquee 对可用性产生负面影响的元素:frameset,frame,noframes在html5 中不支持frame框架,只支持iframe框架

    iframe的缺点:
    iframe会阻塞主页面的onload事件
    搜索引擎无法检索iframe,不利于seo
    iframe和主页面共享连接池,浏览器对相同域的链接有限制,所以会影响页面的并行加载
    解决:需要使用iframe的话,最好使用js动态的给iframe添加src属性。

扩展XML XHTML HTML

  1. XML是可扩展的标记语言,主要用于存储数据,有时候回合json进行比较
  2. HTML是超文本标记语言,语法较为松散
  3. XHTML是可扩展的超文本标记语言,基于XML,作用与HTML类似,有点像他俩的组合,但语法更加严格,XHTML标签名必须小写,元素必须关闭,必须正确的嵌套,必须要有根元素。

常见面试题

  • 前端需要注意哪些SEO

      1. 给meta标签设置合理的title,description,keyword。title强调重点,description高度概括内容,keywords列出重要关键字,如淘宝页
      2. 编写语义化的html代码,语义化的html代码搜索引擎更容易解析,更容易理解。
      3. 提高网站速度
      4. 重要内容放在前面,更快的被搜索引擎找到,不要用js输出,搜索引擎是不会执行js获取内容的
      5. 少用iframe:搜索引擎不会抓取iframe中的内容。
      6. 非装饰性的图片加上alt描述
      
    

image.png

  • cookies,sessionStorag,localStorage的区别
  • 对语义化的理解
  • Doctype的作用,严格模式与混杂模式的区别
  • canvas与svg的区别
  • html5为什么只需要写Doctype
  • html5新增了哪些特性

标签

html标签分为三类:块级元素、行类元素与空元素

  • 块级元素:独占一行,可以设置宽高的元素称为块级元素->div ul li dl dt dd h1-h6 p等

  • 行类元素:不独占一行,不可以设置宽高->a b sapn input select strong等

  • 空元素:也就是自结束标签->br hr img link meta

      注:img属于行类替换元素,效果等同于块级元素
      可以使用css属性display改变元素类型
      display: inline;//行类元素
      display: block;//块级元素
      display: inine-block;//块级行类元素,不独占一行,但是可以设置宽高
    

这里只列举几个标签,其他的详见MDN

  • title与h标签:title顶替文档的标题,显示在浏览器的标题栏或者标签页上,h标签指不同级别的标题,h1级别最高,h6最低
  • meta:元数据标签,不会显示在浏览器,但是会被浏览器解析,meta标签可以做很多事,比如设置请求头部信息,设置页面关键字,描述信息(搜索引擎优化),设置viewport来改变移动端布局,页面重定向等。
  • link:链接外包元素,通常用于引入外部css文件,一般放在head里面(目得是为了先加载样式,在渲染页面,这样不会照成页面最开始的页面时没有css样式页面的问题,也就是页面闪烁fouc)。也可以用来设置网站的logo。
//设置网站logo
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
    扩展:
    页面导入样式时:使用link与@import的区别
    1. link属于HTML标签,@import时css提供的
    2. 页面被加载的同时,link就会被同时加载,而@import引入的css会等到页面被加载完成只会再加载,会影响页面渲染。
    3. @import只有ie5以上才能识别
    4. link方法的样式权重大于@import的权重
    
  • img:img标签用于显示图片

      扩展:
      1. img标签的title属性与alt属性的区别
      title是为该元素提供建议性信息,鼠标移入就会显示
      alt是img的特有属性,再图片不能正常显示的时候作为其提代方案显示
      
      2. img是通过src引入图片的,link是使用href引入的,src与href有什么区别
      src是用于替换当前元素,也就是说img是将图片替换了img,而href是用于在当前文档和引入资源之间建立联系。
      
      3. 几种图片格式及区别
      png:背景透明,常用于做透明背景图
      jpg:图片不透明,可压缩,可以根据需求调整分辨率
      gif:动画图
      webP:谷歌开发的用于加快图片加载速度的图片格式,压缩体积大概只有jpg的2/3
      Apng:png的位图动画扩展,可以实现png格式的动态图效果
      
    
  • a:锚点元素,超链接,可以通过它的href属性创建通向其他网页的位置。可以通过定位锚点来实现页面位置跳转。可以跳转到头部,底部或者是页面的任意位置。

//点击锚点可以直接跳转到底部
<a href = "#footer">跳转到底部</a>
....
<div id = "footer>这里是页面底部</div>
    扩展:vue-router中的hash模式的实现原理就是使用了a标签的锚点定位。
    hash#)是url的一个锚点,代表的是网页的一个位置,只是hash部分变化的话,页面只会滚动到相应的位置,不会重新加载
    网页,也就不会再次向服务器发送请求,但是每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用后退前
    进按钮可以跳转,hash模式就是通过锚点值得改变,根据不同得值获取不同得数据。通过监听hashchange事件来监听hash改
    变,执行相应的逻辑,获取数据,部分刷新页面。

其他

  1. html与dom的关系:html是网页标签,dom是由html解析获得,可以通过js代码进行维护修改。

  2. html元素的嵌套关系:块级元素可以包含行内元素,可能能包含其他块级元素,行内元素一般不能包含块级元素(a元素除外)

  3. 良好的前端结构:行为(js),样式(css),结构分离(html),代码分离,有利于开发和后期维护。

  4. 渐进增强与优雅降级:渐进增强是针对低版本浏览器实现基础的功能,在针对高级浏览器进行效果,交互等方面的改进和功能追加,达到更好的用户体验。优雅降级是指一开始就建立完整的功能,在针对低版本浏览器进行兼容。

  5. script标签的defer与async:script标签引入的内容会阻碍页面的渲染,当执行到script标签处,会停止页面渲染,开始下载script标签的内容,下载完毕之后再继续渲染页面,解决办法就行使用defer或者是async进行异步下载。

     两者的区别:
     async:文件下载完成就会立即执行,按照下载完成时间执行,而不是引入顺序。
     defer:等全部文件下载完毕,整个页面再内存中正常渲染结束之后按照引入顺序执行
    
     使用type="module"的script标签也是异步加载的,等同域打开了defer属性
     
    
  6. 浏览器乱码:网页源代码是gbk编码,而内容中的中文是utf-8编码,两者编码格式不一致,导致乱码。解决办法,统一编码格式。

进阶

meta标签

meta标签是网页的元数据信息,提供了html文档的元数据,虽然不会显示在客户端,但是会被浏览器解析。 可以用来设置网页的标题,关键字,描述信息等利于搜索引擎优化(SEO)

  • 定义文档关键字,描述,作者等
<meta name="keyword" content="HTML,CSS,XML,JavaScript"/>
<meta name="description" content="页面描述信息"/>
<meta name="author" content="wood"/>
  • 可以用来自动刷新,如大屏需要每隔一段时间获取最新数据时,可以直接用meta标签代替轮询查询接口
<meta http-equiv="refresh" content="30"/>
  • 也可以用来实现定时跳转功能,如实现一个类似ppt的效果,5s后自动跳转到page2页面
<meta http-equiv="refresh" content="5;URL=page2.html"/>
  • viewport为移动端设备设置视口属性
<meta name="viewport" content="width=device-width,initial-scale=1.0,mininum-scale=1.0,maxmum-scale=1.0,user-scalable=no"/>
//width 设置viewport宽度,为一个正整数或字符串device-width(设备的宽度)
//height 设置viewport高度,一般设置了宽度就会自动解析出高度
//initial-scale 默认缩放比例(初始缩放比例),为一个数字,可以带小数
//minimum-scale 允许用户最小缩放比例
//maximum-scale 允许用户最大缩放比例
//user-scalable 是否允许手动缩放
  扩展:移动端1px被渲染成2px的问题
  局部处理方式:
  meta标签中的viewport属性,initial-scale设置为1,rem按照设计稿走,但是要利用transform:scale(0.5)缩小一倍
  全局处理方式:
  meta标签中的viewport属性,initial-scale设置为0.5,rem按照设计稿走

性能优化

性能优化主要从两方面着手:一方面是渲染速度,另一方面是请求时间。

  • 调整script标签位置:渲染引擎在解析html页面时,如果遇到了script标签引用文件,那么就会暂停解析,去下载文件,下载完成之后执行代码,然后再继续解析页面,这样就会阻碍页面的渲染。但是有些文件可能再首屏时不需要加载,就会延长用户看到页面的时间,降低用户体验。解决方案也很简单。将script标签放在底部。或者是利用script标签的defer/async属性。

     async属性: 会立即请求文件,但是不会阻碍渲染引擎解析html,但是文件下载完成之后就会立即执行,这时如果页面没有渲染完毕也会阻碍页面的渲染。并且代码的执行情况是根据下载时间来的,而不是引入顺序
     defer属性:会立即请求文件,但是不会阻碍渲染引擎解析html,下载完成之后不会立即执行,会等到页面渲染完毕之后再按照引入顺序执行。
     设置type="module"效果等同于defer
     
    
  • linek标签:通过预处理提示渲染速度:对大型单页应用进行性能优化时,可能会用到按需懒加载的方式来加载对应的模块,如果合理的利用link标签的rel属性值来进行预加载的话, 也能提示渲染速度

  • dns-prefetch:当link标签的rel属性设置为dns-prefetch时,会对href指定的域名进行dns解析并缓存,这样当请求相同域名资源时,就可以省去域名查询的时间。下面的淘宝的设置。

image.png

  • preconnect:让浏览器再一个http请求正式发送给服务器前先执行一些操作,如dns解析,tls协商,tcp握手等,通过消除往返延迟来节约时间
  • prefetch/preload:都是预先下载并缓存资源,但是prefetch可能会再浏览器忙时被忽略,而preload则一定会被预先加载
  • prerender:浏览器会提前解析执行页面,进行预渲染
  • 浏览器获取资源文件的流程如下

image.png

dom操作

  • dom操作为什么会耗时?

    • 线程切换:浏览器为了避免两个引擎同时修改页面造成渲染结果不一致的情况,规定了两个引擎具有互斥性,也就是同一时刻只有一个引擎再允许。而操作系统再切换线程时需要保持上一个线程执行时的状态信息并读取下一个线程的状态信息,也就是进行上下文切换,这个操作相对而言时比较耗时的。每次dom操作都会引起线程的上下文切换,从javascript引擎切换到渲染引擎执行对应操作之后再切换javascript引擎继续执行,这样就带来了性能损耗,频繁大量的切换就会造成性能问题。

    • 重新渲染:元素的样式变化引擎的再次渲染,在渲染过程中最耗时的两个步骤就是重排与重绘,浏览器在渲染页面时会将html和css反别解析成dom树和cssom树,然后合并进行排布,再绘制到页面上,如果再操作dom时修改了元素的样式,那么就会引擎渲染引擎重新计算样式生成cssom树,同时页面结构改变的话还会引起元素的重新排布和重新绘制。

        影响到其他元素排布的操作就会引发重排,继而引发重绘:修改编剧,大小,添加删除元素,改变窗口大小,获取offsetWidth,offsetHeight(通过重新排布来计算值)等。
        引起重绘:设置背景图片,修改字体颜色,改变visibility的值等
      
  • 高效的操作dom

    • 再循环外操作元素。如
    const times = 10000;
    console.time('switch')
    for (let i = 0; i < times; i++) {
      document.body === 1 ? console.log(1) : void 0;
    }
    console.timeEnd('switch') // 1.873046875ms
    var body = JSON.stringify(document.body)
    console.time('batch')
    for (let i = 0; i < times; i++) {
      body === 1 ? console.log(1) : void 0;
    }
    console.timeEnd('batch') // 0.846923828125ms
    
    • 批量操作元素,如
    const times = 10000;
    console.time('createElement')
    for (let i = 0; i < times; i++) {
      const div = document.createElement('div')
      document.body.appendChild(div)
    }
    console.timeEnd('createElement')// 54.964111328125ms
    console.time('innerHTML')
    let html=''
    for (let i = 0; i < times; i++) {
      html+='<div></div>'
    }
    document.body.innerHTML += html // 31.919921875ms
    console.timeEnd('innerHTML')
    

drag api

  • dragstart:事件主体是被拖放元素,在开始拖放元素时触发
  • drag:事件主体时被拖放元素,在正在拖放被拖放元素时触发
  • dragenter:事件主体是目标元素,在被拖放元素进入某元素时触发
  • dragover:事件主体是目标元素,在被拖放元素在目标元素内移动时触发
  • dragleave:事件主体时目标元素,在被拖放元素移出目标元素时触发
  • drop:事件主体时目标元素,在目标元素完全接受被拖放元素时触发
  • dragend:事件主体时被拖放元素,在整个拖放操作结束时触发

iframe

iframe可以用来内嵌网页,但是存在很多问题,如:iframe会阻塞组页面的onload事件,搜索引擎无法解析,不利于seo,iframe和主页面共享连接池,浏览器对相同域的链接有限制,会影响页面的并行加载,一定要使用的话,最好使用src动态的给iframe设置src属性

多标签页通讯

  • 调用localstorage,在一个标签页里面使用localstorage.setItem(key,value)来修改内容,在另一个标签页里面监听storage事件,即可完成。要求是统一项目的不同标签页。
//标签页1
localStorage.setItem("userInfo",{name:"wood"})
//标签页2
window.addEventListener("storage",function(event){
    console.log(event.key+"="+event.newValue)
})
  • 使用cookie,同一host下面的网页是共享cookie的,可以将信息存储在cookie中,在要用到的地方获取。

div模拟textarea

给div添加contenteditable=true即可

a标签点击后hover事件失效

改变a标签css属性的排列顺序 遵顼love hate原则 link->visited->hover->active

点击一个input依次触发的事件

onmouseenter->onmousedown->onfocus->onclick

addEventListene函数的第三个参数

为true时为捕获,为false时为冒泡

dom事件流

事件发送时会在元素节点之间按照特定的顺序传播,整个传播过程就叫做dom事件流。 分为三个阶段:

  • 捕获阶段->事件从window发出,自上而下向目标节点传播

  • 目标阶段->真正的目标阶段正在处理事件的阶段

  • 冒泡阶段->事件从目标节点自下而上传播的阶段。

      补充:
      阻止事件冒泡:w3c->event.stopPropagation() ie->e.cancelBubble = true
      阻止事件默认行为:w3c->event.preventDefault() ie->e.returnValue = false
    

offset、scroll、client

client:

  • event.clientX->指鼠标到可视区左边框的距离
  • event.clientY->指鼠标到可视区上边框的距离
  • clientWidth->指可视区的宽度
  • clientHeight->指可视区的高度
  • clientLeft->获取左边框的宽度
  • clientTop->获取上边框的宽度 offset:
  • offsetWidth->指div的宽度,包括边框
  • offsetHeight->指div的高度,包括边框
  • offsetLeft->指div到整个页面左边框的距离,不包括边框
  • offsetTop->指div到整个页面上边框的距离,不包括边框 scroll:
  • scrollTop->指可视区顶部边框与整个页面上部边框的看不到的区域
  • scrollLeft->指可视区左边边框与整个页面左边边框的看不到的区域
  • scrollWidth->指左边看不到的区域加可视区加右边看不到的区域即整个页面的宽度,包括边框
  • scrollHeight->指上边看不到的区域加可视区下边看不到的区域即整个页面的高度,包括边框

target="_blank"

设置target="_blank"可以在新窗口打开页面,但是存在一些问题,如:

  • 安全隐患:新打开的窗口可以通过window。opener获取来源页面的window对象即使跨域也可以。某些属性的访问会被拦截,这是因为跨域安全策略限制。
  • 新打开的窗口与原页面窗口共用一个进程,会影响原页面。