HTML、CSS、浏览器知识点

5 阅读56分钟

HTML

html 标签的类型(head, body,!Doctype) 他们的作用是什么

HTML 标签主要分为三种类型:DOCTYPE 声明、head 标签和 body 标签。

  1. <!DOCTYPE> 声明:它规定了当前文档的类型和版本。它不是 HTML 标签,而是一种指令,告诉浏览器使用哪种 HTML 版本解析页面。它通常位于文档的开头。
  2. <head> 标签:这个标签用于定义 HTML 文档的头部部分,包括文档的元信息,如标题、引用的样式表或脚本,字符集声明等。在 <head> 标签中的内容不会直接显示在浏览器窗口中。
  3. <body> 标签:这个标签包含了页面中的实际内容,比如文本、图像、链接等。浏览器会显示 <body> 标签中的内容,并根据其中的 HTMLCSS 规则来渲染页面的可见部分。

HTML5有哪些新特性、移除了哪些元素?

  1. HTML5 新增了 27 个元素,废弃了 16 个元素,根据现有的标准规范,把 HTML5 的元素按优先级定义为 结构性属性、级块性元素、行内语义性元素和交互性元素 4 大类。

    结构性元素: 主要负责web上下文结构的定义

    • section:在 web 页面应用中,该元素也可以用于区域的章节描述。
    • header:页面主体上的头部, header 元素往往在一对 body 元素中。
    • footer:页面的底部(页脚),通常会标出网站的相关信息。
    • nav:专门用于菜单导航、链接导航的元素,是 navigator 的缩写。
    • article:用于表现一篇文章的主体内容,一般为文字集中显示的区域。

    级块性元素: 主要完成web页面区域的划分,确保内容的有效分割。

    • aside:用于表达注记、贴士、侧栏、摘要、插入的引用等作为补充主体的内容。
    • figure:是对多个元素进行组合并展示的元素,通常与 figcaption 联合使用。
    • code:表示一段代码块。
    • dialog:用于表达人与人之间的对话,该元素包含 dt 和 dd 这两个组合元素, dt 用于表示说话者,而 dd 用来表示说话内容。

    行内语义性元素: 主要完成web页面具体内容的引用和描述,是丰富内容展示的基础。

    • meter:表示特定范围内的数值,可用于工资、数量、百分比等。
    • time:表示时间值。
    • progress:用来表示进度条,可通过对其 max 、 min 、 step 等属性进行控制,完成对进度的表示和监视。
    • video:视频元素,用于支持和实现视频文件的直接播放,支持缓冲预载和多种视频媒体格式。
    • audio:音频元素,用于支持和实现音频文件的直接播放,支持缓冲预载和多种音频媒体格式。

    交互性元素: 主要用于功能性的内容表达,会有一定的内容和数据的关联,是各种事件的基础。

    • details:用来表示一段具体的内容,但是内容默认可能不显示,通过某种手段(如单击)与 legend 交互才会显示出来。
    • menu:主要用于交互菜单(曾被废弃又被重新启用的元素)。
    • command:用来处理命令按钮(已被弃用,MDN中查找不到)。
  2. 多媒体支持:HTML5 提供了 videoaudio

  3. Canvas: HTML5 引入了 <canvas> 标签,允许通过 JavaScript 来绘制图形、制作动画和处理图像。

  4. 本地存储:HTML5 提供了本地存储功能,如 localStoragesessionStorage ,以便在客户端存储数据。

  5. 表单控件: HTML5 增加了一些新的表单控件,如日期选择器、颜色选择器、范围输入等,提供更多选择和输入方式。

伪类和伪元素的区别

伪类和伪元素是CSS中的两个不同概念:

  1. 伪类(Pseudo-classes):伪类用于向选择器添加特殊的状态,例如 :hover(鼠标悬停状态)、:active(鼠标点击状态)、:first-child(选择第一个子元素)等。它们可以用于根据用户操作或文档的状态来选择元素。
  2. 伪元素(Pseudo-elements):伪元素允许你为元素的特定部分添加样式,例如::before(在元素内容之前插入内容)、::after(在元素内容之后插入内容)、::first-line(选择元素的第一行文本)等。它们可以用于创建一些文档中不存在的元素或为元素的特定部分添加样式。

总的来说,伪类用于选择元素的特定状态,而伪元素用于选择元素的特定部分。

HTML5语义化的优点

  1. 更好的可读性:使用语义化标签可以使代码更易于理解和维护,因为它清晰地描述了内容的结构。
  2. 更好的搜索引擎优化(SEO):搜索引擎可以更好地理解网页的内容结构,因此更容易索引网页内容。
  3. 更好的可访问性:语义化标签可以提高网站的可访问性,使得使用辅助技术的用户更容易理解页面内容。
  4. 更好的跨平台兼容性:语义化标签有助于确保网页在不同设备和平台上的兼容性,例如在移动设备或屏幕阅读器上的显示效果更佳。
  5. 更好的代码组织:使用语义化标签可以帮助开发者更好地组织和管理页面结构,使得代码更加清晰和易于维护。 总的来说,HTML5 语义化可以提高网页的质量和可维护性,同时改善用户体验和网站的表现。

元素属性

title 与 h3,b 与 strong,i 与 em 的区别

titleh3bstrongiem
没有明确意义只是标题表示层次明确的标题,对页面信息的抓取有很大帮助加粗标明重点内容,有语气加强的含义,使用阅读器时会重读斜体强调文本

src、href 的区别

标签区别
src替换当前元素,同步
href在当前文档和引用资源之间确立联系,异步。

img元素 title、alt 的区别

img属性区别
title为属性提供信息,当鼠标滑动到元素上的时候显示
alt用于图片无法加载时显示

全局属性

accesskey规定激活元素(使元素获得焦点)的快捷键。
class规定元素的一个或多个类名(引用样式表中的类)。
contenteditable规定元素内容是否可编辑。
contextmenu规定元素的上下文菜单。上下文菜单在用户点击元素时显示。(主流浏览器无法支持)
data-*用于存储页面或应用程序的私有定制数据。
dir规定元素中内容的文本方向。
draggable规定元素是否可拖动。
dropzone规定在拖动被拖动数据时是否进行复制、移动或链接。
hidden规定元素仍未或不再相关。
id规定元素的唯一 id。
lang规定元素内容的语言。
spellcheck规定是否对元素进行拼写和语法检查。
style规定元素的行内 CSS 样式。
tabindex规定元素的 tab 键次序。
title规定有关元素的额外信息。
translate规定是否应该翻译元素内容。(主流浏览器无法支持)

置换元素

浏览器根据元素的标签和属性,来决定元素的具体显示内容。 例如:浏览器根据标签的src属性显示图片。根据标签的type属性决定显示输入框还是按钮。

置换元素在其显示中生成了框,这也就是有的内联元素能够设置宽高的原因。<img /> <input /> <textarea /> <select /> <object />都是置换元素,这些置换元素往往没有实际内容,即是一个空元素。

target的打开方式

  • _blank :在新浏览器窗口中打开链接文件
  • _parent :将链接的文件载入含有该链接框架的父框架集或父窗口中。如果含有该链接的框架不是嵌套的,则在浏览器全屏窗口中载入链接的文件,就象 _self 参数一。
  •  _self :在同一框架或窗口中打开所链接的文档。此参数为默认值,通常不用指定。但是我不太理解。
  •  _top :在当前的整个浏览器窗口中打开所链接的文档,因而会删除所有框架。

iframe有哪些缺点

  • iframe会阻塞主页面的 Onload 事件;
  • 搜索引擎的检索程序无法解读这种页面,不利于 SEO;
  • iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载。

使用iframe之前需要考虑上述缺点。如果需要使用 iframe ,最好是通过 javascript。动态给iframe添加 src 属性值,这样可以绕开上述问题。

图片

图片的格式

  1. jpg

    • 支持的颜色比较丰富,不支持透明效果,不支持动图
    • 一般用来显示照片
  2. gif

    • 支持的颜色比较少,支持简单透明,动图
    • 颜色单一的图片,动图
  3. png

    • 支持的颜色丰富,支持复杂透明,不支持动图
    • 颜色丰富,复杂透明图片(专业为网页而生)
  4. webp

    • 谷歌新推出的专门用来表示网页中图片的一种格式

    • 它具备其他图片全优点且文件小

      缺点:兼容性不好

  5. base64

    • 将图片使用 base64 进行编码,通过字符的形式引入图片
    • 一般都是一些需要和网页一起加载的图片采用 base64
拓展名MIME透明动画IE兼容性特点
.icoimage/x-icon×IE早期浏览器只支持 favicon.ico
.bmpimage/bmp××IEwindows 系统原生支持,图片信息丰富
.jpgimage/jpeg××IE可控制品质,模糊到清晰或渐进加载,常见于照片
.pngimage/png×IE6(不透明)可控制品质、位数,常见于绘画
.gifimage/gifIE基于颜色透明,有毛边,256颜色上限,适合动画
.svgimage/svg+xml×IE9+无损放大,可调色、修改,更常见于图标
.apngimage/apngEdgeMozilla主导,兼容PNG浏览器即可显示第一帧,压缩率较高,无毛边
.webpimage/webpEdgeCoogle主导,压缩率更高,无毛边,常见于微信公众号
.avifimage/avif×Netflix主导,压缩率更高,无毛边,同压缩比效果有时超过 webp

图片元素alt属性

alt 属性用来为图像定义一串预备的可替换的文本。替换文本属性的值是用户定义的。在浏览器无法载入图像时,替换文本属性告诉读者她们失去的信息。此时,浏览器将显示这个替代性的文本而不是图像。为页面上的图像都加上替换文本属性是个好习惯,这样有助于更好的显示信息,并且对于那些使用纯文本浏览器的人来说是非常有用的。

audio

audio 常用属性

  1. src : 指定音频文件的 URL
  2. controls : 显示音频播放器的控件,如播放按钮、音量控制等。
  3. autoplay : 指定音频在页面加载后是否自动播放。
  4. loop : 指定音频是否应该循环播放。
  5. preload : 指定页面加载时是否应该预先加载音频。可以取值为 autometadatanone
  6. muted: 指定音频是否应该处于静音状态。
  7. volume: 指定音频的默认音量。
  8. crossorigin: 指定音频的跨域设置,用于跨域访问音频资源。
  9. poster: 指定一个预览图像,当音频未加载时显示。
  10. muted: 是否静音
  11. currentSrc: 当前播放地址
  12. currentTime: 当前播放时长 单位 s
  13. duration: 音频时长 单位 s
  14. playbackRate: 播放速度

audio 常用函数

  1. load(): 加载音频、视频软件
  2. play(): 开始播放音频,或重新播放。
  3. pause(): 暂停播放
  4. canPlayType(obj):测试是否支持给定的 Mini 类型文件

audio 常用事件

  1. oncanplay: 音频可以播放事件(缓冲已足够开始时)
  2. oncanplaythrough: 音频可以不缓冲直接从头执行到尾
  3. ondurationchange: 当媒体时长被改变
  4. ontimeupdate: 播放时间更新的事件
  5. onended: 当音频结束播放事件
  6. onpause: 当音频播放暂停事件
  7. onvolumechange: 当音量发生改变时触发

CSS

基础知识

CSS 的基本语法和结构

link和@import的区别

<link rel='stylesheet' rev='stylesheet' href='CSS文件' type='text/css' media='all'/>

<style type='text/css' media='screen'>
@import url('CSS文件');
</style>

两者都是外部引用CSS的方式,但是存在一定的区别:

  1. link 是 XHTML 标签,除了加载 CSS 外,还可以定义 RSS 等其他事务; @import 属于 CSS 范畴,只能加载 CSS 。
  2. link 引用 CSS 时,在页面载入时同时加载; @import 需要页面网页完全载入以后加载。
  3. link 是 XHTML 标签,无兼容问题; @import 是在 CSS2.1 提出的,低版本的浏览器不支持。
  4. link 支持使用 Javascript 控制 DOM 去改变样式;而 @import 不支持。

使用css来修改元素的样式的方法

  1. 内联样式、行内样式
    • 在标签内部通过style属性来设置元素的样式
    • 问题:如果使用内联样式,样式只能对一个标签生效,并且当样式发生变化时,必须逐一修改,开发时不用内联样式
  2. 内联样式表
    • 将样式编写到head中的style标签里,然后通过css选择器来选中元素并设置各种样式
    • 可以同时为多个标签设置样式,并且修改时只需修改一处
    • 问题:只能对一个网页起作用,不能跨页面进行复用
  3. 外部样式表
    • 可以将 css 样式编写到一个外部的 css 文件中,通过 link 标签来引入外部 css 文件
    • 样式通过 link 标签进行引入,实现了不同网页之间复用
    • 将样式编写到外部 css 文件中,可以使用到浏览器的缓存机制,从而加快网页的加载速度。

选择器

CSS选择符

id选择器(#myid)、类选择器(.myclassname)、标签选择器(div, h1, p)、相邻选择器(h1 + p)、子选择器(ul > li)、后代选择器(li a)、通配符选择器(*)、属性选择器(a[rel=”external”])、伪类选择器(a:hover, li:nth-child)

是否可继承属性

  • 可继承的属性: font-size, font-family, color,text-align
  • 不可继承的样式: border, padding, margin, width, height

优先级

  1. 同类型,同级别的样式后者先于前者
  2. ID > 类样式 > 标签 > *
  3. 内联>ID选择器>伪类|属性选择器|类选择器>标签选择器|伪元素>通用选择器(*)>关系选择器|继承的样式
  4. 具体 > 泛化的,特殊性即css优先级
  5. 近的 > 远的 (内嵌样式 > 内部样式表 > 外联样式表)
    1. 内嵌样式:内嵌在元素中,<span style="color:red">span</span>
    2. 内部样式表:在页面中的样式,写在<style></style>中的样式
    3. 外联样式表:单独存在一个 css 文件中,通过 link 引入或 import 导入的样式
  6. important 权重最高,比 inline style 还要高

CSS3新增伪类

  • :first-of-type : 选择属于其父元素的首个元素
  • :last-of-type : 选择属于其父元素的最后元素
  • :only-of-type : 选择属于其父元素唯一的元素,父元素中只包含一个目标元素,但可以包含别的元素
  • :only-child : 选择属于其父元素的唯一子元素,父元素中只包含一个目标元素,且不包含别的元素
  • :nth-child(2) : 选择属于其父元素的第二个子元素
  • :enabled :disabled : 表单控件的禁用状态。
  • :checked : 单选框或复选框被选中。

元素类型

块元素、行内元素、行内块元素

  1. 块元素

    • 独霸一行,总是在新行上开始
    • 宽度缺省是它父级元素的100%,除非设定一个宽度
    • 高度、行高、外边距、内边距都可以设置
    • 可以容纳其他内联元素或者其他块元素
  2. 行内元素

    • 和其他元素都在一行上,遇到父级元素边界会自动换行
    • 高、行高以及内外边距都不可以改变
    • 宽度与内容一样宽,且不可改变
    • 行内元素只能容纳文本或者其他行内元素

    对于行内元素,需要注意的是:

    • 设置宽度width无效,设置高度无效,可以通过设置line-height来设置
    • 设置margin只有左右有效,上下无效
    • 设置padding只有左右有效,上下无效
  3. 行内块元素

    • 元素排列在一行
    • 宽度默认由内容决定
    • 元素间默认有间距
    • 支持宽高、外边距、内边距的所有样式的设置

display :设置元素显示的类型

  • inline:将元素设置为行内元素
  • block:将元素设置为块元素
  • inline-block:将元素设置为行内块元素,行内块,既可以设置宽度和高度又不会独占一行
  • table:将元素设置为一个表格
  • none:将元素不在页面中显示

盒模型( box-sizing )

css 将页面中所有元素都设置为一个矩形的盒子,每一个盒子都由以下几个部分组成:

内容区(content)、内边距(padding)、边框(border)、外边距(margin)

  • 内容区( content ) : 元素内容。
  • 内边距( padding ) : 定义元素边框与元素内容之间的距离。
  • 边框( border ) : 边框样式定义要显示怎样一个元素边界。
  • 外边距( margin ) : 是指相邻同辈元素之间的距离。相邻元素块的margin叠加显示
  • 轮廓线( outline ) : 轮廓线,画在边框外,外边距里。轮廓和边框不同点:轮廓不会影响可见框的大小

box-sizing属性: 用来控制元素的盒子模型的解析模式,默认为 content-box

  • context-box: W3C的标准盒子模型,设置元素的 height/width 属性指的是 content 部分的高/宽。宽度=内容的宽度(content)+ border + padding + margin
  • border-box: IE传统盒子模型。设置元素的 height/width 属性指的是 border + padding + content 部分的高/宽。宽度=内容宽度(content+border+padding)+ margin

overflow 属性

  • 参数是 scroll 时候,必会出现滚动条。
  • 参数是 auto 时候,子元素内容大于父元素时出现滚动条。
  • 参数是 visible 时候,溢出的内容出现在父元素之外。
  • 参数是 hidden 时候,溢出隐藏。

布局

浮动

通过浮动可以使一个元素向其父元素的左侧或右侧移动,float:left。 可选值:none 默认值,元素不浮动,left 元素向左浮动,right 元素向右浮动。

注意:元素设置浮动之后,水平布局等式失效。会完全从文档流中脱离,不再占用文档流的位置。元素下边的还在文档流中的元素会自动向上移动。

浮动的特点

  1. 浮动的元素会完全脱离文档流,不再占据文档流中的位置
  2. 元素下边的还在文档流中的元素会自动向上移动。
  3. 设置浮动之后,元素会向父元素的左侧或者右侧移动
  4. 浮动元素默认不会从父元素中移出
  5. 浮动元素不会盖住其他浮动元素
  6. 如果浮动元素的上边是个没有浮动的块元素,则浮动元素无法上移
  7. 浮动元素不会超过它上边的浮动兄弟元素,最多一样高

浮动的作用

是让页面中的元素可以水平排列,浮动元素不会盖住文字,文字会自动环绕在浮动元素周围,利用浮动来设置文字环绕图片的效果

元素设置浮动以后,会从文档流中脱离,从文档流中脱离后,元素有些特点也会发生变化

脱离文档流特点

  1. 块元素:

    • 块元素不再独占页面一行
    • 脱离文档流之后,块元素宽度高度默认被内容撑开
  2. 行内元素:

    • 行内元素脱离文档流后变成块元素
    • 脱离文档流后,不再区分块和行内

清除浮动

clear 属性: 清除浮动元素对当前元素所产生的影响

  • left 清楚左侧浮动元素对当前元素的影响,
  • right 清楚右侧浮动元素对当前元素的影响,
  • both 清除两侧中最大影响的那一侧

原理:设置清除浮动之后,会为元素自动添加一个上外边距,使其不受浮动影响

清除浮动的方式

  1. 父级div定义height 
    • 原理:父级 div 手动定义 height ,就解决了父级 div 无法自动获取到高度的问题 
    • 优点:简单、代码少、容易掌握
    • 缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级 div 不一样时,会产生问题
    • 建议:不推荐使用,只建议高度固定的布局时使用
  2. 结尾处加空div标签 clear:both
    • 原理:添加一个空 div ,利用css clear:both 清除浮动,让父级 div 能自动获取到高度 
    • 优点:简单、代码少、浏览器支持好、不容易出现怪问题 
    • 缺点:不少初学者不理解原理;如果页面浮动布局多,就要增加很多空 div,让人感觉很不好 
    • 建议:不推荐使用,但此方法是以前主要使用的一种清除浮动方法 
  3. 父级div定义伪类:afterzoom
    • 原理:IE8以上和非IE浏览器才支持:after,原理和方法2有点类似,zoom(IE转有属性)可解决ie6,ie7浮动问题 
    • 优点:浏览器支持好、不容易出现怪问题(目前:大型网站都有使用,如:腾迅,网易,新浪等等) 
    • 缺点:代码多、不少初学者不理解原理,要两句代码结合使用才能让主流浏览器都支持。
    • 建议:推荐使用,建议定义公共类,以减少 CSS 代码。
.father::after {
  content: "";
  display: block;
  clear: both;
}
  1. 父级div定义overflow:hidden或者overflow:auto
    • 原理:必须定义widthzoom:1,同时不能定义height,使用overflow:hidden或者overflow:auto时,浏览器会自动检查浮动区域的高度 
    • 优点:简单、代码少、浏览器支持好 
    • 缺点overflow:hidden不能和position配合使用,因为超出的尺寸的会被隐藏。overflow:auto,内部宽高超过父级div时,会出现滚动条
    • 建议:只推荐没有使用position或对overflow:hidden理解比较深的朋友使用。

定位 position

  1. 相对定位 relative

    特点:

    1. 当元素开启相对定位以后,若不设置偏移量则不会发生任何变化
    2. 相对定位是参照于元素在文档流中的位置进行定位的
    3. 相对定位会提升元素的层级
    4. 相对定位不会使元素脱离文档流
    5. 相对定位不会改变元素的性质,块或行内
  2. 绝对定位 absolute

    特点:

    1. 开启绝对定位后,如不设置偏移量,元素位置不会发生变化
    2. 开启绝对定位后,元素会从文档流中脱离
    3. 绝对定位会改变元素的性质,行内变成块,块的宽高被内容撑开
    4. 绝对定位会使元素提升一个层级
    5. 绝对定位是相对于其包含块进行定位的

    包含块 containing block

    正常情况下:

    • 包含块就是离当前元素最近的祖先块元素
    • 绝对定位的包含块:
      • 包含块就是离它最近的开启了定位的祖先包含元素
      • 如果所有祖先元素都没有开启定位,则根元素就是包含块
      • html(根元素、初始包含块)
  3. 固定定位 fixed

    • 固定定位也是一种绝对定位,所以固定定位的大部分特地都和绝对定位一样
    • 唯一不同的是固定定位永远参照于浏览器的视角进行定位
    • 固定定位的元素不会随网页的滚动条滚动
  4. 粘滞定位 sticky

    • 粘滞定位和相对定位的特点基本一致
    • 不同的是粘滞定位可以在元素到达某个位置时将其固定

弹性布局flex

  1. 容器属性:

    • display: flex; 定义容器为弹性布局容器
    • flex-direction: 定义主轴的方向(rowrow-reversecolumncolumn-reverse
    • flex-wrap: 定义是否换行(nowrapwrapwrap-reverse
    • justify-content: 定义主轴上的对齐方式(flex-startflex-endcenterspace-betweenspace-around
  2. 项目属性:

    • order: 定义项目的排列顺序
    • flex-grow: 定义项目的放大比例
    • flex-shrink: 定义项目的缩小比例
    • flex-basis: 定义在分配多余空间之前,项目占据的主轴空间
    • flex: 简写属性,包括 flex-growflex-shrinkflex-basis
  3. 对齐方式:

    • align-items: 定义项目在交叉轴上的对齐方式(flex-startflex-endcenterbaselinestretch
    • align-content: 定义多根轴线的对齐方式(flex-startflex-endcenterspace-betweenspace-aroundstretch

网格布局 grid

  1. 容器属性

    • display: grid; 定义容器为网格布局容器
    • grid-template-rows, grid-template-columns: 定义网格的行和列的大小和数量
    • grid-template-areas: 通过命名区域定义网格布局
    • grid-template: 简写属性,包括 grid-template-rowsgrid-template-columns
    • grid-gap, grid-row-gap, grid-column-gap: 定义网格行间距和列间距
  2. 项目属性:

    • grid-row-start, grid-row-end, grid-column-start, grid-column-end: 定义项目的起始和结束位置
    • grid-row, grid-column: 简写属性,包括上述属性
    • grid-area: 定义项目所占的区域
  3. 对齐与布局:

    • justify-items: 定义项目在单元格内的水平对齐方式
    • align-items: 定义项目在单元格内的垂直对齐方式
    • justify-content: 定义整个网格在容器内的水平对齐方式
    • align-content: 定义整个网格在容器内的垂直对齐方式
    • justify-self: 定义单个项目在单元格内的水平对齐方式
    • align-self: 定义单个项目在单元格内的垂直对齐方式

外边距重叠

块的上外边距( margin-top )和下外边距( margin-bottom )有时合并(折叠)为单个边距,其大小为单个边距的最大值(或如果它们相等,则仅为其中一个),这种行为称为边距折叠。 设定 floatposition=absolute 的元素不会产生外边距重叠行为。

外边距重叠三种情况:

  1. 同一层相邻元素之间:两个元素之间的外边距重叠,除非后一个元素加上 clear-fix 清除浮动。
  2. 没有内容将父元素和后代元素分开:就会出现父块元素和其内后代块元素外边界重叠,重叠部分最终会溢出到父级块元素外面。
  3. 空的块级元素:当一个块元素上边界 margin-top 直接贴到元素下边界 margin-bottom 时也会发生边界折叠。

高度塌陷、BFC、IFC

高度塌陷

在浮动布局中,父元素的高度默认是被子元素撑开的,当子元素浮动后,会脱离文档流,将无法撑起父元素高度,导致父元素的高度丢失,父元素高度丢失以后,其下的元素会自动上移,导致页面布局混乱

BFC(Block Formatting Context)块级格式化环境

BFC(Block Formatting Contexts)直译为"块级格式化上下文",就是页面上的一个隔离的渲染区域,容器里面的子元素不会在布局上影响到外面的元素,为一个元素开启BFC后会变成一个独立的布局区域。从清除浮动引起的BFC,IFC,FFC再学习 - SegmentFault 思否

  • 元素开启BFC后的特点

    • 开启BFC的元素不会被浮动元素所覆盖
    • 开启BFC的元素子元素和父元素外边距不会重叠
    • 开启BFC的元素可以包含浮动的子元素
  • 开启方式(特殊方式)

    • 设置元素的浮动:父元素浮动 float: left
    • 将元素设置为table-cell, table-caption, inline-block 中的任何一个 display: inline-block
    • 将元素的 overflow 设置为一个非 visible 的值 overflow: hidden
    • position 的值为 absolutefixed
    • display:flow-root: 可以让元素块状化,同时包含格式化上下文BFC,可以用来清除浮动,去除 margin 合并,实现两栏自适应布局等子元素自适应布局效果。

IFC

IFC(Inline Formatting Contexts)直译为"内联格式化上下文"。在网页布局中合理使用inline formating context(IFC) - 荒漠千蝶 - 博客园 (cnblogs.com)。 IFC 的 line box(线框)高度由其包含行内元素中最高的实际高度计算而来(不受到竖直方向的 padding / margin 影响)

IFC作用

  • 水平居中:当一个块要在环境中水平居中时,设置其为 inline-block 则会在外层产生IFC,通过 text-align 则可以使其水平居中。
  • 垂直居中:创建一个IFC,用其中一个元素撑开父元素的高度,然后设置其 vertical-align:middle,其他行内元素则可以在此父元素下垂直居中。利用vertical-align:middle垂直居中 - 简书 (jianshu.com)

响应式设计和媒体查询

响应式设计是一种网页设计和开发的方法,旨在使网站能够在各种设备上提供最佳的视觉和用户体验。媒体查询是实现响应式设计的关键工具之一。 媒体查询是CSS3的一部分,允许开发者根据设备的特定特征(如屏幕宽度、高度、设备方向、分辨率等)来应用不同的样式。主要包括以下部分:

1. 基本结构:

@media (max-width: 768px) {
 /* 在最大宽度为768像素时应用的样式 */
}

@media (min-width: 768px) and (max-width: 1024px) {
 /* 在宽度介于768像素和1024像素之间时应用的样式 */
}

2. 常见应用:

  • 根据屏幕尺寸调整布局:例如,在小屏幕上将侧边栏转换为顶部导航
  • 图像和媒体资源的响应式调整:例如,根据屏幕尺寸加载不同大小的图像
  • 字体大小和间距的调整:例如,在小屏幕上增加文字大小以提高可读性

动画与过渡

  • 过渡 transition 是一种元素从一种样式逐渐变为另一种样式的效果。它可以在元素的状态变化时产生平滑的过渡效果,比如在鼠标悬停时改变背景颜色或者大小。过渡是在特定的状态变化时触发的。
  • 动画 animation 则是指元素的样式在一段时间内发生连续的变化。通过使用 @keyframes 规则,可以定义元素的动画过程,并将其应用于元素。动画是可以无限循环播放的。

过渡 transition

  1. transition-property:指定应用过渡效果的 CSS 属性的名称,可以是单个属性或多个属性的列表。
  2. transition-duration:指定过渡效果持续的时间,通常以秒(s)或毫秒(ms)为单位。
  3. transition-timing-function:指定过渡效果的速度曲线,控制过渡过程中属性值的变化速度,包括线性变化、加速变化、减速变化等ease,ease-in,linear,step-start,step-end,steps(4,jump-end)
  4. transition-delay:指定过渡效果开始执行之前的延迟时间,通常以秒(s)或毫秒(ms)为单位。

过渡 transition是指元素从一种样式逐渐变为另一种样式的效果。例如,下面的代码将使元素的背景颜色在状态变化时产生平滑的过渡效果:

.element {
    transition: background-color 0.3s ease;
}

.element:hover {
    background-color: #ff0000;
}

动画 animation

  1. animation-name:指定 @keyframes 规则的名称,定义了动画的关键帧。
  2. animation-duration:指定动画一个周期的持续时间,通常以秒(s)或毫秒(ms)为单位。
  3. animation-timing-function:指定动画的速度曲线,控制动画过程中属性值的变化速度,包括线性变化、加速变化、减速变化等。
  4. animation-delay:指定动画开始执行之前的延迟时间,通常以秒(s)或毫秒(ms)为单位。
  5. animation-iteration-count:指定动画播放的次数,可以是一个整数或者"infinite"表示无限播放。
  6. animation-direction:指定动画播放的方向,可以是正向(normal)、反向(reverse)、交替反向(alternate-reverse)等。
  7. animation-fill-mode:指定动画在播放之前和之后如何应用样式,包括保持(forwards)、返回(backwards)、保持和返回(both)等选项。
  8. animation-play-state:指定动画的播放状态,可以是运行(running)或暂停(paused)。

例如,下面的代码将创建一个简单的旋转动画,这段代码会使元素无限制地以线性方式旋转,每次旋转经过2秒:

@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

.element {
    animation: spin 2s linear infinite;
}

兼容性与性能

浏览器兼容性

浏览器兼容性前缀(vendor prefixes)是CSS3属性的前缀,用于指明属性适用的浏览器厂商。

  • -webkit-:Chrome、Safari等基于WebKit引擎的浏览器。
  • -moz-:Firefox浏览器。
  • -o-:Opera浏览器(早期版本)。
  • -ms-:Internet Explorer浏览器和Edge浏览器。

性能优化

减少重绘与回流

重绘是指更改元素样式而不影响其布局的过程,而回流是指更改布局导致其他元素的重新计算位置和大小。要减少重绘和回流,可以采取以下措施:

  1. 使用 CSS 合并:尽量减少样式更改,合并多个样式更改为一次操作,避免频繁的样式变更。
  2. 避免频繁操作 DOM:尽量减少对 DOM 结构的操作,例如批量插入或移除元素,以减少回流的次数。
  3. 使用文档片段(Document Fragment):将需要多次操作的 DOM 元素先加入到文档片段中,完成操作后再统一加入文档,减少回流次数。
  4. 使用 CSS3 硬件加速:通过 transform , opacity , filter , will-change 属性等,将一些元素的渲染操作交给 GPU 处理,减少 CPU 的回流重绘操作。
    • 硬件加速原理: 浏览器首先页面解释成 DOM 树,DOM 树和 CSS 让浏览器构建渲染树,渲染树包含渲染对象 —— 在页面中需要渲染的元素,每一个渲染对象被分配到一个图层中,每一个图层被更新到 GPU,这里的秘诀就在于通过 transform 的层会使用 GPU 渲染,因此不需要重绘,就像 3D 图形一样。这个转换是单独处理的。
  5. 使用事件委托:将事件处理程序尽可能绑定到父级元素上,避免大量事件处理器的绑定。

使用合适的单位

使用合适的单位可以提高性能的主要原因在于它们能够减少浏览器的计算负担和减少页面渲染所需的时间。以下是一些原因:

  1. 相对单位的灵活性:相对单位(如 %、em、rem、vw、vh)能够根据父元素或视口尺寸进行调整,因此能够更好地适应不同设备的屏幕尺寸,从而减少需要进行回流和重绘的次数。
  2. 相对单位的适应性:相对单位能够更好地适应用户的字体大小偏好和浏览器的默认字体大小,从而提高可访问性。
  3. CSS Grid等新特性的支持:新的CSS特性(如CSS Grid)中引入了更适合响应式设计的单位,如fr单位,这些单位能够更好地适应不同屏幕尺寸,减少了对JavaScript进行手动计算的需要。
  4. 避免不必要的计算:使用像素单位时,可以减少浏览器对相对单位进行计算的时间,因为像素单位在计算时不需要依赖父元素或视口尺寸。

精灵图

精灵图(Sprite sheet)是指将多个图像合并到单个图像文件中的技术。在Web开发中,精灵图通常用于将网站中多个小图标或图片合并到一个文件中,以减少HTTP请求次数,从而提高页面加载性能。

通过使用精灵图,可以减少网页加载时需要请求的文件数量,从而减少了服务器和浏览器之间的通信次数,减轻了网络流量,加快了网页加载速度。在网页渲染时,通过调整精灵图的背景位置,可以轻松地显示所需的图像,同时也可以减小页面所需的总体资源大小。

图标字体

图标字体是一种使用字体文件中的符号或图标来呈现图像的技术。这种技术通过将图标设计为字体的特定字符,然后在网页中使用 CSS 来指定该字体,进而将图标呈现出来。 使用图标字体带来了一些优势:

  1. 减少HTTP请求:与使用单独的图像文件相比,使用图标字体可以减少 HTTP 请求的数量,从而提高页面加载性能。
  2. 易于调整颜色和大小:由于图标字体实际上是文本,因此可以使用 CSS 属性(如color和font-size)轻松地调整图标的颜色和大小。
  3. 易于扩展和维护:添加新的图标只需更新字体文件,而不必管理和维护多个图像文件。
  4. 矢量化:字体图标是矢量化的,这意味着它们可以在不损失清晰度的情况下缩放到任意大小。

样式

隐藏元素

display:noneopacity:0,visibility:hidden。三种方法均可隐藏元素。不同在于以下几点:

  1. 空间占据

    • display:none 的元素不会占据,但是设置 display:none 会引发回流和重绘
    • opacity:0visibility:hidden 的元素会占据位置,但是改变这属性时只会触发重绘
  2. 子元素继承

    • display:none 不会被子元素继承,但是父元素都不在了,子元素自然也就不会显示了。
    • visibility:hidden 会被子元素继承,可以通过设置子元素 visibility:visible 使子元素显示出
    • opacity: 0 也会被子元素继承,但是不能通过设置子元素 opacity: 0 使其重新显示
  3. 事件绑定

    • display:none 的元素都已经不再页面存在了,因此肯定也无法触发它上面绑定的事件;
    • visibility:hidden 元素上绑定的事件也无法触发;
    • opacity: 0 元素上面绑定的事件是可以触发的。
  4. 过渡动画

    • transition 对于 displayvisibility 是无效的,对于 opacity 是有效

居中div,居中浮动元素,居中绝对定位的div

  1. 绝对定位:父元素开启相对定位,子元素开启绝对定位
.center {
  width: 100px;
  height: 100px;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
}
  1. 负margin居中(传统方法),需知道元素宽高
.box {
  width: 200px;
  height: 200px;
  position: relative;
}
.chl_box {
  width: 100px;
  height: 100px;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -50px;
  margin-left: -50px;
}
  1. margin固定宽高居中
.chl_box {
  width: 100px;
  height: 100px;
  margin: 50px 50px;
}
  1. flex居中
.box {
  display: flex;
  justify-content: center;
  align-items: center;
}
  1. transform居中,IE9 以下不支持
.box {
    width: 200px;
    height: 200px;
    position: relative;
}
.chl_box {
    width: 100px;
    height: 100px;
    position: relative;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
}
  1. 不确定宽高居中
.box {
  width: 200px;
  height: 200px;
  position: relative;
}

.chl_box {
  position: absolute;
  left: 25%;
  right: 25%;
  top: 25%;
  bottom: 25%;
}
  1. 居中浮动元素
.outerbox {
  float: left;
  position: relative;
  left: 50%;
}

.innerbox {
  float: left;
  position: relative;
  right: 50%;
}

行内元素的间距问题

两个行内元素在一起,会出现一定的间距,即使将border、padding、margin都设置为零也无济于事,那么怎么才能去除这些间距呢?

  1. 重设字体:将行内元素的直接父级设置font-size=0px;再给行内元素设置字体大小就可以解决。
  2. 借助HTML注释:在两个行内元素之间加入 HTML 注释,告诉浏览器这中间不是换行也不是空格,而是连接在一起的,这样也可以解决。
  3. 取消标签闭合:把span标签的结束标签去掉,这样间隙就没有了。为了兼容 IE6/IE7 ,最后一个标签需要闭合。
  4. 设置子元素margin值为负数:元素之间间距的大小与上下文字体大小相关;并且同一大小的字体,元素之间的间距在不同浏览器下是不一样的,如:font-size:16px时,Chrome下元素之间的间距为8px,而Firefox下元素之间的间距为4px。所以不同浏览器下margin-right的负值是不一样的,因此这个方法不通用。
  5. 设置父元素,display:tableword-spacing:-1em

浏览器是怎样解析CSS选择器的

CSS选择器的解析是从右向左解析的。若从左向右的匹配,发现不符合规则,需要进行回溯,会损失很多性能。若从右向左匹配,先找到所有的最右节点,对于每一个节点,向上寻找其父节点直到找到根元素或满足条件的匹配规则,则结束这个分支的遍历。两种匹配规则的性能差别很大,是因为从右向左的匹配在第一步就筛选掉了大量的不符合条件的最右节点(叶子节点),而从左向右的匹配规则的性能都浪费在了失败的查找上面。

而在 CSS 解析完毕后,需要将解析的结果与 DOM Tree 的内容一起进行分析建立一棵 Render Tree(渲染树),最终用来进行绘图。在建立 Render Tree 时(WebKit 中的「Attachment」过程),浏览器就要为每个 DOM Tree 中的元素根据 CSS 的解析结果(Style Rules)来确定生成怎样的 Render Tree。

高级主题

  1. 自定义属性(CSS 变量)

    自定义属性,也被称为CSS变量,是一种在CSS中定义的可重复使用的值,可以通过使用var()函数在整个样式表中引用。通过自定义属性,可以在多个地方使用相同的值,从而更轻松地对整个网站的外观进行调整。使用自定义属性(CSS变量)的主要优势包括:

    1. 简化样式表:通过将重复使用的值定义为自定义属性,可以减少样式表中的重复内容,使样式表更加简洁和易于维护。
    2. 提高灵活性:自定义属性使得可以在一个地方定义值,在需要的地方引用,从而使得整个网站的外观更容易进行统一调整。
    3. 动态更新:自定义属性可以使用JavaScript动态更新,从而实现动态改变页面样式的功能。
    4. 适应响应式设计:通过在自定义属性中定义与布局和设计相关的值,可以更轻松地实现响应式设计,使网页更好地适应不同的屏幕尺寸和设备。
  2. CSS 预处理器(如 SASS、LESS)

    1. 变量:允许定义可重复使用的值,例如颜色、字体等,以便在整个样式表中引用。
    2. 嵌套规则:允许以层次结构的方式编写样式,提高了可读性并减少了重复。
    3. Mixins(混合) :允许将一组样式属性定义为一个可重用的块,并在需要时引用。
    4. 函数:允许定义和调用函数,以便在样式表中执行复杂的计算。
    5. 导入:允许将样式表分解为多个文件,并在需要时导入它们,有助于组织和管理样式表。
  3. CSS 模块化(BEM、SMACSS 等)

    1. BEM(块、元素、修饰符) :BEM是一种命名约定,它将样式表中的各个部分分为块(Block)、元素(Element)和修饰符(Modifier)。这种方法通过使用双下划线(__)和双短横线(--)来创建层次结构,使得样式规则更加清晰和可预测。
    2. SMACSS(可扩展和模块化的CSS) :SMACSS是一种用于组织CSS代码的方法,它强调将样式表分为基础、布局、模块、状态和主题等几个类别。这种方法通过建立一致的结构和分类来帮助开发人员更好地管理样式表。

浏览器

Cookies , sessionStorage , localStorage 的区别

  1. Cookies:

    • 用途:主要用于在客户端和服务器之间传递数据,可以存储少量文本数据,并在每次HTTP请求时发送到服务器。
    • 存储大小:每个cookie最多可以存储4KB的数据。
    • 有效期:可以设置过期时间,可以是会话级的(浏览器关闭时过期)或者持久性的(在指定的日期过期)。
    • 安全性:可以设置安全标志,防止被恶意篡改。
  2. sessionStorage:

    • 用途:用于在单个会话期间(即当页面打开时到页面关闭时)存储数据。
    • 存储大小:每个域名下可以存储5MB的数据。
    • 有效期:当浏览器选项卡或窗口关闭时数据会被清除。
  3. localStorage:

    • 用途:用于持久性地存储数据,数据不会随着浏览器关闭而消失。
    • 存储大小:每个域名下可以存储5MB的数据。
    • 有效期:除非被显式删除,否则数据永久保存在浏览器中。

浏览器标签页间通信

Broadcast Channel API

Broadcast Channel API:通过使用 Broadcast Channel API,不同标签页可以在同一浏览器中进行实时通信。一个标签页可以发送信息,而其他标签页可以监听并接收这些信息。

// 在一个标签页中创建一个新的Broadcast Channel
const channel = new BroadcastChannel('my_channel');

// 发送消息到其他标签页
channel.postMessage('Hello, other tabs!');

// 在另一个标签页中监听消息
const otherTabChannel = new BroadcastChannel('my_channel');
otherTabChannel.onmessage = function(event) {
  console.log('Received message: ' + event.data);
};

LocalStorage

LocalStorageStorage 事件:当一个标签页修改了 LocalStorage 中的数据时,其他标签页可以通过监听 Storage 事件来获取通知,并相应地更新自己的数据。

在第一个标签页中:
```javaScript
// 将数据存储到LocalStorage
localStorage.setItem('message', 'Hello, other tabs!');

// 发送Storage事件通知其他标签页
localStorage.setItem('message', 'Hello, other tabs!');
```
在其他标签页中

```javaScript
// 监听Storage事件,当LocalStorage中的数据被修改时触发
window.addEventListener('storage', function(event) {
  if (event.key === 'message') {
    // 更新页面中的数据
    document.getElementById('output').innerText = event.newValue;
  }
});
```

postMessage API

postMessage API:使用 postMessage API 可以在不同标签页之间安全地发送消息。这允许在不同域之间传递数据,但需要对消息来源进行验证。

在发送消息的标签页中
```javaScript
// 定义接收消息的目标窗口,通常是其他标签页的window对象
const targetWindow = otherWindow; // 这里应该替换为实际的目标窗口

// 发送消息
targetWindow.postMessage('Hello, other tabs!', 'http://目标窗口的域名');
```
在接收消息的标签页中
```javaScript
// 监听消息事件
window.addEventListener('message', function(event) {
  // 验证消息来源
  if (event.origin === 'http://发送消息的窗口的域名') {
    // 处理接收到的消息
    console.log('Received message: ' + event.data);
  }
});
```

Shared WorkersService Workers

Shared WorkersService Workers:这些技术可以在多个标签页之间共享数据或者进行通信,从而实现标签页间的协作。

**Shared Workers 示例代码**

```javaScript
// 创建一个共享的 Shared Worker
const worker = new SharedWorker('sharedWorker.js');

// 监听来自 Shared Worker 的消息
worker.port.onmessage = function(event) {
  console.log('Received message from Shared Worker: ', event.data);
};

// 向 Shared Worker 发送消息
worker.port.postMessage('Hello from main page!');
```

在`sharedWorker.js`文件中:

```javaScript
// 监听来自主页面的消息
self.onconnect = function(e) {
  const port = e.ports[0];

  port.onmessage = function(event) {
    console.log('Received message from main page: ', event.data);
    // 向主页面发送消息
    port.postMessage('Hello from Shared Worker!');
  };
};
```

**Service Workers 示例代码**

Service Workers 通常用于处理网络请求、缓存资源以及推送通知等操作。它们可以在后台运行,与页面分离,因此不会直接参与页面间的通信,但可以通过 postMessage API 与页面进行通信。

在 Service Worker 中,可以通过如下方式与页面通信:
```javaScript
// 在 Service Worker 中接收来自页面的消息
self.addEventListener('message', function(event) {
  console.log('Received message from page: ', event.data);
  // 向页面发送消息
  clients.matchAll().then(function(clients) {
    clients.forEach(function(client) {
      client.postMessage('Hello from Service Worker!');
    });
  });
});
```
在页面中,可以通过以下方式向 Service Worker 发送消息:

```javaScript
// 在页面中向 Service Worker 发送消息
navigator.serviceWorker.controller.postMessage('Hello from page!');
```


跨域通信

nginx - 前端常见跨域解决方案(全) - 个人文章 - SegmentFault 思否

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

同源策略

同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指协议+域名+端口三者相同,即便两个不同的域名指向同一个ip地址,也非同源。 同源策略限制以下几种行为:

  1. Cookie、LocalStorage 和 IndexDB 无法读取
  2. DOM 和 Js对象无法获得
  3. AJAX 请求不能发送

CORS

CORS(Cross-Origin Resource Sharing)是一种机制,允许网页应用从不同的域请求资源,并允许服务器端对这些跨域请求进行响应。通过在 HTTP 头中使用特定的 CORS 标头( Access-Control-Allow-Origin ),服务器可以指示浏览器是否允许跨域请求,以及允许哪些来源、方法和标头。

优点:

  1. 支持跨域资源访问:使得网页能够安全地从不同的域请求资源。
  2. 提高安全性:服务器可以灵活地控制允许跨域请求的来源、方法和标头,从而提高安全性。

缺点:

  1. 复杂性:配置 CORS 可能会增加开发和维护的复杂性。
  2. 兼容性问题:一些旧版本的浏览器对 CORS 支持不完善,可能需要特殊处理。
  3. 潜在的安全风险:不正确配置 CORS 可能导致安全漏洞,例如暴露敏感信息给不受信任的来源。

JSONP

JSONP 利用了 HTML 中 script 标签不受同源策略限制的特性。它通过动态创建 script 标签,将跨域请求发送到目标服务器上,目标服务器返回的数据会作为 JavaScript 函数的参数,从而实现跨域数据交换。

function handleResponse(data) {
  // 处理从跨域服务器返回的数据
  console.log(data);
}

var script = document.createElement('script');
script.src = 'http://example.com/api/data?callback=handleResponse';
document.body.appendChild(script);

优点

  1. 能够绕过浏览器的同源策略限制,实现跨域数据获取。
  2. 相对简单,易于实现和部署。
  3. 在一些古老的浏览器中仍然可以使用。

缺点

  1. 安全性问题:JSONP 存在安全风险,因为它需要服务器端支持,并且容易受到跨站脚本攻击(XSS)的影响。
  2. 仅支持 GET 请求:JSONP 仅支持 GET 请求,无法支持其他类型的 HTTP 请求方法。
  3. 无法处理错误:JSONP 无法像 XMLHttpRequest 那样处理 HTTP 错误状态码,因此难以进行错误处理。
  4. 可靠性问题:JSONP 的回调函数是在全局作用域中执行的,如果出现命名冲突,可能会导致意外行为。

iframe + postMessage

通过在当前页面中嵌入一个来自不同域的 iframe,可以利用 iframe 的内容窗口和父窗口之间的通信来进行数据交换。

在父页面中:

// 创建一个 iframe 元素
var iframe = document.createElement('iframe');
iframe.src = 'https://子域名.com/iframe.html';
document.body.appendChild(iframe);

// 监听来自 iframe 的消息
window.addEventListener('message', function(event) {
  // 确保消息来自预期的域
  if (event.origin !== 'https://子域名.com') return;

  // 处理收到的消息
  console.log('Received message from iframe: ' + event.data);
}, false);

// 向 iframe 发送消息
var message = 'Hello, iframe!';
iframe.contentWindow.postMessage(message, 'https://子域名.com');

在子域名.com 的 iframe.html 页面中:

// 监听来自父页面的消息
window.addEventListener('message', function(event) {
  // 确保消息来自预期的域
  if (event.origin !== 'https://父域名.com') return;

  // 处理收到的消息
  console.log('Received message from parent: ' + event.data);

  // 向父页面发送消息
  var message = 'Hello, parent!';
  event.source.postMessage(message, 'https://父域名.com');
}, false);

优点:

  1. 安全性:通过 postMessage 进行通信可以绕过同源策略,同时确保安全性,防止恶意网站获取用户敏感信息。
  2. 灵活性:允许在不同域的页面之间进行双向通信,可以用于实现单点登录、嵌入第三方内容等功能。
  3. 跨平台性:适用于不同浏览器和不同平台,提供了一种较为通用的跨域通信解决方案。

缺点:

  1. 复杂性:需要编写额外的 JavaScript 代码来处理消息的发送和接收,增加了开发和维护的复杂性。
  2. 安全风险:虽然 postMessage 可以确保安全通信,但在实际应用中仍需谨慎处理发送和接收的消息,以防止跨站脚本攻击(XSS)等安全问题。
  3. 兼容性:在一些旧版本的浏览器中,postMessage 的支持可能存在一些问题,需要进行兼容性处理。

document.domain

原理:

  1. 页面在加载时,若需要进行跨域通信,两个页面都将它们的 document.domain 设置为相同的顶级域名,比如example.com。
  2. 设置 document.domain 之后,这两个页面就可以自由地进行跨域通信,包括共享 cookie、调用 JavaScript 等操作,因为浏览器会认为它们属于同一个安全域。
  3. 需要注意的是,document.domain 只能设置为更高一级的域名,且一旦设置后就不能再修改为更低一级的域名。

优点:

  1. 简单易行:使用 document.domain 可以很容易地在同一顶级域名下的不同子域之间实现跨域通信,而无需复杂的消息传递机制。
  2. 适用范围广:适用于需要在同一顶级域名下的不同子域之间进行跨域通信的场景,能够方便地实现这种通信需求。

缺点:

  1. 安全性限制:document.domain 只能设置为更高一级的域名,因此在涉及到更复杂的跨域通信时,可能会存在安全风险。
  2. 限制较多:需要确保在设置 document.domain 时,两个页面的顶级域名是相同的,且一旦设置后就不能再修改为更低一级的域名,这种限制较多。
  3. 仅适用于特定场景:document.domain 只适用于同一顶级域名下的不同子域之间的跨域通信,对于其他跨域通信场景并不适用。

location.hash + iframe

原理:

  1. 父页面和嵌套的 iframe 页面位于不同的域名下,它们之间无法直接进行 JavaScript 交互。
  2. 父页面可以通过修改 iframe 的 src 属性,向 iframe 页面传递信息,而 iframe 页面可以通过监听父页面的 hashchange 事件来获取这些信息。
  3. 为了进行通信,父页面将要传递的信息编码为 hash 值,并将其附加到 iframe 的 URL 中,而 iframe 页面则通过监听父页面的 hashchange 事件来获取这些信息。

a.html:http://www.domain1.com/a.html

<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
    var iframe = document.getElementById('iframe');

    // 向b.html传hash值
    setTimeout(function() {
        iframe.src = iframe.src + '#user=admin';
    }, 1000);
    
    // 开放给同域c.html的回调方法
    function onCallback(res) {
        alert('data from c.html ---> ' + res);
    }
</script>

b.html:http://www.domain2.com/b.html

<iframe id="iframe" src="http://www.domain1.com/c.html" style="display:none;"></iframe>
<script>
    var iframe = document.getElementById('iframe');

    // 监听a.html传来的hash值,再传给c.html
    window.onhashchange = function () {
        iframe.src = iframe.src + location.hash;
    };
</script>

c.html:http://www.domain1.com/c.html

<script>
    // 监听b.html传来的hash值
    window.onhashchange = function () {
        // 再通过操作同域a.html的js回调,将结果传回
        window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', ''));
    };
</script>

优点:

  • 相对简单:使用 location.hash 结合 iframe 进行跨域通信相对简单,无需复杂的后端支持。
  • 支持性广泛:几乎所有现代浏览器均支持该方法,因此具有较好的兼容性。

缺点:

  • 传输容量有限:由于 hash 值的限制,传输内容受到长度限制,无法传递大量数据。
  • 安全性考虑:由于传输的信息会暴露在 URL 中,存在一定的安全风险,特别是在传递敏感信息时需要格外小心。
  • 单向通信:该方法只支持单向通信,父页面向 iframe 页面传递信息,而 iframe 页面无法直接向父页面传递信息。

window.name + iframe跨域

window.name属性的独特之处:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)

WebSocket协议跨域

需要后台配合修改协议,不兼容,需要使用 socket.io

WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。 原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容

前端代码:

<div>user input:<input type="text"></div>
<script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080');

// 连接成功处理
socket.on('connect', function() {
    // 监听服务端消息
    socket.on('message', function(msg) {
        console.log('data from server: ---> ' + msg); 
    });

    // 监听服务端关闭
    socket.on('disconnect', function() { 
        console.log('Server socket has closed.'); 
    });
});

document.getElementsByTagName('input')[0].onblur = function() {
    socket.send(this.value);
};
</script>

Nodejs socket后台:

var http = require('http');
var socket = require('socket.io');

// 启http服务
var server = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-type': 'text/html'
    });
    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

// 监听socket连接
socket.listen(server).on('connection', function(client) {
    // 接收信息
    client.on('message', function(msg) {
        client.send('hello:' + msg);
        console.log('data from client: ---> ' + msg);
    });

    // 断开处理
    client.on('disconnect', function() {
        console.log('Client socket has closed.'); 
    });         

nginx代理跨域

1、 nginx配置解决iconfont跨域

浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。

location / {
  add_header Access-Control-Allow-Origin *;
}

2、 nginx反向代理接口跨域

原理: 同源策略是浏览器的安全策略,不是 HTTP 协议的一部分。服务器端调用 HTTP 接口只是使用 HTTP 协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。

实现思路: 通过nginx配置一个代理服务器(域名与 domain1 相同,端口不同),反向代理访问domain2 接口,并且可以顺便修改 cookie 中 domain 信息,方便当前域 cookie 写入,实现跨域登录。

nginx具体配置:

#proxy服务器
server {
    listen       81;
    server_name  www.domain1.com;

    location / {
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;

        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为*
        add_header Access-Control-Allow-Credentials true;
    }
}

1.) 前端代码示例:

var xhr = new XMLHttpRequest();

// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;

// 访问nginx中的代理服务器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();

2.) Nodejs后台示例:

var http = require('http');
var server = http.createServer();
var qs = require('querystring');

server.on('request', function(req, res) {
    var params = qs.parse(req.url.substring(2));

    // 向前台写cookie
    res.writeHead(200, {
        'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'   // HttpOnly:脚本无法读取
    });

    res.write(JSON.stringify(params));
    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

Nodejs中间件代理跨域

node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。

前端常见的攻击手段和防御方法

前端常见的攻击方式及预防方法 - 简书 (jianshu.com)

  1. 跨站脚本(XSS)攻击:攻击者通过注入恶意脚本来篡改页面内容或窃取用户信息。
  2. 跨站请求伪造(CSRF)攻击:攻击者通过伪造用户的请求来执行未经授权的操作。
  3. 点击劫持:攻击者将透明的、可点击的层覆盖在诱导用户点击的页面上,以达到恶意目的。
  4. 同源策略绕过:攻击者试图绕过浏览器的同源策略,从而访问另一个域下的资源。

防御方法包括:

  1. 输入验证和数据过滤:对用户输入的数据进行验证和过滤,以防止XSS攻击。
  2. 使用CSRF令牌:在用户请求中包含CSRF令牌,以验证请求的合法性。
  3. X-Frame-Options头部:通过设置X-Frame-Options头部来防止点击劫持攻击。
  4. 同源策略:利用浏览器的同源策略,限制跨域资源的访问。

浏览器缓存

  1. 强缓存

    强缓存是指浏览器在请求资源时,先检查本地是否有缓存副本,如果有并且未过期,浏览器直接使用该缓存,不会向服务器发送请求。通过设置 HTTP 响应头中的 Expires:Mon, 06 Jan 2025 13:00:19 GMT(过期时间戳)Cache-Control:max-age=31536000(>0的数) 来实现。 当 Cache-Control 与 expires 两者都存在时,Cache-Control 优先级更高

    • Expires
      • 值为一个时间戳,服务器返回该资源缓存的到期时间。但 Expires 有个缺点,就是它判断是否过期是用本地时间来判断的,本地时间是可以自己修改的。到了 HTTP/1.1Expire 已经被 Cache-Control 替代
    • Cache-Control
      • public:资源客户端和服务器都可以缓存
      • privite:资源只有客户端可以缓存
      • no-cache:客户端缓存资源,但是是否缓存需要经过协商缓存来验证
      • no-store:不使用缓存
      • max-age:缓存保质期,是相对时间
        • Cache-Control: no-cache:这个很容易让人产生误解,误以为是响应不被缓存实际上Cache-Control: no-cache 是会被缓存的,是协商缓存的标识,只不过每次都会向服务器发起请求,来验证当前缓存的有效性
        • Cache-Control: no-store:这个才是响应不被缓存的意思
  2. 协商缓存

    协商缓存是指浏览器首先向服务器发送请求,服务器决定是否需要重新获取资源,如果资源未发生变化,服务器会返回 304 Not Modified 响应,告知浏览器可以继续使用缓存。Cache-Control:no-cache 或者 Cache-Control: max-age=0时进行协商缓存

    • Last-Modified :文件在服务器最后被修改的时间
      1. 第一次访问页面时,服务器的响应头会返回 Last-Modified 字段
      2. 客户端再次发起该请求时,请求头 If-Modified-Since 字段会携带上次请求返回的 Last-Modified
      3. 服务器根据 if-modified-since 的值,与该资源在服务器最后被修改时间做对比,若服务器上的时间大于 Last-Modified 的值,则重新返回资源,返回 200,表示资源已更新;反之则返回 304 ,代表资源未更新,可继续使用缓存
    • ETag:当前资源文件的一个唯一标识(由服务器生成),若文件内容发生变化该值就会改变
      1. 第一次访问页面时,服务器的响应头会返回 etag 字段
      2. 客户端再次发起该请求时,请求头 If-None-Match 字段会携带上次请求返回的 etag
      3. 服务器根据 If-None-Match 的值,与该资源在服务器的 Etag 值做对比,若值发生变化,状态码为 200,表示资源已更新;反之则返回 304,代表资源无更新,可继续使用缓存

    为什么要有 Etag ?

    Etag 的出现主要是为了解决一些 Last-Modified 难处理的问题:

    1. 一些文件也许会周期性的更改,但是内容并不改变(仅仅改变的修改时间),这时候并不希望客户端认为这个文件被修改了而重新去请求;
    2. 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说 1s 内修改了 N 次),If-Modified-Since 能检查到的粒度是秒级的,使用 Etag 就能够保证这种需求下客户端在 1 秒内能刷新 N 次 cache

    强缓存与协商缓存相结合的方案

    1. HTML 文档配置协商缓存
    2. JS、CSS、图片等资源配置强缓存

    此方案的好处:当项目版本更新时,可以获取最新的页面;若版本未变化,可继续复用之前的缓存资源;既很好利用了浏览器缓存,又解决了页面版本更新的问题

事件循环

在 JavaScript 中,宏任务(macrotask)和微任务(microtask)是用于管理异步操作的概念。

宏任务包括:

  • script(整体代码)
  • 从浏览器接收到的事件(如用户交互,定时器等)。setTimeoutsetIntervalsetImmediateI/OUI render
  • 从服务器接收到的响应。

微任务包括:

  • Promise 的处理程序(.then 或 .catch)。
  • MutationObserver 的回调函数。
  • Async/Await(实际就是promise)
  • process.nextTick(Node.js 环境)。

微任务在当前任务执行完毕后会优先执行,而宏任务则会在微任务执行完毕后才会执行。