前端面试题总结

timg

一、Ajax 和 JSONP 哪个可以跨域?原理是什么? JSONP 有什么问题?

答:JSONP 可以跨域。

1. JSONP 原理:

​ 网页通过动态添加一个 script 元素,向服务器请求 JSON 数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

​ 利用<script>标签没有跨域限制的“漏洞”来达到与第三方通讯的目的。当需要通讯时,本站脚本创建一个 script 元素,地址指向第三方的API网址,形如:<script src="http://www.example.net/api?param1=1&param2=2"></script>并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。 第三方产生的响应为 json数据的包装(故称之为 jsonp ,即 json padding),形如: callback({“name”:”hax”,”gender”:”Male”})这样浏览器会调用 callback 函数,并传递解析后 json 对象作为参数。本站脚本可在 callback 函数里处理所传入的数据。

2. JSONP 局限性:

​ 使用 jsonp 的局限性:只能使用 get 请求,不能发送 post 请求。如果想要发送 post 请求,只能其他的途径。

3. JSON 和 JSONP 的区别:

​ JSON 是一种数据交换格式,而 JSONP 是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。我们拿最近比较火的谍战片来打个比方,JSON 是地下党们用来书写和交换情报的“暗号”,而JSONP则是把用暗号书写的情报传递给自己同志时使用的接头方式。一个是描述信息的格式,一个是信息传递双方约定的方法。

1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;

2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。

3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。

4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用 jsonp 提供公开服务。

总而言之,jsonp不是ajax的一个特例,哪怕 jquery 等巨头把 jsonp 封装进了ajax,也不能改变着一点!

4. JSON 的优点:

1、基于纯文本,跨平台传递极其简单;

2、Javascript原生支持,后台语言几乎全部支持;

3、轻量级数据格式,占用字符数量极少,特别适合互联网传递;

4、可读性较强,虽然比不上XML那么一目了然,但在合理的依次缩进之后还是很容易识别的;

5、容易编写和解析,当然前提是你要知道数据结构;

5. JSON 的格式或者叫规则:

JSON能够以非常简单的方式来描述数据结构,XML能做的它都能做,因此在跨平台方面两者完全不分伯仲。

1、JSON只有两种数据类型描述符,大括号{}和方括号[],其余英文冒号:是映射符,英文逗号,是分隔符,英文双引号””是定义符。

2、大括号{}用来描述一组“不同类型的无序键值对集合”(每个键值对可以理解为OOP的属性描述),方括号[]用来描述一组“相同类型的有序数据集合”(可对应OOP的数组)。

3、上述两种集合中若有多个子项,则通过英文逗号,进行分隔。

4、键值对以英文冒号:进行分隔,并且建议键名都加上英文双引号””,以便于不同语言的解析。

5、JSON内部常用数据类型无非就是字符串、数字、布尔、日期、null 这么几个,字符串必须用双引号引起来,其余的都不用,日期类型比较特殊,这里就不展开讲述了,只是建议如果客户端没有按日期排序功能需求的话,那么把日期时间直接作为字符串传递就好,可以省去很多麻烦。

6. JSONP 的产生:

1、一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;

2、不过我们又发现,Web页面上调用 js 文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有” src “这个属性的标签都拥有跨域的能力,比如<script><img><iframe>);

3、于是可以判断,当前阶段如果想通过纯 web 端(ActiveX 控件、服务端代理、属于未来的 HTML5 之 Websocket 等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进 js 格式的文件里,供客户端调用和进一步处理;

4、恰巧我们已经知道有一种叫做 JSON 的纯字符数据格式可以简洁的描述复杂数据,更妙的是 JSON 还被 js 原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;

5、这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的 js 格式文件(一般以 JSON 为后缀),显而易见,服务器之所以要动态生成 JSON 文件,目的就在于把客户端需要的数据装入进去。

6、客户端在对 JSON 文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像 AJAX,但其实并不一样。

7、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作 JSONP,该协议的一个要点就是允许用户传递一个 callback 参数给服务端,然后服务端返回数据时会将这个 callback 参数作为函数名来包裹住 JSON 数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

二、谈谈你对语义化的理解?

答:

1.什么是语义化

​ Tim Berners-Lee(万维网发明者)最早提出了语义网(Semantic Web)的概念,而语义网的核心是通过给万维网上的文档(如HTML)添加能够被计算机所理解的元数据(Meta data),从而使整个互联网成为一个通用的信息交换媒介。

​ 简单讲就是根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地解析。

2.为什么要语义化

​ 随着互联网的发展,WEB也承载越来越多的信息(图片,声音,视频等),人们开始用机器来处理网络信息,就此诞生了搜索引擎。如次庞大及复杂的信息如何让搜索引擎处理和挖掘,所以让机器能够更好地读懂WEB上内容就变得越来越重要。

传统的Web由文档组成,W3C希望通过一组技术支撑“数据的Web”,即Web of Data,将Web看作一个存储和管理数据的大型分布式数据库。语义Web是构造这样的数据Web的重要一环,帮助人们创建数据并存储在Web上,创建相关的词汇表及数据的处理规则。 —— w3.org

​ 既然W3C有如此雄心为我们规划未来语义网,我们开发者作为W3C的坚定追随者还有什么理由不跟着大步迈进呢?

语义网的基础必然是语义化的结构网页。

此外,语义化可以带来许多好处:

  • 清晰的页面结构

    去掉或样式丢失的时候,也能让页面呈现清晰的结构,增强页面的可读性。

  • 支持更多的设备

    屏幕阅读器(如果访客有视障)会完全根据你的标记来“读”你的网页。 如果你使用的含语义的标记,屏幕阅读器会根据你的标签来判断网页的内容,而不是一个字母一个字母的拼写出来。

  • 有利于SEO

    和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息,搜索引擎的爬虫也依赖于标记来确定上下文和各个关键字的权重。

  • 便于团队开发和维护

    在团队中大家都遵循同一个标准,可以减少很多差异化的东西,方便开发和维护,提高开发效率,甚至实现模块化开发。

三、网页制作的图片格式有哪些?

答:

​ 图片格式是指计算机存储图片的格式,常见的存储的格式有BMP、JPEG、GIF、PNG、SVG、等等。我们常用到的网页图片格式一般分为2种:一种是位图图像;另一种是矢量图像。

1.位图图像

​ 位图图像(bitmap,简称:BMP), 亦称为点阵图像或绘制图像,是由称作为像素(图片元素)的单个点组成的。这些点可以进行不同的排列和染色以构成图样。当放大位图时,可以看见赖以构成整个图像的无数单个方块。扩大位图尺寸的效果是增大单个像素,从而使线条和形状显得参差不齐,从稍远的位置查看它的颜色与形状又显得是连续的。我们常用的位图处理软件有Photoshop、Gimp等图像工具。

位图图像属性

索引颜色/颜色表

位图常用的一种压缩方法。从位图图片中选择最有代表性的若干种颜色(通常不超过256种)编制成颜色表,然后将图片中原有颜色用颜色表的索引来表示。这样原图片可以被大幅度有损压缩[1]。适合于压缩网页图形等颜色数较少的图形,不适合压缩照片等色彩丰富的图形。

Alpha通道

在原有的图片编码方法基础上,增加像素的透明度信息。图形处理中,通常把RGB三种颜色信息称为红通道、绿通道和蓝通道,相应的把透明度称为Alpha通道。多数使用颜色表的位图格式都支持Alpha通道。

色彩深度

色彩深度又叫色彩位数,即位图中要用多少个二进制位来表示每个点的颜色,是分辨率的一个重要指标。常用有1位(单色),2位(4色,CGA),4位(16色,VGA),8位(256色),16位(增强色),24位(真彩色)和32位等。色深16位以上的位图还可以根据其中分别表示RGB三原色或CMYK四原色(有的还包括Alpha通道)的位数进一步分类,如16位位图图片还可分为R5G6B5,R5G5B5X1(有1位不携带信息),R5G5B5A1,R4G4B4A4等等。

  • 8位色,所谓8位色并不是图像只有8种颜色,而是28即256种颜色,8位图指的是用8个bits来表示颜色;
  • 16位色,216,从人眼的感觉来说,16位色基本可以满足视觉需要了;
  • 24位色,又称为“真彩色”。224,大概有1600万之多,这个数字几乎是人类视觉可分辨颜色的极限;
  • 32位色,并非232发色数,其实也是224种颜色,不过它增加了28阶颜色的灰度,也就是8位透明度,因此规定它为32位色。

在制作网站页面图片的时候,设计者一般选择24位图像。32位图像虽然质量更好,但同时也带来更大的图像体积(事实上,一般肉眼也很难分辨24位图和32位图的区别)。如果一个页面中图片体积过大的话,会使得浏览器加载页面速度明显变慢。此外将原始位图放大与缩小都会使图像效果失真,这是因为它们减小了图像中有效像素的数量或密度的缘故,所以在制作过程中应尽量避免图片被编辑的次数。

图像分辨率

图像分辨率是指一个图像文件中包含的细节和信息的大小,以及输入、输出、或显示设备能够产生的精细程度。编辑处理位图时要着重考虑分辨率这一要素,位图输出图像的质量决定于处理过程开始时设置的分辨率高低。通常情况下,图像的分辨率越高,所包含的像素就越多,图像就越清晰,印刷或显示的质量也就越好。同时,它也会增加文件占用的存储空间。也就是说编辑处理位图时,分辨率既会影响最后输出的质量也会影响文件的大小。与此相反矢量图中就不必过多考虑分辨率这一因素了。

常见位图图像格式

(1)BMP格式

BMP格式[2]是一种与硬件设备无关的图像文件格式,使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可用任何颜色深度(从黑白到 24 位颜色)存储单个光栅图像。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。从总体上看,它不支持文件压缩,文件体积较大所以不适用于 Web 页面图片。可以说Windows 位图文件格式的缺点已经超过了它的优点。为了保证WEB图片(尤其为照片)的质量,请使用 PNG 、JPEG等其它文件格式,BMP则更适用于 Windows 中的壁纸图片。

  • 优点:BMP 支持 1 位到 24 位颜色深度,并且BMP 格式与现有 Windows 程序广泛兼容;
  • 缺点:BMP 不支持压缩,这会造成生成的文件非常大。

(2)JPEG格式

JPEG格式是最常见的一种图像格式,它是由联合照片专家组(英语全称:Joint Photographic Experts Group),文件后辍名为“.JPEG”或“.jpg”[3],JPEG可以说是人们最熟悉的图档格式了,相信在数字相机普及的现在,几乎每台数字相机、照相手机都可以(甚至只能)输出 JPEG 格式的图档。JPEG是一种很典型的使用破坏性压缩(lossy compression)的图档格式,也就是说使用者每次进行 JPEG 的存档动作后,图档的一些内容细节都会遭到永久性的破坏,尤其是使用过高的压缩比例,将使最终解压缩后恢复的图像质量明显降低,如果追求高品质图像,不宜采用过高压缩比例[4]

JPEG格式目前非常的流行,应用也非常广泛,在网络和光盘读物上,都能找到它的身影。各类浏览器均支持JPEG这种图像格式,因为JPEG格式的文件尺寸较小,下载速度快。JPEG2000作为JPEG的升级版,其压缩率比JPEG高约30%左右,同时支持有损和无损压缩。JPEG2000格式有一个极其重要的特征在于它能实现渐进传输,即先传输图像的轮廓,然后逐步传输数据,不断提高图像质量,让图像由朦胧到清晰显示。此外,JPEG2000还支持所谓的”感兴趣区域” 特性,可以任意指定影像上感兴趣区域的压缩质量,还可以选择指定的部分先解压缩。JPEG2000和JPEG相比优势明显,且向下兼容,因此可取代传统的JPEG格式。

优点:

  • 由于JPEG格式压缩的主要是高频信息,对色彩的信息保留较好,可以把文件压缩到最小,适合应用于WEB图片,可减少图像的传输时间;
  • 可以支持24bit真彩色,普遍应用于需要连续色调的图像如色彩丰富的图片、照片等;
  • 可利用可变的压缩比以控制文件大小;
  • 支持交错(对于渐近式 JPEG 文件);
  • JPEG 广泛支持 WEB 标准,浏览器兼容支持较好。

缺点:

  • 有损耗压缩会使原始图片数据质量下降;
  • 当您每编辑和重新保存 JPEG 文件时,JPEG 会混合原始图片数据的质量下降。这种下降是累积性的、永久性的;
  • JPEG 不适用于所含颜色很少、具有大块颜色相近的区域或亮度差异十分明显的较简单的图片;不适合用来储存线条图、图标或文字等等有清晰边缘的图片,而这正是下文中PNG格式的强势所在。

(3)GIF格式

图形交换格式(简称:GIF,英语全称:Graphics Interchange Format),是CompuServe公司在 1987年开发的图像文件格式。GIF文件的数据,是一种基于LZW算法的连续色调的无损压缩格式。其压缩率一般在50%左右,它不属于任何应用程序所以几乎所有相关软件都支持它,公共领域有大量的软件在使用GIF图像文件。

GIF图像文件的数据是经过压缩的,而且是采用了可变长度等压缩算法。所以GIF的图像深度从lbit到8bit,也即GIF最多支持256种色彩的图像。GIF格式的另一个特点是其在一个GIF文件中可以存多幅彩色图像,如果把存于一个文件中的多幅图像数据逐幅读出并显示到屏幕上,就可构成一种最简单的动画。

GIF解码较快,因为采用隔行存放的GIF图像,在边解码边显示的时候可分成四遍扫描。第一遍扫描虽然只显示了整个图像的八分之一,第二遍的扫描后也只显示了1/4,但这已经把整幅图像的概貌显示出来了。在显示GIF图像时,隔行存放的图像会给您感觉到它的显示速度似乎要比其他图像快一些,这是隔行存放的优点;另外,GIF不支持Alpha透明通道。

GIF 在许多特性与表现上都与 JPEG 有着相对的特性。GIF 使用无损压缩格式(Lossless Compression),但却限制了色彩表现能力、能够有效地节省档案尺寸。GIF 只拥有 8 位(256色)的颜色深度信息,当你的图片中出现的色彩在 256 色以内时,使用 GIF 可以得到相当好的输出质量、同时兼顾了档案大小。因此 GIF 非常适合用来表现图标、 UI接口、线条插画、文字等部分的输出。另外 GIF 同时还支持透明背景(不支持Alpha透明通道)、以及动画图档格式,并且几乎不用担心支持性的问题:几乎 100% 的浏览器都支持它。

由于 GIF 与 JPEG有着如此不同的特性,因此我们可以很轻易的选择何时该用哪一种格式来输出我们需要的图档:当图片拥有丰富的色彩时,并且没有明显锐利反差的边缘线条时,选择 JPEG 可以得到最好的输出结果,像是照片就是最好的例子;当图片是拥有明确边缘的线条图、没有使用太多色彩、甚至可能需要透明背景时,GIF 是很完美的选择,档案小、画质又精美。

(4)PNG格式

便携式网络图形(简称PNG,英语全称:Portable Network Graphics),是网上接受的最新图像文件格式。PNG能够提供长度比GIF小30%的无损压缩图像文件。它同时提供 24位和32位真彩色图像支持以及其他诸多技术性支持。由于PNG优秀的特点,PNG格式图片可以称为“网页设计专用格式”。由于PNG非常新,所以并不是所有的程序都可以用它来存储图像文件,但Photoshop,Gimp可以处理PNG图像文件,也可以用PNG图像文件格式存储。PNG 最初的开发目的是为了作为 GIF 的替代方案的,作为做新开发的影像传输文件格式,PNG 同样使用了无损压缩格式,事实上 PNG 的开发就是因为 GIF 所使用的无损压缩格式专利问题而诞生的。PNG 分为 PNG-8 以及 PNG-24 两种格式,PNG-8 的特性很接近 GIF ,支持 256 色以及透明背景的特性。而 PNG-24 则支持了多达 160 万个色彩。

虽然 PNG 不支持动画,但是 PNG-24 支持了Alpha 透明效果,这可以说是 PNG-24 最令人眼睛一亮的地方了。也就是说使用 PNG 输出图档时,可以有效的支持不同的透明度效果。

优点:

  • 支持高级别无损耗压缩;
  • 支持 alpha 通道透明度;
  • 支持伽玛校正、支持交错。

缺点:

  • 较旧的浏览器IE6- 和程序可能不支持 PNG 文件;
  • 与 JPEG 的有损耗压缩相比,PNG 提供的压缩量较少;
  • 与 GIF 格式相比,对多图像文件或动画文件不提供任何支持。

(5)WebP格式

WebP格式,谷歌2010年开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器带宽资源和数据空间。Facebook Ebay等知名网站已经开始测试并使用WebP格式。 但WebP是一种有损压缩,相较编码JPEG文件,编码同样质量的WebP文件需要占用更多的计算资源,意味着用户不需要牺牲图片质量就能够获得小体积的图片。然而,目前只有 Chrome、Opera 浏览器和 Android 4.0 默认浏览器本地原生支持 WebP 图片格式,所以要想成为标准 Google 还有很长的路要走。

Google 开发团队说相比于 PNG 图片,即便是最高的压缩,WebP 也比它小 28%,下面的示例3:《WebP格式与PNG格式的对比》中,WebP 图片比 PNG 图片小 45%,就是说从网页中加载图片时,WebP 比 PNG 快 45%。对于 Google 开发团队来说,想把它打造成新的 Web 标准的路很艰难,但是它的优势也很明显:更小的图片体积 = 更快的加载速度。

从上对比的示例中不难看出:

  • PNG 转 WebP 的压缩率要高于 PNG 原图压缩率,同样支持有损与无损压缩;
  • 转换后的 WebP 体积大幅减少,图片质量也得到保障;支持 Alpha 透明和 24-bit 颜色数,不存在 PNG8 色彩不够丰富和在浏览器中可能会出现毛边的问题;
  • WebP 的优势体现在它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量;同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性,在 JPEG 和 PNG 上的转化效果都非常优秀、稳定和统一。

如果你想尝试 WebP 图片格式,可以在 Windows 下安装一个WebP图片解码器,或者使用 GIMP 等图片编辑软件,也可以安装 Photoshop插件。同样也可以在 Google 里搜索 WebP 格式图片,只需在关键词后边加个 filetype:webp 就可以。

除上述几种常用的位图图片格式外,尚有TGA、EXIF、FPX等多种图像格式,由于Web设计中很少用到,所以在此不再细述。

2.矢量图

​ 矢量图,也称为面向对象的图像或绘图图像,繁体版本上称之为向量图,是计算机图形学中用点、直线或者多边形等基于数学方程的几何图元表示图像。矢量图形最大的优点是无论放大、缩小或旋转等不会失真;最大的缺点是难以表现色彩层次丰富的逼真图像效果。矢量文件中的图形元素称为对象。每个对象都是一个自成一体的实体,它具有颜色、形状、轮廓、大小和屏幕位置等属性。这意味着它们可以按最高分辨率显示到输出设备上。

矢量图是根据几何特性来绘制图形,矢量可以是一个点或一条线,矢量图只能靠软件生成,文件占用内在空间较小,因为这种类型的图像文件包含独立的分离图像,可以自由无限制的重新组合。它的特点是放大后图像不会失真,和分辨率无关,适用于图形设计、文字设计和一些标志设计、版式设计等。

矢量图以几何图形居多,图形可以无限放大,不变色、不模糊。常用于图案、标志、VI、文字等设计。常用软件有:CorelDraw、Illustrator、Freehand、XARA、CAD等。

常用矢量图格式

(1)BW格式

它是包含各种像素信息的一种黑白图形文件格式。

(2)AI格式

AI格式是Illustrator中的一种图形文件格式,也即Illustrator软件生成的矢量文件格式, 用Illustrator、CorelDraw、Photoshop 均能打开,编辑修改等等。与PSD格式文件相同,AI也是一种分层文件,每个对象都是独立的,他们具有各自的属性,如大小、形状、轮廓、颜色、位置等。以这种格式保存的文件便于修改,这种格式文件可以在任何尺寸大小下按最高分辨率输出。

(3)CDR格式

它是CorelDraw中的一种图形文件格式,是所有CorelDraw应用程序中均能够使用的一种图形图像文件格式,也可以将CDR格式的文件导出为AI格式使用。

(4)ICO格式

全称为 Icon file,它是Windows的图标文件格式,在站点图标制作中相信对它并不陌生,我们经常把它命名为favicon.ico。

(5)SVG格式

可缩放矢量图形(简称SVG,英语全称:Scalable Vector Graphics)。它是基于XML(标准通用标记语言的子集),由万维网联盟进行开发(这也是将它作为重点介绍的原因之一)。因为SVG是被设计用于互联网,所以通过Javascript和DOM访问它就是最重要的应用模式。通过Javascript和DOM可以动态地修改HTML,同样也可以在浏览器中动态地创建、修改和删除图片。一种开放标准的矢量图形语言,可任意放大图形显示,边缘异常清晰,文字在SVG图像中保留可编辑和可搜寻的状态,没有字体的限制,生成的文件很小,下载很快,十分适合用于设计高分辨率的Web图形页面。

SVG 优势

与位图图像JPEG、GIF等格式相比,使用 SVG 的优势还在于:

  • SVG 图像可通过文本编辑器来创建和修改,可被搜索、索引、脚本化或压缩;
  • SVG 是可伸缩的,可在图像质量不下降的情况下被放大,可在任何的分辨率下被高质量地打印。

3.位图与矢量图的区别

  • 位图受分辨率的影响,缩放和旋转容易失真,同时文件容量较大,当图片放大时,位图清晰度会变低,而矢量图不受分辨率影响,清晰度不变;
  • 位图组成单位是“像素”,而矢量图组成单位是“数学向量”;
  • 位图适用于色彩丰富的图片,只要有足够多的不同色彩的像素,就可以制作出色彩丰富的图象,逼真地表现自然界的景象;而矢量图文件容量较小,在进行放大、缩小或旋转等操作时图象不会失真,却不适用于色彩丰富的图片;
  • 位图常用于网页中的照片等,容量较大;矢量图常用于印刷行业、网页logo或矢量插图中。

WEB网页设计中对于图片格式其它一些技巧总结

  • 尽量通过较小的视觉牺牲来换取较大的性能提升;
  • 对于写实的摄影图像或是颜色层次非常丰富的图像采用JPEG的图片格式保存一般能达到最佳的压缩效果;而处理一些logo、banner、需要透明效果、色调单一或简单线条构图的时候,适合使用PNG格式;GIF格式通常只适合表达动画效果;
  • 不要保存为100%品质的JPEG格式图片。因为100%并不一定是最高的品质,而是一个优化算法的极限值,所以会增加不必要的文件大小。建议存储95%品质的图片就可以最大限度的降低失真度;
  • 谨慎使用50%品质以下的压缩率。使用50%以下品质存储时会采用额外的压缩算法而导致图片失真更严重,尤其是对于有高对比度的图片;

四、写出至少 3 种做水平和垂直居中的方法?

答:

对一个元素水平垂直居中,在我们的工作中是会经常遇到的,也是CSS布局中很重要的一部分,本文就来讲讲CSS水平垂直居中的一些方法。另外,文中的css都是用less书写的,如果看不懂less,可以把我给的demo链接打开,然后在控制台中查看最终的css,或者是点击codepen上的“View Compiled”按钮,可以查看编译后的css

先看一张图,这是去年cssConf大会时阿里的 @寒冬winter 老师放出来的:

alt

如图所示,CSS布局是可以分为几大块的:

  • 盒子内部的布局
    • 文本的布局
    • 盒模型本身的布局
  • 盒子之间的布局visual formatting
    • 脱离正常流normal flow的盒子的布局
      • absolute布局上下文下的布局
      • float布局上下文下的布局
    • 正常流normal flow下的盒子的布局
      • BFC布局上下文下的布局
      • IFC布局上下文下的布局
      • FFC布局上下文下的布局
      • table布局上下文下的布局
      • css grid布局上下文下的布局

所有的CSS布局其实都是围绕着这些布局模块来的,水平垂直居中也一样。

1. 文本的水平垂直居中

line-height + text-align:center

DEMO链接

代码:

1
2
3
<div class='wrap'>
水平垂直居中水平垂直居中
</div>
1
2
3
4
5
6
7
8
9
10
11
12
html,body{
margin: 0;
}
.wrap{
line-height: 400px;
text-align:center;
height: 400px;
font-size: 36px;
background-color: #ccc;
}

这种方法只适合单行文字的水平垂直居中

2. 利用盒模型的水平垂直居中

我们一般讲的盒模型都是说的块级盒的盒模型,也只有块级盒的盒模型用得多一点,块级盒block-level box又是分别由content-box、padding-box、border-box、margin-box组成的,如下图:

Alt text

也就说我任一个子盒子的水平和垂直方向的边与最外面盒子的间距都是可以控制的,因此也就有如下居中方法:

padding填充

DEMO链接

代码:

1
2
3
<div class="wrap">
<div class="content"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@wrapWidth : 400px;
.wrap{
margin-left: auto;
margin-right: auto;
margin-top: 20px;
width: @wrapWidth;
height: @wrapWidth;
background-color: #ccc;
}
.content{
@contentWidth : 100px;
width: @contentWidth;
height: @contentWidth;
padding: (@wrapWidth - @contentWidth) / 2;
background-color: #333;
background-clip:content-box;
}

也可以用css3的calc()动态计算:

DEMO链接

1
2
3
<div class="wrap">
<div class="content"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.wrap{
margin-top: 20px;
margin-left: auto;
margin-right: auto;
width: 400px;
height: 400px;
background-color: #ccc;
.content{
padding: -webkit-calc(~"(100% - 100px) / 2");
padding: calc(~"(100% - 100px) / 2");
width: 100px;
height: 100px;
background-color: #333;
background-clip: content-box;
}
}

注意这里我在calc中使用了一个~””的写法,这是less中的一个语法,告诉less这里不被less所编译,要是被less编译了的话,css的calc函数的参数就不是100% - 100px,而是0%了。

margin填充

DEMO链接

代码:

1
2
3
<div class="wrap">
<div class="ele"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.wrap{
@wrapHeight : 400px;
@contenHeight : 100px;
overflow: hidden;
width: 100%;
height: @wrapHeight;
background-color: #ccc;
.ele{
margin-left: auto;
margin-right: auto;
margin-top: (@wrapHeight - @contenHeight) / 2;
width: 100px;
height: @contenHeight;
background-color: #333;
color: #fff;
}
}

使用margin填充我们需要知道元素的宽度,这点不太灵活,不过CSS3搞出了一个加fit-content的属性值,可以动态计算元素的宽度,DEMO链接

使用盒模型进行布局不会产生reflow,兼容也好,使用盒模型布局是一种布局思想,其实仅仅靠它就能实现很多visual formatting才能实现的布局,这是另一个话题,这里不展开。

3. absolute布局上下文下的水平垂直居中

50% + -50%

原理很简单,就是利用left:50%将盒子的左边先置于父容器的中点,然后再将盒子往左偏移盒子自身宽度的50%,这里有三种具体实现:

DEMO链接

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="wrap">
<div class="ele margin">水平垂直居中水平垂直<br>居中水平垂直居中水平<br>垂直居中水平垂直居<br>中水平垂直居中</div>
</div>
<div class="wrap">
<div class="ele translate">水平垂直居中水平垂直<br>居中水平垂直居中水平<br>垂直居中水平垂直居<br>中水平垂直居中</div>
</div>
<div class="wrap">
<div class="ele relative">
<div class="ele-inner">水平垂直居中水平垂直<br>居中水平垂直居中水平<br>垂直居中水平垂直居<br>中水平垂直居中</div>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
.wrap{
position: relative;
width: 100%;
height: 200px;
border:1px solid;
background-color: #ccc;
.ele{
position: absolute;
left: 50%;
top: 50%;
background-color: #333;
&.margin{
width: 160px;
height: 100px;
margin-left: -80px;
margin-top: -50px;
}
&.translate{
-webkit-transform:translate3d(-50%, -50%, 0);
transform:translate3d(-50%, -50%, 0);
}
.ele-inner{
position: relative;
left: -50%;
top: -50%;
width: 100%;
height: 100%;
background-color: #333;
}
&.relative{
width: 150px;
height: 100px;
background-color: transparent;
}
}
}

上面三个方法中,margin方法和relative方法都需要知道元素的宽高才行(relative方法只知道高也行),适用于固定式布局,而transform方法则可以不知道元素宽高

text-align:center + absolute

text-aign:center本来是不能直接作用于absolute元素的,但是没有给其left等值的行级absolute元素是会受文本的影响的,可以参考张老师的这篇文章

DEMO链接

代码:

1
2
3
<div class="wrap">
<div class="ele"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.wrap{
text-align: center;
width: 100%;
height: 400px;
background-color: #ccc;
font-size: 0;
}
.ele{
position: absolute;
margin-left: -(100px / 2);
margin-top: (400px - 100px) / 2;
width: 100px;
height: 100px;
display: inline-block;
background-color: #333;
}

简单解释下,首先,text-align:center作用的是文本而不是absolute的元素,但是,当absolute元素为inline-block的时候,它会受到文本的影响,然后你可能会问这里没文本啊,我只能告诉你说这下面是有的,是个匿名的文本节点。具体的这里不展开,可以参考标准,然后理解这句话:

If the inline box contains no glyphs at all, it is considered to contain a strut (an invisible glyph of zero width) with the A and D of the element’s first available font

然后这个匿名文本由于受到text-align:center影响居中了,这个时候absolute盒子的左边跟父容器的中点对齐了,所以就还需要往回拉50%,这里用的是margin-left,你也可以用其它方式拉。然后就是垂直方向的对齐,垂直方向是不能被操作文本的属性影响的,所以我这里用的是margin-top来让它偏移下去。

absolute + margin : auto

DEMO链接

代码:

1
2
3
<div class="wrap">
<div class="ele"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
html,body{
width: 100%;
height: 100%;
margin: 0;
}
.wrap{
position: relative;
width: 100%;
height: 100%;
background-color: #ccc;
.ele{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 100px;
height: 100px;
background-color: #333;
}
}

关于这种布局的原理,在标准中能找到如下解释:

w3c.org中有这样一句话:

The constraint that determines the used values for these elements is:
‘left’ + ‘margin-left’ + ‘border-left-width’ + ‘padding-left’ + ‘width’ + ‘padding-right’ + ‘border-right-width’ + ‘margin-right’ + ‘right’ = width of containing block

这句话说的是absolute性质的盒子,它的包含块的宽度等于它的盒模型的宽度 + left + right值,包含块的高度同理,盒模型包括margin-box、border-box、padding-box、content-box,而在这个居中方法中,.ele的left + right值是0,width是定值,width所在盒子包括了除了margin-box外的那三个box,margin都是auto值,按照上面那个公式,margin-left + margin-right的值应该等于包含块的宽度 - left的值 - right的值 - width的值,也就是说margin-left + margin-right的值等于除了width所占宽度外的剩下宽度,拥有剩下宽度后,就是平分其宽度,以让左右两边相等,达到居中,标准中给出了答案:

If none of the three is ‘auto’: If both ‘margin-left’ and ‘margin-right’ are ‘auto’, solve the equation under the extra constraint that the two margins get equal values, unless this would make them negative, in which case when direction of the containing block is ‘ltr’ (‘rtl’), set ‘margin-left’ (‘margin-right’) to zero and solve for ‘margin-right’ (‘margin-left’)

这里的”three”指的是left, width, right。如果left、right和width都不为auto,同时margin-left和margin-right都是auto,除非特别情况,它们俩就是相等的,而这个例子中不在特殊情况之列,因此两者平分,此时达到了水平居中。而对于垂直方向的margin的auto值的计算,标准中也有如下两句话,跟水平方向的同理(这里的“three”指的是“top, height, bottom”):

the used values of the vertical dimensions must satisfy this constraint:
‘top’ + ‘margin-top’ + ‘border-top-width’ + ‘padding-top’ + ‘height’ + ‘padding-bottom’ + ‘border-bottom-width’ + ‘margin-bottom’ + ‘bottom’ = height of containing block

if none of the three are ‘auto’: If both ‘margin-top’ and ‘margin-bottom’ are ‘auto’, solve the equation under the extra constraint that the two margins get equal values.

垂直方向也就因此也居中了。

这种方法能简单的做到居中,但是必须有width和height值

适用于图片居中的网易nec的一个方法

DEMO链接

代码:

1
2
3
4
5
6
<div class="wrap">
<p>
<img src="http://nec.netease.com/img/s/1.jpg" alt="" />
<img src="http://nec.netease.com/img/s/1.jpg" alt="" />
</p>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
html,body{
width: 100%;
height: 100%;
margin: 0;
}
.wrap{
position:relative;
width: 100%;
height: 100%;
p{
position:absolute;
left:50%;
top:50%;
}
img{
&:nth-child(1){
position:static;
visibility:hidden;
}
&:nth-child(2){
position:absolute;
right:50%;
bottom:50%;
}
}
}

这种方法主要是利用了一个图片进行占位,以让父容器获得高宽,从而让进行-50%偏移的图片能有一个参照容器作百分比计算。优点是可以不知道图片的大小,随便放张尺寸不超过父容器的图片上去都能做到居中。另外,兼容性好,如果是不使用nth-child选择器的花,IE6都是能顺利兼容的

4. float布局上下文下的水平垂直居中

float + -50%

DEMO链接

代码:

1
2
3
4
5
<div class="wrap">
<div class="ele">
<div class="ele-inner">居中居中居中居中居中居中<br>居中居中居中居中居中居中居中居中居<br>中居中居中居中居中居中居中居中居中居<br>中居中居中居中居中居中居中</div>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.wrap{
float: left;
width: 100%;
height: 400px;
background-color: #ccc;
.ele{
float: left;
position: relative;
left: 50%;
top: 50%;
}
.ele-inner{
position: relative;
left: -50%;
-webkit-transform : translate3d(0, -50%, 0);
transform : translate3d(0, -50%, 0);
background-color: #333;
color: #fff;
}
}

这种方法的原理,首先是利用float属性将需要居中的元素的父元素.ele的宽度收缩,然后left:50%将.ele的左边和水平中线对齐,这个时候还没居中,还需要将其往回拉自身宽度的50%,于是.ele-inner便是真正需要水平居中的元素,我给它一个position:relative,将其往回拉自身宽度50%就行了。对于垂直方向,依然是先将.ele top:50%到垂直方向中点,但是这时给.ele-inner top:50%是不起作用的,因为如果没给父元素明确高度的话,这个50%是计算不出来的,因此,就有了transform : translate3d(0, -50%, 0)。

这种方法的好处是元素可以不定宽,任何时候都可以做到居中

我当时在w3cplus的站上发现这个方法后,当时觉得这个方法很好,兼容性好,又还可以不定宽,但当我用了一段时间后,发现了一个问题:

就是当居中元素的父元素left:50%时,如果元素宽度足够大,会超出外面的容器,而如果外面的容器又正好是overflow:auto的话,那就会在外面产生滚动条,问题DEMO链接在这里,后来我找到了一个办法:DEMO链接 ,基本思想就是利用元素超出父元素的左边不会产生滚动条的特性,有点奇淫技巧,但是能解决问题,有兴趣的可以看看

margin-bottom : -50%

DEMO链接

代码:

1
2
3
4
<div class="wrap">
<div class="placeholder"></div>
<div class='content'></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.wrap{
float: left;
width: 100%;
height: 400px;
background-color: #ccc;
@contentHeight : 100px;
.placeholder{
float: left;
width: 100%;
height: 50%;
/*居中元素.content高度一半*/
margin-bottom: -(@contentHeight / 2);
}
.content{
position: relative;
left: 50%;
transform:translate3d(-50%, 0, 0);
clear: both;
/*演示用,实际不需要定宽*/
max-width: 100px;
height: @contentHeight;
background-color: #333;
}
}

这种方法是先让占位元素.placeholder占据50%高度,然后给一个居中元素高度一半的负的margin-bottom,然后下面的元素只要跟着摆放就能垂直居中了。水平方向就是利用translate做偏移,这个没什么好说的,你也可以换成其他办法。

这种方法就是各种固定死,首先最外层的父容器需要一个固定高度,以让.placeholder的height:50%有效,然后,margin-bottom也需要固定死,而且得需要知道居中元素高度。单纯就水平方向来说,这个方法比较适合需要兼容低版本IE的固定式布局的项目,因为兼容性好。

5. BFC布局上下文下的水平垂直居中

BFC的全称是块级排版上下文,这里有篇文章对齐进行了简单的介绍,BFC布局上下文下的布局其实就是利用盒模型本身进行的布局,前面在利用盒模型布局的那一节中已经讲过了,这里就不重复了

6. IFC布局上下文下的水平垂直居中

IFC又是个什么概念呢,你可以看看官方文档,也可以简单的理解为 display为inline性质的行级元素的布局。

text-align:center + vertical-align:middle

DEMO链接

代码:

1
2
3
4
<div class="wrap">
<div class='placeholder'><!--占位元素,用来作为居中元素的参照物--></div>
<div class="ele"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.wrap{
width: 100%;
height: 400px;
/* min-height: 400px; */
text-align:center;
font-size: 0;
background-color: #ccc;
.placeholder,
.ele{
vertical-align: middle;
display: inline-block;
}
.placeholder{
overflow: hidden;
width: 0;
min-height: inherit;
height: inherit;
}
.ele{
width: 100px;
height: 100px;
background-color: #333;
}
}

行级元素会受到text-align和vertical-align的影响,关于vertical-align,不太好理解,我多贴几篇文章:@灵感idea 的张鑫旭的MDN上的css-trick上的,以及官方文档,这里首先是用text-center让inline-block水平居中,然后给一个vertical-align:middle,但是仅仅给vertical-align:middle是不够的,因为此时它还没有vertical-align对齐的参照物,所以就给了一个占位的inline-block,它的高度是100%。

这个方法对于居中元素不需要定宽高,而且元素根据vertical-align值的不同不仅仅可以实现居中,还可以将其放在上面下面等。缺点是父元素需定高

text-align:center + line-height

DEMO链接

代码:

1
2
3
<div class="wrap">
<div class="ele">居中居中居中居中居中居中<br>居中居中居中居中居中居中居中<br>居中居中居中居中居中居中居中居中<br>居中居中居中居中居中居中居中居中</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.wrap{
text-align: center;
line-height: 400px;
width: 100%;
height: 400px;
background-color: #ccc;
font-size: 0;
.ele{
line-height: normal;
vertical-align: middle;
display: inline-block;
background-color: #333;
font-size: 18px;
color: #fff;
}
}

这个方法,首先是水平方向,text-align:center就行了,至于垂直方向,起作用的就是父容器的一个line-height和居中元素的vertical-align:middle,为什么这两个属性可以让一个inline-block垂直居中呢,这里重点是父容器在其下面产生了一个隐匿的文本节点,这个我在上面 text-align:center + absolute 那个方法的讲解中说到过了,然后这个这个隐匿文本节点会因line-height属性的作用而拥有了一个父容器一样高的行高,此时元素有了一个vertical-align对齐的参照物,再给其vertical-align:middle值就能垂直对齐了。

使用这个方法,居中元素无需定宽高,但缺点是得给父容器一个固定的行高才行。

text-align:center + font-size

DEMO链接

代码:

1
2
3
<div class="wrap">
<div class="ele"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.wrap{
text-align: center;
font-size: 400px * 0.873;/*约为高度的0.873*/
margin-left: auto;
margin-right: auto;
width: 400px;
height: 400px;
background-color: #ccc;
.ele{
vertical-align: middle;
width: 100px;
height: 100px;
display: inline-block;
background-color: #333;
}
}

这个方法来自淘宝,基本原理还是让隐匿文本节点所占据的行高等于父容器的高度,然后给居中元素一个vertical-align:middle对齐的一个参照。只是这里把定义line-height值换成了定义font-size值,让font-siz足够大从而让其行高等于父容器高度。为了证明这个font-size的作用,我把居中元素换成文本

DEMO链接

代码:

1
2
3
<div class="wrap">
a
</div>
1
2
3
4
5
6
7
8
9
10
.wrap{
text-align: center;
font-size: 400px * 0.873;/*约为高度的0.873*/
margin-left: auto;
margin-right: auto;
width: 400px;
height: 400px;
background-color: #ccc;
}

效果:

alt

可以看到字母a垂直居中了,这个字母a就对应那个隐匿文本节点

7. FFC布局上下文下的水平垂直居中

父元素、子元素都定义flex:

DEMO链接

代码:

1
2
3
4
5
6
7
8
9
<div class="wrap">
<div class="ele">
居中居中居中居中居中居中居中<br>
居中居中居中居中居中居中居中<br>
居中居中居中居中居中居中居中<br>
居中居中居中居中居中居中居中<br>
居中居中居中居中居中居中居中
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
html,body{
width: 100%;
height: 100%;
}
.wrap{
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: #ccc;
.ele{
background-color: #333;
}
}

只有父元素定义flex,子元素定义margin:auto:

DEMO链接

代码:

1
2
3
4
5
6
7
8
9
<div class="wrap">
<div class="ele">
居中居中居中居中居中居中居中<br>
居中居中居中居中居中居中居中<br>
居中居中居中居中居中居中居中<br>
居中居中居中居中居中居中居中<br>
居中居中居中居中居中居中居中
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
html,body{
width: 100%;
height: 100%;
}
.wrap{
display: flex;
width: 100%;
height: 100%;
background-color: #ccc;
.ele{
margin:auto;
background-color: #333;
}
}

flex box的标准中有这句话(参考链接:http://www.w3.org/TR/css-flexbox-1/#item-margins)::)

The margins of adjacent flex items do not collapse. Auto margins absorb extra space in the corresponding dimension and can be used for alignment and to push adjacent flex items apart; see Aligning with auto margins.

意思就是说flex item的margin不会折叠,在flex-item有明确大小并且margin:auto时外边距吸收了伸缩包含块下的额外的空间,并且能被用于居中以及会让其相邻的flex item尽可能的往这个flex item所在的那一个方向靠。

flexbox是个很强大的布局模块,也就三个属性就搞定居中了,而且不论父容器还是居中元素都可以不定宽高。参考链接:图解CSS3 Flexbox属性

8. table布局上下文下的水平垂直居中

DEMO链接

代码:

1
2
3
4
5
<div class='wrap'>
<div class='ele'>
<div class="ele-inner">居中居中居中居中居中居中居中居中<br>居中居中居中居中居中居中居中居中<br>居中居中居中居中居中居中居中居中居中居中</div>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.wrap{
width: 100%;
height: 300px;
display: table;
background-color: #ccc;
}
.ele{
text-align:center;
vertical-align: middle;
display:table-cell;
}
.ele-inner{
display: inline-block;
background-color: #333;
}

原理就是把div模拟成表格(换成真正的表格标签也是可以的),然后给那几个属性就成了,这个没什么好讲的,不懂的去翻翻手册就明白了,然后@于江水写的一篇table那些事还不错

9. CSS grid布局上下文下的水平垂直居中

CSS3 grid layout是IE搞出来的一个布局模块,目前貌似还只有IE0和IE11支持,我没有研究过其居中的方法,有兴趣的可以看看大漠老师的介绍文章

10. 其它未知归属的水平垂直居中方法

使用button标签

DEMO链接

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<button>
<div>
居中居中居中居中居中居中<br>
居中居中居中居中居中居中<br>
居中居中居中居中居中居中<br>
居中居中居中居中居中居中<br>
</div>
</button>
button{
width: 100%;
height: 400px;
background-color: #cccccc;
border-width:0;
&:focus{
outline:none;
}
div{
display: inline-block;
font-size: 18px;
background-color: #333;
color: #fff;
}
}

这种方法属于奇淫技巧,利用button标签天生外挂的这一技能对其里面的元素进行居中。

(本题完)、

五、CSS 常见的 hack 方法有哪些?

答:

1. 什么是CSS hack

由于不同厂商的流览器或某浏览器的不同版本(如IE6-IE11,Firefox/Safari/Opera/Chrome等),对CSS的支持、解析不一样,导致在不同浏览器的环境中呈现出不一致的页面展现效果。这时,我们为了获得统一的页面效果,就需要针对不同的浏览器或不同版本写特定的CSS样式,我们把这个针对不同的浏览器/不同版本写相应的CSS code的过程,叫做CSS hack!

2. CSS hack的原理

由于不同的浏览器和浏览器各版本对CSS的支持及解析结果不一样,以及CSS优先级对浏览器展现效果的影响,我们可以据此针对不同的浏览器情景来应用不同的CSS。

3. CSS hack分类

CSS Hack大致有3种表现形式,CSS属性前缀法、选择器前缀法以及IE条件注释法(即HTML头部引用if IE)Hack,实际项目中CSS Hack大部分是针对IE浏览器不同版本之间的表现差异而引入的。

  • 属性前缀法(即类内部Hack):例如 IE6能识别下划线”“和星号” “,IE7能识别星号” “,但不能识别下划线”“,IE6~IE10都认识”\9”,但firefox前述三个都不能认识。
  • 选择器前缀法(即选择器Hack):例如 IE6能识别html .class{},IE7能识别+html .class{}或者*:first-child+html .class{}。
  • IE条件注释法(即HTML条件注释Hack):针对所有IE(注:IE10+已经不再支持条件注释): ,针对IE6及以下版本: 。这类Hack不仅对CSS生效,对写在判断语句里面的所有代码都会生效。

CSS hack书写顺序,一般是将适用范围广、被识别能力强的CSS定义在前面。

(1)CSS hack方式一:条件注释法

 

这种方式是IE浏览器专有的Hack方式,微软官方推荐使用的hack方式。举例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
只在IE下生效
<!--[if IE]>
这段文字只在IE浏览器显示
<![endif]-->
只在IE6下生效
<!--[if IE 6]>
这段文字只在IE6浏览器显示
<![endif]-->
只在IE6以上版本生效
<!--[if gte IE 6]>
这段文字只在IE6以上(包括)版本IE浏览器显示
<![endif]-->
只在IE8上不生效
<!--[if ! IE 8]>
这段文字在非IE8浏览器显示
<![endif]-->
非IE浏览器生效
<!--[if !IE]>
这段文字只在非IE浏览器显示
<![endif]-->

(2)CSS hack方式二:类内属性前缀法

属性前缀法是在CSS样式属性名前加上一些只有特定浏览器才能识别的hack前缀,以达到预期的页面展现效果。

IE浏览器各版本 CSS hack 对照表

hack 写法 实例 IE6(S) IE6(Q) IE7(S) IE7(Q) IE8(S) IE8(Q) IE9(S) IE9(Q) IE10(S) IE10(Q)
* *color 青色 Y Y Y Y N Y N Y N Y
+ +color 绿色 Y Y Y Y N Y N Y N Y
- -color 黄色 Y Y N N N N N N N N
_ _color 蓝色 Y Y N Y N Y N Y N N
# #color 紫色 Y Y Y Y N Y N Y N Y
\0 color:red\0 红色 N N N N Y N Y N Y N
\9\0 color:red\9\0 粉色 N N N N N N Y N Y N
!important color:blue !important;color:green; 棕色 N N Y N Y N Y N Y Y

说明:在标准模式中

  • “-″减号是IE6专有的hack
  • “\9″ IE6/IE7/IE8/IE9/IE10都生效
  • “\0″ IE8/IE9/IE10都生效,是IE8/9/10的hack
  • “\9\0″ 只对IE9/IE10生效,是IE9/10的hack

demo如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<script type="text/javascript">
//alert(document.compatMode);
</script>
<style type="text/css">
body:nth-of-type(1) .iehack{
color: #F00;/* 对Windows IE9/Firefox 7+/Opera 10+/所有Chrome/Safari的CSS hack ,选择器也适用几乎全部Mobile/Linux/Mac browser*/
}
.demo1,.demo2,.demo3,.demo4{
width:100px;
height:100px;
}
.hack{
/*demo1 */
/*demo1 注意顺序,否则IE6/7下可能无法正确显示,导致结果显示为白色背景*/
background-color:red; /* All browsers */
background-color:blue !important;/* All browsers but IE6 */
*background-color:black; /* IE6, IE7 */
+background-color:yellow;/* IE6, IE7*/
background-color:gray\9; /* IE6, IE7, IE8, IE9, IE10 */
background-color:purple\0; /* IE8, IE9, IE10 */
background-color:orange\9\0;/*IE9, IE10*/
_background-color:green; /* Only works in IE6 */
*+background-color:pink; /* WARNING: Only works in IE7 ? Is it right? */
}
/*可以通过javascript检测IE10,然后给IE10的<html>标签加上class=”ie10″ 这个类 */
.ie10 #hack{
color:red; /* Only works in IE10 */
}
/*demo2*/
.iehack{
/*该demo实例是用于区分标准模式下ie6~ie9和Firefox/Chrome的hack,注意顺序
IE6显示为:绿色,
IE7显示为:黑色,
IE8显示为:红色,
IE9显示为:蓝色,
Firefox/Chrome显示为:橘色,
(本例IE10效果同IE9,Opera最新版效果同IE8)
*/
background-color:orange; /* all - for Firefox/Chrome */
background-color:red\0; /* ie 8/9/10/Opera - for ie8/ie10/Opera */
background-color:blue\9\0; /* ie 9/10 - for ie9/10 */
*background-color:black; /* ie 6/7 - for ie7 */
_background-color:green; /* ie 6 - for ie6 */
}
/*demo3
实例是用于区分标准模式下ie6~ie9和Firefox/Chrome的hack,注意顺序
IE6显示为:红色,
IE7显示为:蓝色,
IE8显示为:绿色,
IE9显示为:粉色,
Firefox/Chrome显示为:橘色,
(本例IE10效果同IE9,Opera最新版效果也同IE9为粉色)
*/
.element {
background-color:orange; /* all IE/FF/CH/OP*/
}
.element {
*background-color: blue; /* IE6+7, doesn't work in IE8/9 as IE7 */
}
.element {
_background-color: red; /* IE6 */
}
.element {
background-color: green\0; /* IE8+9+10 */
}
:root .element { background-color:pink\0; } /* IE9+10 */
/*demo4*/
/*
该实例是用于区分标准模式下ie6~ie10和Opera/Firefox/Chrome的hack,本例特别要注意顺序
IE6显示为:橘色,
IE7显示为:粉色,
IE8显示为:黄色,
IE9显示为:紫色,
IE10显示为:绿色,
Firefox显示为:蓝色,
Opera显示为:黑色,
Safari/Chrome显示为:灰色,
*/
.hacktest{
background-color:blue; /* 都识别,此处针对firefox */
background-color:red\9; /*all ie*/
background-color:yellow\0; /*for IE8/IE9/10 最新版opera也认识*/
+background-color:pink; /*for ie6/7*/
_background-color:orange; /*for ie6*/
}
@media screen and (min-width:0){
.hacktest {background-color:black\0;} /*opera*/
}
@media screen and (min-width:0) {
.hacktest { background-color:purple\9; }/* for IE9/IE10 PS:国外有些习惯常写作\0,根本没考虑Opera也认识\0的实际 */
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
.hacktest { background-color:green; } /* for IE10+ 此写法可以适配到高对比度和默认模式,故可覆盖所有ie10的模式 */
}
@media screen and (-webkit-min-device-pixel-ratio:0){ .hacktest {background-color:gray;} } /*for Chrome/Safari*/
/* #963棕色 :root is for IE9/IE10, 优先级高于@media, 慎用!如果二者合用,必要时在@media样式加入 !important 才能区分IE9和IE10 */
/*
:root .hacktest { background-color:#963\9; }
*/
</style>

demo1是测试不同IE浏览器下hack 的显示效果
IE6显示为:粉色,
IE7显示为:粉色,
IE8显示为:蓝色,
IE9显示为:蓝色,
Firefox/Chrome/Opera显示为:蓝色,
若去掉其中的!important属性定义,则IE6/7仍然是粉色,IE8是紫色,IE9/10为橙色,Firefox/Chrome变为红色,Opera是紫色。是不是有些奇怪:除了IE6以外,其他所有的表现都符合我们的期待。那为何IE6表现的颜色不是_background-color:green;的绿色而是+background-color:pink的粉色呢?其实是最后一句所谓的IE7私有hack惹的祸?不是说+是IE7的专有hack吗???错,你可能太粗心了!我们常说的IE7专有+hack的格式是+html selector,而不是上面的直接在属性上加*+前缀。如果是为IE7定制特殊样式,应该这样使用:

1
2
3
*+html #ie7test { /* IE7 only*/
color:green;
}

经过测试,我发现属性前缀+background-color:pink;只有IE6和IE7认识。而+html selector只有IE7认识。所以我们在使用时候一定要特别注意。

demo2实例是用于区分标准模式下ie6~ie9和Firefox/Chrome的hack,注意顺序
IE6显示为:绿色,
IE7显示为:黑色,
IE8显示为:红色,
IE9显示为:蓝色,
Firefox/Chrome显示为:橘色,
(本例IE10效果同IE9,Opera最新版效果同IE8)

demo3实例也是用于区分标准模式下ie6~ie9和Firefox/Chrome的hack,注意顺序
IE6显示为:红色,
IE7显示为:蓝色,
IE8显示为:绿色,
IE9显示为:粉色,
Firefox/Chrome显示为:橘色,
(本例IE10效果同IE9,Opera最新版效果也同IE9为粉色)

demo4实例是用于区分标准模式下ie6~ie10和Opera/Firefox/Chrome的hack,本例特别要注意顺序
IE6显示为:橘色,
IE7显示为:粉色,
IE8显示为:黄色,
IE9显示为:紫色,
IE10显示为:绿色,
Firefox显示为:蓝色,
Opera显示为:黑色,
Safari/Chrome显示为:灰色,

img

(3)CSS hack方式三:选择器前缀法

选择器前缀法是针对一些页面表现不一致或者需要特殊对待的浏览器,在CSS选择器前加上一些只有某些特定浏览器才能识别的前缀进行hack。

目前最常见的是

1
2
3
4
5
6
7
8
9
*html *前缀只对IE6生效
*+html *+前缀只对IE7生效
@media screen\9{...}只对IE6/7生效
@media \0screen {body { background: red; }}只对IE8有效
@media \0screen\,screen\9{body { background: blue; }}只对IE6/7/8有效
@media screen\0 {body { background: green; }} 只对IE8/9/10有效
@media screen and (min-width:0\0) {body { background: gray; }} 只对IE9/10有效
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {body { background: orange; }} 只对IE10有效
等等

结合CSS3的一些选择器,如html:first-child,body:nth-of-type(1),衍生出更多的hack方式,具体的可以参考下表:

img

4. CSS3选择器结合JavaScript的Hack

我们用IE10进行举例:

由于IE10用户代理字符串(UserAgent)为:Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0),所以我们可以使用JavaScript将此属性添加到文档标签中,再运用CSS3基本选择器匹配。

JavaScript代码:

1
2
3
var htmlObj = document.documentElement;
htmlObj.setAttribute('data-useragent',navigator.userAgent);
htmlObj.setAttribute('data-platform', navigator.platform );

CSS3匹配代码:

1
2
3
html[data-useragent*='MSIE 10.0'] #id {
color: #F00;
}

5. CSS hack利弊

一般情况下,我们尽量避免使用CSS hack,但是有些情况为了顾及用户体验实现向下兼容,不得已才使用hack。比如由于IE8及以下版本不支持CSS3,而我们的项目页面使用了大量CSS3新属性在IE9/Firefox/Chrome下正常渲染,这种情况下如果不使用css3pie或htc或条件注释等方法时,可能就得让IE8-的专属hack出马了。使用hack虽然对页面表现的一致性有好处,但过多的滥用会造成html文档混乱不堪,增加管理和维护的负担。相信只要大家一起努力,少用、慎用hack,未来一定会促使浏览器厂商的标准越来越趋于统一,顺利过渡到标准浏览器的主流时代。抛弃那些陈旧的IE hack,必将减轻我们编码的复杂度,少做无用功。

最后补上一张引自国外某大牛总结的CSS hack表,这时一张6年前的旧知识汇总表了,放在这里仅供需要时候方便参考。

img

六、对设计模式了解吗?请实现一个单例模式。

答:

1. 设计模式

​ 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

设计模式有六大原则:

  1. 开闭原则。就是说模块应对扩展开放,而对修改关闭。
  2. 里氏代换原则。如果调用的是父类的话,那么换成子类也完全可以运行。
  3. 依赖倒转原则。把父类都替换成它的子类,程序的行为没有变化。
  4. 接口隔离原则,每一个接口应该是一种角色,不多不少,不干不该干的事,该干的事都要干。
  5. 单一职责原则。
  6. 迪米特法则。 最少知识原则。

2. 单例模式

​ 在传统开发工程师眼里,单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。在JavaScript里,单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象。

在JavaScript里,实现单例的方式有很多种,其中最简单的一个方式是使用对象字面量的方法,其字面量里可以包含大量的属性和方法:

1
2
3
4
5
6
7
var mySingleton = {
property1: "something",
property2: "something else",
method1: function () {
console.log('hello world');
}
};

如果以后要扩展该对象,你可以添加自己的私有成员和方法,然后使用闭包在其内部封装这些变量和函数声明。只暴露你想暴露的public成员和方法,样例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var mySingleton = function () {
/* 这里声明私有变量和方法 */
var privateVariable = 'something private';
function showPrivate() {
console.log(privateVariable);
}
/* 公有变量和方法(可以访问私有变量和方法) */
return {
publicMethod: function () {
showPrivate();
},
publicVar: 'the public can see this!'
};
};
var single = mySingleton();
single.publicMethod(); // 输出 'something private'
console.log(single.publicVar); // 输出 'the public can see this!'

上面的代码很不错了,但如果我们想做到只有在使用的时候才初始化,那该如何做呢?为了节约资源的目的,我们可以另外一个构造函数里来初始化这些代码,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var Singleton = (function () {
var instantiated;
function init() {
/*这里定义单例代码*/
return {
publicMethod: function () {
console.log('hello world');
},
publicProperty: 'test'
};
}
return {
getInstance: function () {
if (!instantiated) {
instantiated = init();
}
return instantiated;
}
};
})();
/*调用公有的方法来获取实例:*/
Singleton.getInstance().publicMethod();

知道了单例如何实现了,但单例用在什么样的场景比较好呢?其实单例一般是用在系统间各种模式的通信协调上,下面的代码是一个单例的最佳实践:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
var SingletonTester = (function () {
//参数:传递给单例的一个参数集合
function Singleton(args) {
//设置args变量为接收的参数或者为空(如果没有提供的话)
var args = args || {};
//设置name参数
this.name = 'SingletonTester';
//设置pointX的值
this.pointX = args.pointX || 6; //从接收的参数里获取,或者设置为默认值
//设置pointY的值
this.pointY = args.pointY || 10;
}
//实例容器
var instance;
var _static = {
name: 'SingletonTester',
//获取实例的方法
//返回Singleton的实例
getInstance: function (args) {
if (instance === undefined) {
instance = new Singleton(args);
}
return instance;
}
};
return _static;
})();
var singletonTest = SingletonTester.getInstance({ pointX: 5 });
console.log(singletonTest.pointX); // 输出 5

其它实现方式

方法1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Universe() {
// 判断是否存在实例
if (typeof Universe.instance === 'object') {
return Universe.instance;
}
// 其它内容
this.start_time = 0;
this.bang = "Big";
// 缓存
Universe.instance = this;
// 隐式返回this
}
// 测试
var uni = new Universe();
var uni2 = new Universe();
console.log(uni === uni2); // true

方法2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Universe() {
// 缓存的实例
var instance = this;
// 其它内容
this.start_time = 0;
this.bang = "Big";
// 重写构造函数
Universe = function () {
return instance;
};
}
// 测试
var uni = new Universe();
var uni2 = new Universe();
uni.bang = "123";
console.log(uni === uni2); // true
console.log(uni2.bang); // 123

方法3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
function Universe() {
// 缓存实例
var instance;
// 重新构造函数
Universe = function Universe() {
return instance;
};
// 后期处理原型属性
Universe.prototype = this;
// 实例
instance = new Universe();
// 重设构造函数指针
instance.constructor = Universe;
// 其它功能
instance.start_time = 0;
instance.bang = "Big";
return instance;
}
// 测试
var uni = new Universe();
var uni2 = new Universe();
console.log(uni === uni2); // true
// 添加原型属性
Universe.prototype.nothing = true;
var uni = new Universe();
Universe.prototype.everything = true;
var uni2 = new Universe();
console.log(uni.nothing); // true
console.log(uni2.nothing); // true
console.log(uni.everything); // true
console.log(uni2.everything); // true
console.log(uni.constructor === Universe); // true

方式4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var Universe;
(function () {
var instance;
Universe = function Universe() {
if (instance) {
return instance;
}
instance = this;
// 其它内容
this.start_time = 0;
this.bang = "Big";
};
} ());
//测试代码
var a = new Universe();
var b = new Universe();
alert(a === b); // true
a.bang = "123";
alert(b.bang); // 123

七、JS 延迟加载的方式有哪些?

答:

1.直接将 script 节点放置在</body>之前,这样 js 脚本就会在页面显示出来之后再加载。

2.使用 script 标签的 defer 和 async 属性,defer 属性为延迟加载,是在页面渲染完成之后再进行加载的,而 async 属性则是和文档并行加载,这两种解决方案都不完美,原因在于不是所有浏览器都支持。

3.通过监听 onload 事件,动态添加 script 节点:

//Firefox,Opera,Chrome,Safari的方式

1
2
3
4
5
6
7
8
9
10
var script = document.createElement ("script")
script.type = "text/javascript";
//Firefox, Opera, Chrome, Safari 3+
script.onload = function(){
alert("Script loaded!");
};
script.src = "script1.js";
document.getElementsByTagName("head")[0].appendChild(script);

//IE的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
var script = document.createElement("script")
script.type = "text/javascript";
//Internet Explorer
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
alert("Script loaded.");
}
};
script.src = "script1.js";
document.getElementsByTagName("head")[0].appendChild(script);

其实IE和其它浏览器加载添加节点的方式都一样,只是加载之后监听是否成功的事件不一样,其实这个不需要也无所谓。

4,通过ajax下载js脚本,动态添加script节点

​ 这种方式与第二种类似,区别就在与js脚本的自动下载还是通过ajax下载,ajax的方式显然可控制性更好一点,它可以先下载js文件,但不立即执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
var xhr = new XMLHttpRequest();
xhr.open("get", "script1.js", true);
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
var script = document.createElement ("script");
script.type = "text/javascript";
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
};
xhr.send(null);

​ 但是ajax有一个缺点,就是无法引用使用CDN方式提供的js文件,因为这种方式下,你即时通过xhr.open下载了js文件,而向body中注入script节点时还是需要向CDN请求js文件。

​ 具体使用哪种方式就得看具体情况了,有几个原则:

​ 如果使用延迟加载技术,那么js脚本应该不能对页面的元素进行更改;

​ js 脚本文件的数量应该尽量少,可以将多个合并在一起。

八、document.write 和 innerHTML 的区别?

答:

document.write只能重绘整个页面, innerHTML可以重绘页面的一部分。

​ document.write 是直接写入到页面的内容流,如果在写之前没有调用document.open,浏览器会自动调用open。每次写完关闭之后重新调用该函数,会导致页面被重写。

​ innerHTML 则是DOM页面元素的一个属性,代表该元素的html内容。你可以精确到某一个具体的元素来进行更改。如果想修改document的内容,则需要修改document.documentElement.innerElement。

innerHTML很多情况下都优于document.write,其原因在于其允许更精确的控制要刷新页面的那一个部分。

九、如何阻止事件冒泡和默认事件?

答:

1. 取消默认操作

w3c 的方法是 e.preventDefault(),IE 则是使用 e.returnValue = false;

在支持 addEventListener() 的浏览器中,也能通过调用时间对象的 preventDefault() 方法取消时间的默认操作。不过,在 IE9 之前的 IE 中,可以通过设置事件对象的 returnValue 属性为 false 来达到同样的效果。下面的代码假设一个事件处理程序,它使用全部的三种取消技术:

1
2
3
4
5
6
7
[js] view plaincopy
function cancelHandler(event){
var event = event || window.event; //用于IE
if(event.preventDefault) event.preventDefault(); //标准技术
if(event.returnValue) event.returnValue = false; //IE
return false; //用于处理使用对象属性注册的处理程序
}

当前的 DOM 事件模型草案定义了 Event 对象属性 defaultPrevented。

return false

javascript 的 return false 只会阻止默认行为,而如果是用 jQuery 的话则既阻止默认行为又防止对象冒泡。

下面这个使用原生 JS,只会阻止默认行为,不会停止冒泡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[js] view plaincopy
<div id='div' onclick='alert("div");'>
  <ul onclick='alert("ul");'>
    <li id='ul-a' onclick='alert("li");'><a href="<a href="http://caibaojian.com/" id="testB" >caibaojian.com<="" a><="" li"="" target="_blank">http://caibaojian.com/"id="testB">caibaojian.com</a></li</a>>
  </ul>
</div>
var a = document.getElementById("testB");
  a.onclick = function(){
  return false;
};

2. 阻止冒泡

w3c 的方法是 e.stopPropagation(),IE 则是使用 e.cancelBubble = true

在支持 addEventListener() 的浏览器中,可以调用事件对象的一个 stopPropagation() 方法以阻止事件的继续传播。如果在同一对象上定义了其他处理程序,剩下的处理程序将依旧被调用,但调用 stopPropagation() 方法可以在事件传播期间的任何时间调用,它能工作在捕获阶段、事件目标本身中和冒泡阶段。

IE9 之前的IE不支持 stopPropagation() 方法。相反,IE事件对象有一个 cancleBubble 属性,设置这个属性为 true 能阻止事件进一步传播。( IE8 及之前版本不支持事件传播的捕获阶段,所以冒泡是唯一待取消的事件传播。)

当前的 DOM 事件规范草案在 Event 对象上定义了另一个方法,命名为stopImmediatePropagation()。类似 stopPropagation(),这个方法组织了任何其他对象的事件传播,但也阻止了在相同对象上注册的任何其他事件处理程序的调用。

1
2
3
4
5
6
7
8
9
10
[js] view plaincopy
<div id='div' onclick='alert("div");'>
  <ul onclick='alert("ul");'>
    <li onclick='alert("li");'>test</li>
  </ul>
</div>

阻止冒泡

1
2
3
4
5
6
[js] view plaincopy
function stopHandler(event)
window.event?window.event.cancelBubble=true:event.stopPropagation();
}

十、如何添加、删除、替换、插入某个节点?举例说明 call 和 apply 的区别?

答:

1. 添加、删除、替换、插入某个节点

创建元素节点 createElement
createElement()方法可创建元素节点。此方法可返回一个 Element 对象。
语法:

1
2
3
document.createElement(tagName)
//参数:
//tagName:字符串值,这个字符串用来指明创建元素的类型。

要与appendChild() 或 insertBefore()方法联合使用,将元素显示在页面中。

创建文本节点createTextNode
createTextNode() 方法创建新的文本节点,返回新创建的 Text 节点。
语法:

1
2
3
document.createTextNode(data)
//参数:
//data : 字符串值,可规定此节点的文本。

删除节点removeChild()
removeChild() 方法从子节点列表中删除某个节点。如删除成功,此方法可返回被删除的节点,如失败,则返回 NULL。
语法:

1
2
3
nodeObject.removeChild(node)
//参数:
//node :必需,指定需要删除的节点。

替换元素节点replaceChild()
语法:

1
2
3
4
node.replaceChild (newnode,oldnew )
//参数:
//newnode : 必需,用于替换 oldnew 的对象。
//oldnew : 必需,被 newnode 替换的对象。

插入节点appendChild()
在指定节点的最后一个子节点列表之后添加一个新的子节点
语法:

1
2
3
appendChild(newnode)
//参数:
//newnode:指定追加的节点。

插入节点insertBefore()
insertBefore() 方法可在已有的子节点前插入一个新的子节点。
语法:

1
2
3
4
insertBefore(newnode,node);
//参数:
//newnode: 要插入的新节点。
//node: 指定此节点前插入节点。

2. call 和 apply 的区别

  • call:调用一个对象的一个方法,以另一个对象替换当前的this,其中传参以不定数的参数传传入。
  • apply:调用一个对象的一个方法,以另一个对象替换当前的this,其中传参以数组或类数组对象传入。
1
2
3
4
5
6
7
8
9
10
var food = "fish";
var Tom = {food:"beef"};
var eatFood = function(friend1,friend2){
console.log('我跟'+friend1+"和"+friend2+"一起去吃"+this.food);
};
/*我跟Karry和Mage一起去吃fish*/
eatFood("Karry","Mage");
/*我跟Monter和Father一起去吃beef*/
eatFood.call(Tom,"Monter","Father");
eatFood.apply(Tom,["Monter","Father"]);

​ eatFood是一个函数对象,callapply是函数对象的一个内置的方法。在非严格模式下,直接调用eatFood()的时候,函数里的this是指向window的,所以打印出来的foodfish ;而通过callapply调用,此时eatFood的this指针已经被Tom代替了,所以,因此打印出来的是beef
​ 还有从例子中,我们也可以看出,call是接收参数需要逐个列举出来,apply则是接收数组形式的参数即可,比如普通数组或者arguments类数组都可以。

作用

其实使用callapply最大的好处,就是可以扩充作用域,对象不需要与方法有任何的耦合关心。
举个栗子,在实现javascript的对象继承的时候,除了使用原型链的方式外,我们还可以使用是用callapply来实现javascript的对象继承。

1
2
3
4
5
6
7
8
9
10
11
function Animal(name){
this.name = name;
this.sayName = function(){
console.log(this.name);
}
}
function Cat(name){
Animal.call(this,name);/*或Animal.apply(this,[name])*/
}
var cat = new Cat("maomao");
cat.sayName();

​ 从例子可以看到,Cat函数对象本身是没有sayName这个方法属性的,那为什么却可以调用呢?实际上,Animal.call(this) 的意思就是使用 Animal对象代替Cat函数对象里面的this指针,那么 Cat中不就有Animal的所有属性和方法了吗,Cat对象就能够直接调用Animal的方法以及属性了.

十一、transition、animation、transform 的区别?

答:

1.transform是单独的形变,偏移,而transitionanimation都加上了时间属性,所以能够产生动画效果。
2.transition的动画效果一般由行为(hover,js等)触发,而animation则是自动触发。
3.transition的动画效果只有两帧关键帧,而animation可以有更多帧。

其中 transform 描述了元素静态样式。而transition 和 animation 却都能实现动画效果。

所以三者之中transform 常常配合后两者使用,在页面实现酷炫的五毛(或五元)特效。

不同点:

  1. 触发条件不同。transition通常和hover等事件配合使用,由事件触发。animation则和gif动态图差不多,立即播放。
  2. 循环。 animation可以设定循环次数。
  3. 精确性。 animation可以设定每一帧的样式和时间。tranistion 只能设定头尾。 animation中可以设置每一帧需要单独变化的样式属性, transition中所有样式属性都要一起变化。
  4. 与JavaScript的交互。animation与js的交互不是很紧密。tranistion和js的结合更强大。js设定要变化的样式,transition负责动画效果,天作之合,比之前只能用js时爽太多。

结论:

  1. 如果要灵活定制多个帧以及循环,用animation.
  2. 如果要简单的from to 效果,用 transition.
  3. 如果要使用js灵活设定动画属性,用transition.

十二、请描述一下重绘和回流是怎么回事?

答:

一、概念

首先我们要明白的是,页面的显示过程分为以下几个阶段:

1、生成DOM树(包括display:none的节点)

2、在DOM树的基础上根据节点的集合属性(margin,padding,width,height等)生成render树(不包括display:none,head节点,但是包括visibility:hidden的节点)

3、在render树的基础上继续渲染颜色背景色等样式

reflow: 当render树的一部分或者全部因为大小边距等问题发生改变而需要重建的过程,叫做回流

repaint: 当诸如颜色背景等不会引起页面布局变化,而只需要重新渲染的过程叫做重绘

​ 通过上述定义,可以很明显看出,重绘的代价要比回流小,毕竟重绘只涉及样式的改变,不涉及到布局。重绘就好像给人染了一个头发,而回流相当于给人做了一次抽脂手术

二、什么会引起回流

这也是网易题目的出法

  1. 页面渲染初始化

  2. DOM结构变化,比如删除了某个节点;骨头都被打断了,肯定比抽脂更严重,所以会引发回流

  3. render树变化,比如减少了padding;也就是进行抽脂手术

  4. 窗口resize事件触发

  5. 最复杂的一种:获取某些属性,引发回流 很多浏览器会对回流做优化,他会等到足够数量的变化发生,在做一次批处理回流。 但是除了render树的直接变化。 当获取一些属性时,浏览器为了获得正确的值也会触发回流。这样就使得浏览器的优化失效了,这些属性包括

    1. offsetTop, offsetLeft, offsetWidth, offsetHeight
    2. scrollTop/Left/Width/Height
    3. clientTop/Left/Width/Height
    4. width,height
    5. 调用了getComputedStyle(), 或者 IE的 currentStyle
    1
    2
    3
    4
    5
    6
    7
    8
    var s = document.body.style;
    s.padding = "2px"; // 回流+重绘
    s.border = "1px solid red"; // 再一次 回流+重绘
    s.color = "blue"; // 再一次重绘
    s.backgroundColor = "#ccc"; // 再一次 重绘
    s.fontSize = "14px"; // 再一次 回流+重绘
    // 添加node,再一次 回流+重绘
    document.body.appendChild(document.createTextNode('abc!'));

    可以看出,回流一定伴随着重绘,而重绘却可以单独出现

    可以理解为,路人甲摔断了腿或者抽脂之后,病怏怏导致头发也变白了(回流+重绘);但是炮灰乙却仅仅是去村口王师傅那里烫了头(重绘)

    回流对性能产生了一定的影响,尽管浏览器机智地帮我们进行了批处理,但是仍然存在着上述诸多阔怕的属性,一获取就回流。怎么解决?

三、减少回流

  1. 避免逐项更改样式。最好一次性更改style属性,或者将样式列表定义为class并一次性更改class属性。
  2. 避免循环操作DOM。创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到window.document。
  3. 避免多次读取offsetLeft等属性。无法避免则将它们缓存到变量。
  4. 将复杂的元素绝对定位或固定定位,使它脱离文档流。否则回流代价十分高

补充:改变字体大小会引发回流

回到网易的问题,并适当做延伸:display:none和visibility:hidden会产生回流与重绘吗?

display:none指的是元素完全不陈列出来,不占据空间,涉及到了DOM结构,故产生reflow与repaint

visibility:hidden指的是元素不可见但存在,保留空间,不影响结构,故只产生repaint

十三、移动端和 PC 端性能优化有哪些方法?

答:

(一)移动端性能优化

移动H5前端性能优化指南

移动H5前端性能优化指南

概述

  1. PC优化手段在Mobile侧同样适用
  2. 在Mobile侧我们提出三秒种渲染完成首屏指标
  3. 基于第二点,首屏加载3秒完成或使用Loading
  4. 基于联通3G网络平均338KB/s(2.71Mb/s),所以首屏资源不应超过1014KB
  5. Mobile侧因手机配置原因,除加载外渲染速度也是优化重点
  6. 基于第五点,要合理处理代码减少渲染损耗
  7. 基于第二、第五点,所有影响首屏加载和渲染的代码应在处理逻辑中后置
  8. 加载完成后用户交互使用时也需注意性能

[加载优化]

加载过程是最为耗时的过程,可能会占到总耗时的80%时间,因此是优化的重点

· 减少HTTP请求
因为手机浏览器同时响应请求为4个请求(Android支持4个,iOS 5后可支持6个),所以要尽量减少页面的请求数,首次加载同时请求数不能超过4个
a) 合并CSS、JavaScript
b) 合并小图片,使用雪碧图

· 缓存
使用缓存可以减少向服务器的请求数,节省加载时间,所以所有静态资源都要在服务器端设置缓存,并且尽量使用长Cache(长Cache资源的更新可使用时间戳)
a) 缓存一切可缓存的资源
b) 使用长Cache(使用时间戳更新Cache)
c) 使用外联式引用CSS、JavaScript

· 压缩HTML、CSS、JavaScript
减少资源大小可以加快网页显示速度,所以要对HTML、CSS、JavaScript等进行代码压缩,并在服务器端设置GZip
a) 压缩(例如,多余的空格、换行符和缩进)
b) 启用GZip

· 无阻塞
写在HTML头部的JavaScript(无异步),和写在HTML标签中的Style会阻塞页面的渲染,因此CSS放在页面头部并使用Link方式引入,避免在HTML标签中写Style,JavaScript放在页面尾部或使用异步方式加载

· 使用首屏加载
首屏的快速显示,可以大大提升用户对页面速度的感知,因此应尽量针对首屏的快速显示做优化

· 按需加载
将不影响首屏的资源和当前屏幕资源不用的资源放到用户需要时才加载,可以大大提升重要资源的显示速度和降低总体流量
PS:按需加载会导致大量重绘,影响渲染性能
a) LazyLoad
b) 滚屏加载
c) 通过Media Query加载

· 预加载
大型重资源页面(如游戏)可使用增加Loading的方法,资源加载完成后再显示页面。但Loading时间过长,会造成用户流失
对用户行为分析,可以在当前页加载下一页资源,提升速度
a) 可感知Loading(如进入空间游戏的Loading)
b) 不可感知的Loading(如提前加载下一页)

· 压缩图片
图片是最占流量的资源,因此尽量避免使用他,使用时选择最合适的格式(实现需求的前提下,以大小判断),合适的大小,然后使用智图压缩,同时在代码中用Srcset来按需显示
PS:过度压缩图片大小影响图片显示效果
a) 使用智图( http://zhitu.isux.us/
b) 使用其它方式代替图片(1. 使用CSS3 2. 使用SVG 3. 使用IconFont)
c) 使用Srcset
d) 选择合适的图片(1. webP优于JPG 2. PNG8优于GIF)
e) 选择合适的大小(1. 首次加载不大于1014KB 2. 不宽于640(基于手机屏幕一般宽度))

· 减少Cookie
Cookie会影响加载速度,所以静态资源域名不使用Cookie

· 避免重定向
重定向会影响加载速度,所以在服务器正确设置避免重定向

· 异步加载第三方资源
第三方资源不可控会影响页面的加载和显示,因此要异步加载第三方资源

[脚本执行优化]

脚本处理不当会阻塞页面加载、渲染,因此在使用时需当注意

· CSS写在头部,JavaScript写在尾部或异步

· 避免图片和iFrame等的空Src
空Src会重新加载当前页面,影响速度和效率

· 尽量避免重设图片大小
重设图片大小是指在页面、CSS、JavaScript等中多次重置图片大小,多次重设图片大小会引发图片的多次重绘,影响性能

· 图片尽量避免使用DataURL
DataURL图片没有使用图片的压缩算法文件会变大,并且要解码后再渲染,加载慢耗时长

[CSS优化]

· 尽量避免写在HTML标签中写Style属性

· 避免CSS表达式
CSS表达式的执行需跳出CSS树的渲染,因此请避免CSS表达式

· 移除空的CSS规则
空的CSS规则增加了CSS文件的大小,且影响CSS树的执行,所以需移除空的CSS规则

· 正确使用Display的属性
Display属性会影响页面的渲染,因此请合理使用
a) display:inline后不应该再使用width、height、margin、padding以及float
b) display:inline-block后不应该再使用float
c) display:block后不应该再使用vertical-align
d) display:table-*后不应该再使用margin或者float

· 不滥用Float
Float在渲染时计算量比较大,尽量减少使用

· 不滥用Web字体
Web字体需要下载,解析,重绘当前页面,尽量减少使用

· 不声明过多的Font-size
过多的Font-size引发CSS树的效率

· 值为0时不需要任何单位
为了浏览器的兼容性和性能,值为0时不要带单位

· 标准化各种浏览器前缀
a) 无前缀应放在最后
b) CSS动画只用 (-webkit- 无前缀)两种即可
c) 其它前缀为 -webkit- -moz- -ms- 无前缀 四种,(-o-Opera浏览器改用blink内核,所以淘汰)

· 避免让选择符看起来像正则表达式
高级选择器执行耗时长且不易读懂,避免使用

[JavaScript执行优化]

· 减少重绘和回流
a) 避免不必要的Dom操作
b) 尽量改变Class而不是Style,使用classList代替className
c) 避免使用document.write
d) 减少drawImage

· 缓存Dom选择与计算
每次Dom选择都要计算,缓存他

· 缓存列表.length
每次.length都要计算,用一个变量保存这个值

· 尽量使用事件代理,避免批量绑定事件

· 尽量使用ID选择器
ID选择器是最快的

· TOUCH事件优化
使用touchstart、touchend代替click,因快影响速度快。但应注意Touch响应过快,易引发误操作

[渲染优化]

· HTML使用Viewport
Viewport可以加速页面的渲染,请使用以下代码
<meta name="viewport" content="width=device-width, initial-scale=1">

· 减少Dom节点
Dom节点太多影响页面的渲染,应尽量减少Dom节点

· 动画优化
a) 尽量使用CSS3动画
b) 合理使用requestAnimationFrame动画代替setTimeout
c) 适当使用Canvas动画 5个元素以内使用css动画,5个以上使用Canvas动画(iOS8可使用webGL)

· 高频事件优化
Touchmove、Scroll 事件可导致多次渲染
a) 使用requestAnimationFrame监听帧变化,使得在正确的时间进行渲染
b) 增加响应变化的时间间隔,减少重绘次数

· GPU加速
CSS中以下属性(CSS3 transitions、CSS3 3D transforms、Opacity、Canvas、WebGL、Video)来触发GPU渲染,请合理使用
PS:过渡使用会引发手机过耗电增加

(二) PC 端性能优化

一、页面优化的常用工具

1
2
3
4
5
6
7
1、Firbug + Yslow + pagespeed
2、webpage test www.webpagetest.org
3、DynaTrace 查看javascript cpu 占用等
4、Firbug net Panel
5、Chrome Developer Tools
6、IE9开发者工具
7、HTTPwatch

网站慢的因素很多

1
2
3
4
5
6
7
8
9
10
1、不同浏览器原因 - 客观
2、DNS原因 - 客观
3、地域问题 - 客观
4、页面html结构和布局
5、图片太多 太胖
6、http请求数太多
7、javascript 太胖
8、服务器端处理太差
9、网络原因
10、。。。。

二、网站优化

1
2
3
①、页面优化
②、服务器端优化
③、“主观”优化
1、页面优化
1
2
3
4
1、减少http请求次数
2、减少交互通信量
3、合理并行加载资源
4、减少消耗
2、服务器端优化
1
2
3
4
5
1、CDN
2、缓存
3、Gzip
4、减少DNS
5、响应速度
3、主观优化
1
2
3
4
1、目录优化
2、内容优化
3、体验优化
4、SEO
①减少http请求次数
1
2
3
4
5
6
1.合并能合并的文件
2.sprites(CSS,img)
紧凑的排列图片,颜色相似放在一起,不要留有空白,以减少体积,加快显示速度
3.删除重复脚本
浏览器不会忽略重复脚本,会再执行一次
4.Src值不能为空
②减少交互通信量
1
2
3
4
5
6
7
8
9
10
11
12
1.压缩技术(JS,CSS,img,cookie)
CSS/JS--减少空白,增强逻辑性,用缩写方式,压缩
IMG—png8,压缩图片,不缩放图片
2.缓存技术(JS,CSS,ajax)
3.减少不必要通信
推迟加载(懒加载)/预加载
用GET方式进行AJAX请求
静态内容无cookie(如图片等)
4.优化DOM结构,降低信噪比
5、JS压缩与格式化 http://tool.chinaz.com/Tools/JsFormat.aspx
css压缩与格式化 http://tool.chinaz.com/Tools/CssFormat.aspx
图片压缩 : 图床
③合理并行加载资源
1
2
3
4
5
6
7
1.尽量避免重定向
2.慎用iframe
不被搜索引擎识别,空的iframe加载时会阻止内容加载
3.CSS置于顶JS置于样式后
JS阻塞加载
4.分域
综合并行加载数,注意加载资源项的域名书写
④减少消耗

1.避免使用CSS表达式(expression方法。计算频度太高)

2.避免使用滤镜(问题在于:代码维护量大,冻结浏览器,增加客户内存占用)

3.减少DOM访问( JS访问DOM是很慢的,重新渲染)

三、对于pc端的性能优化的其他说法

1
2
3
4
5
6
7
1、对于页面:采用最优布局方式;优化DOM结构;减少iframe使用;推迟加载;预加载;
2、对于CSS:把样式表置于顶部:避免使用CSS表达式(Expression);避免使用滤镜;使用外部CSS;削减CSS;合并压缩;
3、对于Javascript:把脚本置于页面底部;使用外部JavaScript;削减JavaScript;剔除重复脚本;减少DOM访问;延迟执行;合并压缩;
4、对于图片Img:PNG8;JPG;优化压缩;CSSsprites;IMGsprites;推迟加载;预加载;

十四、对 BFC 了解吗?

答:简单地说,BFC就是像例子里面一样顺次竖着排块级盒的一种上下文。竖着排盒子而已,竖着排盒子有什么理解不了的啊我X?

一、BFC是什么?

BFC(Block Formatting Context)直译为“块级格式化范围”。

是 W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。当涉及到可视化布局的时候,Block Formatting Context提供了一个环境,HTML元素在这个环境中按照一定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。比如浮动元素会形成BFC,浮动元素内部子元素的主要受该浮动元素影响,两个浮动元素之间是互不影响的。这里有点类似一个BFC就是一个独立的行政单位的意思。也可以说BFC就是一个作用范围。可以把它理解成是一个独立的容器,并且这个容器的里box的布局,与这个容器外的毫不相干。

另一个通俗点的解释是:在普通流中的 Box(框) 属于一种 formatting context(格式化上下文) ,类型可以是 block ,或者是 inline ,但不能同时属于这两者。并且, Block boxes(块框) 在 block formatting context(块格式化上下文) 里格式化, Inline boxes(块内框) 则在 inline formatting context(行内格式化上下文) 里格式化。任何被渲染的元素都属于一个 box ,并且不是 block ,就是 inline 。即使是未被任何元素包裹的文本,根据不同的情况,也会属于匿名的 block boxes 或者 inline boxes。所以上面的描述,即是把所有的元素划分到对应的 formatting context 里。

其一般表现规则,我整理了以下这几个情况:

1、在创建了 Block Formatting Context 的元素中,其子元素按文档流一个接一个地放置。垂直方向上他们的起点是一个包含块的顶部,两个相邻的元素之间的垂直距离取决于 ‘margin’ 特性。

​ 根据 CSS 2.1 8.3.1 Collapsing margins 第一条,两个相邻的普通流中的块框在垂直位置的空白边会发生折叠现象。也就是处于同一个BFC中的两个垂直窗口的margin会重叠。

​ 根据 CSS 2.1 8.3.1 Collapsing margins 第三条,生成 block formatting context 的元素不会和在流中的子元素发生空白边折叠。所以解决这种问题的办法是要为两个容器添加具有BFC的包裹容器。

2、在 Block Formatting Context 中,每一个元素左外边与包含块的左边相接触(对于从右到左的格式化,右外边接触右边), 即使存在浮动也是如此(尽管一个元素的内容区域会由于浮动而压缩),除非这个元素也创建了一个新的 Block Formatting Context 。

3、Block Formatting Context就是页面上的一个隔离的独立容器,容器里面的子元素不会在布局上影响到外面的元素,反之也是如此。

4、根据 CSS 2.1 9.5 Floats 中的描述,创建了 Block Formatting Context 的元素不能与浮动元素重叠。

​ 表格的 border-box、块级的替换元素、或是在普通流中创建了新的 block formatting context(如元素的 ‘overflow’ 特性不为 ‘visible’ 时)的元素不可以与位于相同的 block formatting context 中的浮动元素相重叠。

5 、当容器有足够的剩余空间容纳 BFC 的宽度时,所有浏览器都会将 BFC 放置在浮动元素所在行的剩余空间内。

6、 在 IE6 IE7 IE8 Chrome Opera 中,当 BFC 的宽度介于 “容器剩余宽度” 与 “容器宽度” 之间时,BFC 会显示在浮动元素的下一行;在 Safari 中,BFC 则仍然保持显示在浮动元素所在行,并且 BFC 溢出容器;在 Firefox 中,当容器本身也创建了 BFC 或者容器的 ‘padding-top’、’border-top-width’ 这些特性不都为 0 时表现与 IE8(S)、Chrome 类似,否则表现与 Safari 类似。

经验证,最新版本的浏览中只有firefox会在同一行显示,其它浏览器均换行。

7、 在 IE6 IE7 IE8 Opera 中,当 BFC 的宽度大于 “容器宽度” 时,BFC 会显示在浮动元素的下一行;在 Chrome Safari 中,BFC 则仍然保持显示在浮动元素所在行,并且 BFC 溢出容器;在 Firefox 中,当容器本身也创建了 BFC 或者容器的 ‘padding- top’、’border-top-width’ 这些特性不都为 0 时表现与 IE8(S) 类似,否则表现与 Chrome 类似。

经验证,最新版本的浏览中只有firefox会在同一行显示,其它浏览器均换行。

8、根据CSS2.1 规范第10.6.7部分的高度计算规则,在计算生成了 block formatting context 的元素的高度时,其浮动子元素应该参与计算。

如果还有其它情况,请各位回得中补充,我会及时更新!

下面先看一个比较典型的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>无标题文档</title>
<style>
* { padding:0; margin:0; }
#red, #yellow, #orange, #green { width:100px; height:100px; float:left; }
#red { background-color:red; }
#yellow { background-color:yellow; }
#orange { background-color:orange; }
#green { background-color:green; }
</style>
</head>
<body>
<div id="c1">
<div id="red">
</div>
<div id="yellow">
</div>
</div>
<div id="c2">
<div id="orange">
</div>
<div id="green">
</div>
</div>
<p>Here is the text!</p>
</body>
</html>

效果如下:

img

该段代码本意要形成两行两列的布局,但是由于#red,#yellow,#orange,#green四个div在同一个布局环境BFC中,因此虽然它们位于两个不同的div(#c1和#c2)中,但仍然不会换行,而是一行四列的排列。

若要使之形成两行两列的布局,就要创建两个不同的布局环境,也可以说要创建两个BFC。那到底怎么创建BFC呢?

二、如何产生BFC:当一个HTML元素满足下面条件的任何一点,都可以产生Block Formatting Context:

  • float的值不为none。
  • overflow的值不为visible。
  • display的值为table-cell, table-caption, inline-block中的任何一个。
  • position的值不为relative和static。

如果还其它方式,请在回复中给出,我会及时更新!!

上面的例子,我再加两行代码,创建两个BFC:

1
2
#c1{overflow:hidden;}
#c2{overflow:hidden;}

效果如下:

img

上面创建了两个布局环境BFC。内部子元素的左浮动不会影响到外部元素。所以#c1和#c2没有受浮动的影响,仍然各自占据一行!

三、BFC能用来做什么?

a、不和浮动元素重叠

如果一个浮动元素后面跟着一个非浮动的元素,那么就会产生一个覆盖的现象,很多自适应的两栏布局就是这么做的。

看下面一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>无标题文档</title>
<style>
html,body {height:100%; }
* { padding:0; margin:0; color:#fff; text-decoration:none; list-style:none; font-family:"微软雅黑" }
.aside{background:#f00;width:170px;float:left;height:300px;}
.main{background:#090;height:100%;}
</style>
</head>
<body>
<div class="aside">
</div>
<div class="main">
</div>
</body>
</html>

效果图如下:

img

很明显,.aside和.mian重叠了。试分析一下,由于两个box都处在同一个BFC中,都是以BFC边界为起点,如果两个box本身都具备BFC的话,会按顺序一个一个排列布局,现在.main并不具备BFC,按照规则2,内部元素都会从左边界开始,除非它本身具备BFC,按上面规则4拥有BFC的元素是不可以跟浮动元素重叠的,所以只要为.mian再创建一个BFC,就可以解决这个重叠的问题。上面已经说过创建BFC的方法,可以根据具体情况选用不同的方法,这里我选用的是加overflow:hidden。

由于ie的原因需要再加一个解发haslayout的zoom:1,有关haslayout后面会讲到。

b、清除元素内部浮动

只要把父元素设为BFC就可以清理子元素的浮动了,最常见的用法就是在父元素上设置overflow: hidden样式,对于IE6加上zoom:1就可以了(IE Haslayout)。

看下面例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>无标题文档</title>
<style>
html,body {height:100%; }
* { padding:10px; margin:0; color:#000; text-decoration:none; list-style:none; font-family:"微软雅黑" }
.outer{width:300px;border:1px solid #666;padding:10px;}
.innerLeft{height:100px;width:100px;float:left;background:#f00;}
.innerRight{height:100px;width:100px;float:right;background:#090;}
</style>
</head>
<body>
<div class="outer">
<div class="innerLeft"></div>
<div class="innerRight"></div>
</div>
</div>
</body>
</html>

效果图如下:

img

根据 CSS2.1 规范第 10.6.3 部分的高度计算规则,在进行普通流中的块级非替换元素的高度计算时,浮动子元素不参与计算。

同时 CSS2.1 规范第10.6.7部分的高度计算规则,在计算生成了 block formatting context 的元素的高度时,其浮动子元素应该参与计算。

所以,触发外部容器BFC,高度将重新计算。比如给outer加上属性overflow:hidden触发其BFC。

c、解决上下相邻两个元素重叠

看下面例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>无标题文档</title>
<style>
html,body {height:100%; }
* { padding:0; margin:0; color:#fff; text-decoration:none; list-style:none; font-family:"微软雅黑" }
.rowone{background:#f00;height:100px;margin-bottom:20px;overflow:hidden;}
.rowtow{background:#090;height:100px;margin-top:20px;position:relative}
</style>
</head>
<body>
<div class="rowone">
</div>
<div class="rowtow">
</div>
</body>
</html>

效果如下:

img

根据 CSS 2.1 8.3.1 Collapsing margins 第一条,两个相邻的普通流中的块框在垂直位置的空白边会发生折叠现象。也就是处于同一个BFC中的两个垂直窗口的margin会重叠。

根据 CSS 2.1 8.3.1 Collapsing margins 第三条,生成 block formatting context 的元素不会和在流中的子元素发生空白边折叠。所以解决这种问题的办法是要为两个容器添加具有BFC的包裹容器。

所以解这个问题的办法就是,把两个容器分别放在两个据有BFC的包裹容器中,IE里就是触发layout的两个包裹容器中!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>无标题文档</title>
<style>
html, body { height:100%; }
* { padding:0; margin:0; color:#fff; text-decoration:none; list-style:none; font-family:"微软雅黑" }
.mg {overflow:hidden; }
.rowone { background:#f00; height:100px; margin-bottom:20px; }
.rowtow { background:#090; height:100px; margin-top:20px; }
</style>
</head>
<body>
<div class="mg">
<div class="rowone">
</div>
</div>
<div class="mg">
<div class="rowtow">
</div>
</div>
</body>
</html>

效果如下:

img

四、什么是IE的haslayout

上面的例子中我们用到了IE的zoom:1;实际上是触发了IE的layout。Layout 是 IE 浏览器渲染引擎的一个内部组成部分。在 IE 浏览器中,一个元素要么自己对自身的内容进行组织和计算大小, 要么依赖于包含块来计算尺寸和组织内容。为了协调这两种方式的矛盾,渲染引擎采用了 ‘hasLayout’ 属性,属性值可以为 true 或 false。 当一个元素的 ‘hasLayout’ 属性值为 true 时,我们说这个元素有一个布局(layout),或拥有布局。可以通过 hasLayout 属性来判断一个元素是否拥有 layout ,

如 object.currentStyle.hasLayout 。

hasLayout 与 BFC 有很多相似之处,但 hasLayout 的概念会更容易理解。在 Internet Explorer 中,元素使用“布局”概念来控制尺寸和定位,分为拥有布局和没有布局两种情况,拥有布局的元素由它控制本身及其子元素的尺寸和定位,而没有布局的元素则通过父元素(最近的拥有布局的祖先元素)来控制尺寸和定位,而一个元素是否拥有布局则由 hasLayout 属性告知浏览器,它是个布尔型变量,true 代表元素拥有布局,false 代表元素没有布局。简而言之,hasLayout 只是一个 IE 下专有的属性,hasLayout 为 true 的元素浏览器会赋予它一系列的效果。

特别注意的是,hasLayout 在 IE 8 及之后的 IE 版本中已经被抛弃,所以在实际开发中只需针对 IE 8 以下的浏览器为某些元素触发 hasLayout。

五、怎样触发layout

一个元素触发 hasLayout 会影响一个元素的尺寸和定位,这样会消耗更多的系统资源,因此 IE 设计者默认只为一部分的元素触发 hasLayout (即默认有部分元素会触发 hasLayout ,这与 BFC 基本完全由开发者通过特定 CSS 触发并不一样),这部分元素如下:

1
2
3
4
5
6
7
<html>, <body>
<table>, <tr>, <th>, <td>
<img>
<hr>
<input>, <button>, <select>, <textarea>, <fieldset>, <legend>
<iframe>, <embed>, <object>, <applet>
<marquee>

除了 IE 默认会触发 hasLayout 的元素外,Web 开发者还可以使用特定的 CSS 触发元素的 hasLayout 。

通过为元素设置以下任一 CSS ,可以触发 hasLayout (即把元素的 hasLayout 属性设置为 true)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
display: inline-block
height: (除 auto 外任何值)
width: (除 auto 外任何值)
float: (left 或 right)
position: absolute
writing-mode: tb-rl
zoom: (除 normal 外任意值)
min-height: (任意值)
min-width: (任意值)
max-height: (除 none 外任意值)
max-width: (除 none 外任意值)
overflow: (除 visible 外任意值,仅用于块级元素)
overflow-x: (除 visible 外任意值,仅用于块级元素)
overflow-y: (除 visible 外任意值,仅用于块级元素)
position: fixed

对于内联元素(可以是默认被浏览器认为是内联元素的 span 元素,也可以是设置了 display: inline 的元素),width 和 height 只在 IE5.x 下和 IE6 或更新版本的 quirks 模式下能触发元素的 hasLayout ,但是对于 IE6,如果浏览器运行于标准兼容模式下,内联元素会忽略 width 或 height 属性,所以设置 width 或 height 不能在此种情况下令该元素触发 hasLayout 。但 zoom 除了在 IE 5.0 中外,总是能触发 hasLayout 。zoom 用于设置或检索元素的缩放比例,为元素设置 zoom: 1 既可以触发元素的 hasLayout 同时不会对元素造成多余的影响。因此综合考虑浏览器之间的兼容和对元素的影响, 建议使用 zoom: 1 来触发元素的 hasLayout 。

六、能解决的问题

hasLayout表现出来的特性跟BFC很相似,所以可以认为是IE中的BFC。上面的规则几乎都遵循,所以上面的问题在IE里都可以通过触发hasLayout来解决。

虽然 hasLayout 也会像 BFC 那样影响着元素的尺寸和定位,但它却又不是一套完整的标准,并且由于它默认只为某些元素触发,这导致了 IE 下很多前端开发的 bugs ,触发 hasLayout 更大的意义在于解决一些 IE 下的 bugs ,而不是利用它的一些“副作用”来达到某些效果。另外由于触发 hasLayout 的元素会出现一些跟触发 BFC 的元素相似的效果,因此为了统一元素在 IE 与支持 BFC 的浏览器下的表现,Kayo 建议为触发了 BFC 的元素同时触发 hasLayout ,当然还需要考虑实际的情况,也有可能只需触发其中一个就可以达到表现统一,下面会举例介绍。

这里首先列出触发 hasLayout 元素的一些效果:

a、阻止外边距折叠

如上面例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>无标题文档</title>
<style>
html, body { height:100%; }
* { padding:0; margin:0; color:#fff; text-decoration:none; list-style:none; font-family:"微软雅黑" }
.mg {zoom:1}
.rowone { background:#f00; height:100px; margin-bottom:20px; }
.rowtow { background:#090; height:100px; margin-top:20px; }
</style>
</head>
<body>
<div class="mg">
<div class="rowone">
</div>
</div>
<div class="mg">
<div class="rowtow">
</div>
</div>
</body>
</html>

需要触发.mg的layout才能解决margin重叠问题

运行效果如下:

img

上面有关BFC所举的例子,在IE6\7中触发layout都可以解决,可以自己动手试一下,这里就不重复举例了。

十五、对 http 协议了解吗?400、500 这些错误号代表什么意思?

答:

1. HTTP简介

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。

HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。

HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的规范化工作正在进行之中,而且HTTP-NG(Next Generation of HTTP)的建议已经提出。

HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。

http请求-响应模型.jpg

2. 主要特点

1、简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

2、灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。

3.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

4.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
5、支持B/S及C/S模式。

3. HTTP之URL

HTTP使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。URL是一种特殊类型的URI,包含了用于查找某个资源的足够的信息

URL,全称是UniformResourceLocator, 中文叫统一资源定位符,是互联网上用来标识某一处资源的地址。以下面这个URL为例,介绍下普通URL的各部分组成:

http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name

从上面的URL可以看出,一个完整的URL包括以下几部分:
1.协议部分:该URL的协议部分为“http:”,这代表网页使用的是HTTP协议。在Internet中可以使用多种协议,如HTTP,FTP等等本例中使用的是HTTP协议。在”HTTP”后面的“//”为分隔符

2.域名部分:该URL的域名部分为“www.aspxfans.com”。一个URL中,也可以使用IP地址作为域名使用

3.端口部分:跟在域名后面的是端口,域名和端口之间使用“:”作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口

4.虚拟目录部分:从域名后的第一个“/”开始到最后一个“/”为止,是虚拟目录部分。虚拟目录也不是一个URL必须的部分。本例中的虚拟目录是“/news/”

5.文件名部分:从域名后的最后一个“/”开始到“?”为止,是文件名部分,如果没有“?”,则是从域名后的最后一个“/”开始到“#”为止,是文件部分,如果没有“?”和“#”,那么从域名后的最后一个“/”开始到结束,都是文件名部分。本例中的文件名是“index.asp”。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名

6.锚部分:从“#”开始到最后,都是锚部分。本例中的锚部分是“name”。锚部分也不是一个URL必须的部分

7.参数部分:从“?”开始到“#”为止之间的部分为参数部分,又称搜索部分、查询部分。本例中的参数部分为“boardID=5&ID=24618&page=1”。参数可以允许有多个参数,参数与参数之间用“&”作为分隔符。

(原文:http://blog.csdn.net/ergouge/article/details/8185219

4. URI和URL的区别

URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。

Web上可用的每种资源如HTML文档、图像、视频片段、程序等都是一个来URI来定位的
URI一般由三部组成:
①访问资源的命名机制
②存放资源的主机名
③资源自身的名称,由路径表示,着重强调于资源。

URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。

URL是Internet上用来描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上,特别是著名的Mosaic。
采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。URL一般由三部组成:
①协议(或称为服务方式)
②存有该资源的主机IP地址(有时也包括端口号)
③主机资源的具体地址。如目录和文件名等

URN,uniform resource name,统一资源命名,是通过名字来标识资源,比如mailto:java-net@java.sun.com。

URI是以一种抽象的,高层次概念定义统一资源标识,而URL和URN则是具体的资源标识的方式。URL和URN都是一种URI。笼统地说,每个 URL 都是 URI,但不一定每个 URI 都是 URL。这是因为 URI 还包括一个子类,即统一资源名称 (URN),它命名资源但不指定如何定位资源。上面的 mailto、news 和 isbn URI 都是 URN 的示例。

在Java的URI中,一个URI实例可以代表绝对的,也可以是相对的,只要它符合URI的语法规则。而URL类则不仅符合语义,还包含了定位该资源的信息,因此它不能是相对的。
在Java类库中,URI类不包含任何访问资源的方法,它唯一的作用就是解析。
相反的是,URL类可以打开一个到达资源的流。

5. HTTP之请求消息Request

客户端发送一个HTTP请求到服务器的请求消息包括以下格式:

请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。

Http请求消息结构.png

  • 请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本。
Get请求例子,使用Charles抓取的request:
1
2
3
4
5
6
7
GET /562f25980001b1b106000338.jpg HTTP/1.1
Host img.mukewang.com
User-Agent Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36
Accept image/webp,image/*,*/*;q=0.8
Referer http://www.imooc.com/
Accept-Encoding gzip, deflate, sdch
Accept-Language zh-CN,zh;q=0.8
第一部分:请求行,用来说明请求类型,要访问的资源以及所使用的HTTP版本.

GET说明请求类型为GET,[/562f25980001b1b106000338.jpg]为要访问的资源,该行的最后一部分说明使用的是HTTP1.1版本。

第二部分:请求头部,紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息

从第二行起为请求头部,HOST将指出请求的目的地.User-Agent,服务器端和客户端脚本都能访问它,它是浏览器类型检测逻辑的重要基础.该信息由你的浏览器来定义,并且在每个请求中自动发送等等

第三部分:空行,请求头部后面的空行是必须的

即使第四部分的请求数据为空,也必须有空行。

第四部分:请求数据也叫主体,可以添加任意的其他数据。

这个例子的请求数据为空。

POST请求例子,使用Charles抓取的request:
1
2
3
4
5
6
7
8
POST / HTTP1.1
Host:www.wrox.com
User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type:application/x-www-form-urlencoded
Content-Length:40
Connection: Keep-Alive
name=Professional%20Ajax&publisher=Wiley

第一部分:请求行,第一行明了是post请求,以及http1.1版本。
第二部分:请求头部,第二行至第六行。
第三部分:空行,第七行的空行。
第四部分:请求数据,第八行。

6. HTTP之响应消息Response

一般情况下,服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息。

HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

http响应消息格式.jpg

例子

1
2
3
4
5
6
7
8
9
10
HTTP/1.1 200 OK
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8
<html>
<head></head>
<body>
<!--body goes here-->
</body>
</html>
第一部分:状态行,由HTTP协议版本号, 状态码, 状态消息 三部分组成。

第一行为状态行,(HTTP/1.1)表明HTTP版本为1.1版本,状态码为200,状态消息为(ok)

第二部分:消息报头,用来说明客户端要使用的一些附加信息

第二行和第三行为消息报头,
Date:生成响应的日期和时间;Content-Type:指定了MIME类型的HTML(text/html),编码类型是UTF-8

第三部分:空行,消息报头后面的空行是必须的
第四部分:响应正文,服务器返回给客户端的文本信息。

空行后面的html部分为响应正文。

7. HTTP之状态码

状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:

1xx:指示信息–表示请求已接收,继续处理
2xx:成功–表示请求已被成功接收、理解、接受
3xx:重定向–要完成请求必须进行更进一步的操作
4xx:客户端错误–请求有语法错误或请求无法实现
5xx:服务器端错误–服务器未能实现合法的请求

常见状态码:

1
2
3
4
5
6
7
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

更多状态码http://www.runoob.com/http/http-status-codes.html

8. HTTP请求方法

根据HTTP标准,HTTP请求可以使用多种请求方法。
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

1
2
3
4
5
6
7
8
GET 请求指定的页面信息,并返回实体主体。
HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE 请求服务器删除指定的页面。
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS 允许客户端查看服务器的性能。
TRACE 回显服务器收到的请求,主要用于测试或诊断。

9. HTTP工作原理

HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。

以下是 HTTP 请求/响应的步骤:

1、客户端连接到Web服务器

一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,http://www.oakcms.cn。

2、发送HTTP请求

通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。

3、服务器接受请求并返回HTTP响应

Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。

4、释放连接TCP连接

若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;

5、客户端浏览器解析HTML内容

客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。

例如:在浏览器地址栏键入URL,按下回车之后会经历以下流程:

1、浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;

2、解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;

3、浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;

4、服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;

5、释放 TCP连接;

6、浏览器将该 html 文本并显示内容;   

10. GET和POST请求的区别

GET请求
1
2
3
4
5
GET /books/?sex=man&name=Professional HTTP/1.1
Host: www.wrox.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Connection: Keep-Alive

注意最后一行是空行

POST请求
1
2
3
4
5
6
7
8
9
POST / HTTP/1.1
Host: www.wrox.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive
name=Professional%20Ajax&publisher=Wiley

1、GET提交,请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,多个参数用&连接;例 如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0 %E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如: %E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。

POST提交:把提交的数据放置在是HTTP包的包体中。上文示例中红色字体标明的就是实际的传输数据

因此,GET提交的数据会在地址栏中显示出来,而POST提交,地址栏不会改变

2、传输数据的大小:首先声明:HTTP协议没有对传输的数据大小进行限制,HTTP协议规范也没有对URL长度进行限制。

而在实际开发中存在的限制主要有:

GET:特定浏览器和服务器对URL长度有限制,例如 IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系 统的支持。

因此对于GET提交时,传输数据就会受到URL长度的 限制。

POST:由于不是通过URL传值,理论上数据不受 限。但实际各个WEB服务器会规定对post提交数据大小进行限制,Apache、IIS6都有各自的配置。

3、安全性

POST的安全性要比GET的安全性高。比如:通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存;(2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了,除此之外,使用GET提交数据还可能会造成Cross-site request forgery攻击

4、Http get,post,soap协议都是在http上运行的

(1)get:请求参数是作为一个key/value对的序列(查询字符串)附加到URL上的
查询字符串的长度受到web浏览器和web服务器的限制(如IE最多支持2048个字符),不适合传输大型数据集同时,它很不安全

(2)post:请求参数是在http标题的一个不同部分(名为entity body)传输的,这一部分用来传输表单信息,因此必须将Content-type设置为:application/x-www-form- urlencoded。post设计用来支持web窗体上的用户字段,其参数也是作为key/value对传输。
但是:它不支持复杂数据类型,因为post没有定义传输数据结构的语义和规则。

(3)soap:是http post的一个专用版本,遵循一种特殊的xml消息格式
Content-type设置为: text/xml 任何数据都可以xml化。

Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST, PUT, DELETE就对应着对这个资源的查,改,增,删4个操作。 我们最常见的就是GET和POST了。GET一般用于获取/查询资源信息,而POST一般用于更新资源信息.

我们看看GET和POST的区别

  1. GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的Body中.
  2. GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
  3. GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值。
  4. GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码.

十六、你在项目中碰到什么问题?怎么解决的?

答:自己根据自己的经验回答即可。

十七、为什么利用多个域名来存储网站资源会更有效?

答:

​ 除了节约cookie带宽的因素,另一个重要因素是节约主域名的连接数,从而提高客户端网络带宽的利用率,优化页面响应。因为老的浏览器(IE6是典型),针对同一个域名只允许同时保持两个HTTP连接。将图片等资源请求分配到其他域名上,避免了大图片之类的并不一定重要的内容阻塞住主域名上其他后续资源的连接(比如ajax请求)。

三个最主流的原因:

  1. CDN缓存更方便
  2. 突破浏览器并发限制 (你随便挑一个 G家的 url: https://lh4.googleusercontent.com/-si4dh2myPWk/T81YkSi__AI/AAAAAAAAQ5o/LlwbBRpp58Q/w497-h373/IMG_20120603_163233.jpg, 把前面的 lh4换成 lh3,lh6啥的,都照样能够访问,像地图之类的需要大量并发下载图片的站点,这个非常重要。)
  3. Cookieless, 节省带宽,尤其是上行带宽 一般比下行要慢。。。

还有另外两个非常规原因:

  1. 对于UGC的内容和主站隔离,防止不必要的安全问题( 上传js窃取主站cookie之类的) 。

正是这个原因要求用户内容的域名必须不是自己主站的子域名,而是一个完全独立的第三方域名。

  1. 数据做了划分,甚至切到了不同的物理集群,通过子域名来分流比较省事. ^_^ 这个可能被用的不多。

PS: 关于Cookie的问题,带宽是次要的,安全隔离才是主要的。
关于多域名,也不是越多越好,虽然服务器端可以做泛解释,浏览器做dns解释也是耗时间的,而且太多域名,如果要走 https的话,还有要多买证书和部署的问题.

十八、浅析圣杯布局和双飞翼布局

答:

​ 三列布局是一种很常见的页面布局方式,三列一般分别是子列sub、主列main和附加列extra,其中子列一般是居左的导航,且宽度固定;主列是居中的主要内容,宽度自适应;附加列一般是广告等额外信息,居右且宽度固定。
圣杯布局和双飞翼布局都可以实现这种三列布局,他们有什么特别之处呢?

​ 在分析圣杯布局和双飞翼布局之前,抛砖引玉,先看看我之前是如何实现左右定宽、中间自适应的三列布局的:子列和附加列分别浮动到左边和右边,主列设置左右外边距即可,需要注意的是子列和附加列要写在主列的前面,顺序不能变。

1
2
3
<div class="sub">子列</div>
<div class="extra">附加列</div>
<div class="main">主列</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.sub {
float: left;
width: 200px;
height: 300px;
background-color: rgba(255, 0, 0, .5);
}
.extra {
float: right;
width: 180px;
height: 300px;
background-color: rgba(0, 255, 0, .5);
}
.main {
height: 300px;
margin-left: 210px;
margin-right: 190px;
background-color: rgba(0, 0, 255, .5);
}

一、圣杯布局

圣杯布局源自 Matthew Levine 在06年的一篇文章,其DOM结构如下:

1
2
3
4
5
<div class="container">
<div class="main"></div>
<div class="sub"></div>
<div class="extra"></div>
</div>

接下来,让我们一步一步地实现圣杯布局;

1、 首先分别浮动main、sub、extra三列, 然后利用负外边距把sub列和extra列定位到左右两边。这时的CSS代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.main {
float: left;
width: 100%;
height: 300px;
background-color: rgba(255, 0, 0, .5);
}
.sub {
float: left;
width: 200px;
height: 300px;
margin-left: -100%;
background-color: rgba(0, 255, 0, .5);
}
.extra {
float: left;
width: 180px;
height: 300px;
margin-left: -180px;
background-color: rgba(0, 0, 255, .5);
}

2、 完成上步后,sub和extra列已经到了正确的位置,但是sub和extra列却覆盖了main的两边,对于这个问题,圣杯布局的解决办法是给容器container添加左、右内边距,从而让main列定位到正确的位置。

1
2
3
4
.container {
padding-left: 210px;
padding-right: 190px;
}

3、 完成第二步后又出现了新问题:sub、extra列也受到容器左右内边距的影响位置发生了移动。为了解决这个问题,圣杯布局使用相对定位使sub、extra列回到正确的位置。新添加代码如下:

1
2
3
4
5
6
7
8
.sub {
position: relative;
left: -210px;
}
.extra {
position: relative;
right: -190px;
}

4、 当浏览器缩小到一定程度时,这个布局可能会被破坏,可以在body上添加min-width属性解决。最终的圣杯布局CSS代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
body {
min-width: 600px; /* 2*sub + extra */
}
.container {
padding-left: 210px;
padding-right: 190px;
}
.main {
float: left;
width: 100%;
height: 300px;
background-color: rgba(255, 0, 0, .5);
}
.sub {
position: relative;
left: -210px;
float: left;
width: 200px;
height: 300px;
margin-left: -100%;
background-color: rgba(0, 255, 0, .5);
}
.extra {
position: relative;
right: -190px;
float: left;
width: 180px;
height: 300px;
margin-left: -180px;
background-color: rgba(0, 0, 255, .5);
}

点击查看在线demo

圣杯布局的优点总结如下:

  1. 使主要内容列先加载。
  2. 允许任何列是最高的。
  3. 没有额外的div。
  4. 需要的hack很少。

二、双飞翼布局

​ 了解了圣杯布局,趁热打铁,再分析一下双飞翼布局是怎么回事。双飞翼布局源自淘宝UED,现在查看下淘宝店铺的DOM结构,就能找到双飞翼布局的身影。接下来,让我们也一步一步实现双飞翼布局。

  1. 首先,和圣杯布局一样,分别浮动main、sub和extra列,然后利用负外边距正确定位sub和extra列。
  2. 这时依旧面临和圣杯布局同样的问题:main列没有正确定位且被sub、extra列覆盖。双飞翼布局的解决办法是在main列外面包裹了一个宽度100%的div,然后通过设置main列的左、右外边距正确定位main列。最终的DOM结构如下:<div class="main-wrapper"> <div class="main"></div></div><div class="sub"></div><div class="extra"></div>

CSS设置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.main-wrapper {
float: left;
width: 100%;
}
.main {
height: 300px;
margin-left: 210px;
margin-right: 190px;
background-color: rgba(255, 0, 0, .5);
}
.sub {
float: left;
width: 200px;
height: 300px;
margin-left: -100%;
background-color: rgba(0, 255, 0, .5);
}
.extra {
float: left;
width: 180px;
height: 300px;
margin-left: -180px;
background-color: rgba(0, 0, 255, .5);
}

点击查看在线demo

双飞翼布局非常灵活,通过调整css代码可以实现各种布局。例如,利用双飞翼布局实现了一套栅格布局系统

双飞翼布局的优点:

  1. DOM按照主、子、附加列的顺序加载,实现了重要内容先加载。
  2. main部分是自适应宽度的,很容易在定宽布局和流体布局中切换。
  3. 在浏览器上的兼容性非常好,IE5.5以上都支持。
  4. 实现了内容与布局的分离,即Eric提到的Any-Order Columns.
  5. 任何一栏都可以是最高栏,不会出问题。
  6. 需要的hack非常少。

三、圣杯布局与双飞翼布局的比较

总结一下两种布局方式在实现上的异同点:

  1. 俩种布局方式都是把主列放在文档流最前面,使主列优先加载。
  2. 两种布局方式在实现上也有相同之处,都是让三列浮动,然后通过负外边距形成三列布局。
  3. 两种布局方式的不同之处在于如何处理中间主列的位置:圣杯布局是利用父容器的左、右内边距定位;双飞翼布局是把主列嵌套在div后利用主列的左、右外边距定位。

两者相比较,双飞翼布局虽然多了一个div,却减少了相对定位属性的代码,个人认为双飞翼布局在实现思路和代码简洁度上都要比圣杯布局更好一些。

十九、什么是同源策略?

答:

同源策略,它是由Netscape提出的一个著名的安全策略,现在所有的可支持javascript的浏览器都会使用这个策略。最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"**三个相同**"。
  1. 协议相同

  2. 域名相同

  3. 端口号相同

    例如:http://www.yztcedu.com/index.html

    协议: http

    域名:www.yztcedu.com

    端口号:80(省略的时候默认是80)

    http://www.yztcedu.com/another.html 同源

    https://www.yztcedu.com/a.html 不同源 因为协议不同

    http://www.yztc.com/a.html 不同源 因为域名不同

    http://www.yztcedu.com:8080/a.html 不同源 因为端口号不同。

    要想同源,三个必须完全相同。


前端部分笔试题

1、常用浏览器的内核分别是什么?

答案解析:
IE: trident内核
Firefox:gecko内核
Safari:webkit内核
Opera:以前是presto内核,Opera现已改用Google Chrome的Blink内核
Chrome:Blink(基于webkit,Google与Opera Software共同开发)

2、每个HTML文件里开头都有个很重要的东西,Doctype,知道这是干什么的吗?

我的答案:
告知浏览器文档使用哪种HTML或者XHTML规范,该标签可什么3种DTD类型,严格版本、过渡版本和基于框架的。(重点:告诉浏览器按照何种规范解析页面)

3、div+css的布局较table布局有什么优点?

答案解析:
•改版的时候更方便 只要改css文件。
•页面加载速度更快、结构化清晰、页面显示简洁。
•表现与结构相分离。
•易于优化(seo)搜索引擎更友好,排名更容易靠前。

4、为什么利用多个域名来存储网站资源会更有效?

答案解析:
•CDN缓存更方便
•突破浏览器并发限制
•节约cookie带宽
•节约主域名的连接数,优化页面响应速度
•防止不必要的安全问题

5、请描述一下cookies,sessionStorage和localStorage的区别?

答案解析:
数据传递不同:cookies是在浏览器和服务器之间来回传递的,而sessionStorage和localSorage是不会把数据传给服务器的,仅在本地保存。
存储数据大小不同:cookie存储数据大小不能超过4k,而sessionStorage和localSorage存储数据大小可以达到5M。
有效期不同:sessionStorage仅在窗口关闭前有效,localSorage始终有效,cookie在有效期之前有效。
作用域不同:localSorage和cookie在同源窗口中是共享的,即使是不同的浏览器,而sessionStorage不是。

文章目录
  1. 1. 一、Ajax 和 JSONP 哪个可以跨域?原理是什么? JSONP 有什么问题?
    1. 1.1. 1. JSONP 原理:
    2. 1.2. 2. JSONP 局限性:
    3. 1.3. 3. JSON 和 JSONP 的区别:
    4. 1.4. 4. JSON 的优点:
    5. 1.5. 5. JSON 的格式或者叫规则:
    6. 1.6. 6. JSONP 的产生:
  2. 2. 二、谈谈你对语义化的理解?
    1. 2.1. 1.什么是语义化
    2. 2.2. 2.为什么要语义化
  3. 3. 三、网页制作的图片格式有哪些?
    1. 3.1. 1.位图图像
      1. 3.1.1. 位图图像属性
    2. 3.2. 常见位图图像格式
      1. 3.2.1. (1)BMP格式
      2. 3.2.2. (2)JPEG格式
      3. 3.2.3. (3)GIF格式
      4. 3.2.4. (4)PNG格式
      5. 3.2.5. (5)WebP格式
    3. 3.3. 2.矢量图
    4. 3.4. 常用矢量图格式
      1. 3.4.1. (1)BW格式
      2. 3.4.2. (2)AI格式
      3. 3.4.3. (3)CDR格式
      4. 3.4.4. (4)ICO格式
      5. 3.4.5. (5)SVG格式
    5. 3.5. 3.位图与矢量图的区别
    6. 3.6. WEB网页设计中对于图片格式其它一些技巧总结
  4. 4. 四、写出至少 3 种做水平和垂直居中的方法?
    1. 4.1. 1. 文本的水平垂直居中
    2. 4.2. 2. 利用盒模型的水平垂直居中
    3. 4.3. 3. absolute布局上下文下的水平垂直居中
    4. 4.4. 4. float布局上下文下的水平垂直居中
    5. 4.5. 5. BFC布局上下文下的水平垂直居中
    6. 4.6. 6. IFC布局上下文下的水平垂直居中
    7. 4.7. 7. FFC布局上下文下的水平垂直居中
    8. 4.8. 8. table布局上下文下的水平垂直居中
    9. 4.9. 9. CSS grid布局上下文下的水平垂直居中
    10. 4.10. 10. 其它未知归属的水平垂直居中方法
  5. 5. 五、CSS 常见的 hack 方法有哪些?
    1. 5.1. 1. 什么是CSS hack
    2. 5.2. 2. CSS hack的原理
    3. 5.3. 3. CSS hack分类
    4. 5.4. (1)CSS hack方式一:条件注释法
    5. 5.5. (2)CSS hack方式二:类内属性前缀法
    6. 5.6. (3)CSS hack方式三:选择器前缀法
    7. 5.7. 4. CSS3选择器结合JavaScript的Hack
    8. 5.8. 5. CSS hack利弊
  6. 6. 六、对设计模式了解吗?请实现一个单例模式。
    1. 6.1. 1. 设计模式
    2. 6.2. 2. 单例模式
      1. 6.2.1. 其它实现方式
  7. 7. 七、JS 延迟加载的方式有哪些?
  8. 8. 八、document.write 和 innerHTML 的区别?
  9. 9. 九、如何阻止事件冒泡和默认事件?
    1. 9.1. 1. 取消默认操作
    2. 9.2. 2. 阻止冒泡
  10. 10. 十、如何添加、删除、替换、插入某个节点?举例说明 call 和 apply 的区别?
    1. 10.1. 1. 添加、删除、替换、插入某个节点
    2. 10.2. 2. call 和 apply 的区别
    3. 10.3. 作用
  11. 11. 十一、transition、animation、transform 的区别?
  12. 12. 十二、请描述一下重绘和回流是怎么回事?
    1. 12.1. 一、概念
      1. 12.1.1. 首先我们要明白的是,页面的显示过程分为以下几个阶段:
    2. 12.2. 二、什么会引起回流
    3. 12.3. 三、减少回流
  13. 13. 十三、移动端和 PC 端性能优化有哪些方法?
    1. 13.1. (一)移动端性能优化
      1. 13.1.1. 移动H5前端性能优化指南
      2. 13.1.2. [加载优化]
      3. 13.1.3. [脚本执行优化]
      4. 13.1.4. [CSS优化]
      5. 13.1.5. [JavaScript执行优化]
      6. 13.1.6. [渲染优化]
    2. 13.2. (二) PC 端性能优化
      1. 13.2.1. 一、页面优化的常用工具
      2. 13.2.2. 网站慢的因素很多
      3. 13.2.3. 二、网站优化
        1. 13.2.3.1. 1、页面优化
        2. 13.2.3.2. 2、服务器端优化
        3. 13.2.3.3. 3、主观优化
        4. 13.2.3.4. ①减少http请求次数
        5. 13.2.3.5. ②减少交互通信量
        6. 13.2.3.6. ③合理并行加载资源
        7. 13.2.3.7. ④减少消耗
      4. 13.2.4. 三、对于pc端的性能优化的其他说法
  14. 14. 十四、对 BFC 了解吗?
    1. 14.1. 一、BFC是什么?
    2. 14.2. 二、如何产生BFC:当一个HTML元素满足下面条件的任何一点,都可以产生Block Formatting Context:
    3. 14.3. 三、BFC能用来做什么?
    4. 14.4. 四、什么是IE的haslayout
    5. 14.5. 五、怎样触发layout
    6. 14.6. 六、能解决的问题
  15. 15. 十五、对 http 协议了解吗?400、500 这些错误号代表什么意思?
    1. 15.1. 1. HTTP简介
    2. 15.2. 2. 主要特点
    3. 15.3. 3. HTTP之URL
      1. 15.3.1. http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name
    4. 15.4. 4. URI和URL的区别
      1. 15.4.0.1. URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。
      2. 15.4.0.2. URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。
      3. 15.4.0.3. URN,uniform resource name,统一资源命名,是通过名字来标识资源,比如mailto:java-net@java.sun.com。
  16. 15.5. 5. HTTP之请求消息Request
    1. 15.5.0.1. 请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。
    2. 15.5.0.2. Get请求例子,使用Charles抓取的request:
    3. 15.5.0.3. 第一部分:请求行,用来说明请求类型,要访问的资源以及所使用的HTTP版本.
    4. 15.5.0.4. 第二部分:请求头部,紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息
    5. 15.5.0.5. 第三部分:空行,请求头部后面的空行是必须的
    6. 15.5.0.6. 第四部分:请求数据也叫主体,可以添加任意的其他数据。
    7. 15.5.0.7. POST请求例子,使用Charles抓取的request:
  • 15.6. 6. HTTP之响应消息Response
    1. 15.6.0.1. HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
    2. 15.6.0.2. 第一部分:状态行,由HTTP协议版本号, 状态码, 状态消息 三部分组成。
    3. 15.6.0.3. 第二部分:消息报头,用来说明客户端要使用的一些附加信息
    4. 15.6.0.4. 第三部分:空行,消息报头后面的空行是必须的
    5. 15.6.0.5. 第四部分:响应正文,服务器返回给客户端的文本信息。
  • 15.7. 7. HTTP之状态码
    1. 15.7.0.0.1. 1xx:指示信息–表示请求已接收,继续处理
    2. 15.7.0.0.2. 2xx:成功–表示请求已被成功接收、理解、接受
    3. 15.7.0.0.3. 3xx:重定向–要完成请求必须进行更进一步的操作
    4. 15.7.0.0.4. 4xx:客户端错误–请求有语法错误或请求无法实现
    5. 15.7.0.0.5. 5xx:服务器端错误–服务器未能实现合法的请求
  • 15.8. 8. HTTP请求方法
  • 15.9. 9. HTTP工作原理
    1. 15.9.0.0.1. 1、客户端连接到Web服务器
    2. 15.9.0.0.2. 2、发送HTTP请求
    3. 15.9.0.0.3. 3、服务器接受请求并返回HTTP响应
    4. 15.9.0.0.4. 4、释放连接TCP连接
    5. 15.9.0.0.5. 5、客户端浏览器解析HTML内容
  • 15.10. 10. GET和POST请求的区别
    1. 15.10.0.0.1. GET请求
    2. 15.10.0.0.2. POST请求
    3. 15.10.0.0.3. 因此,GET提交的数据会在地址栏中显示出来,而POST提交,地址栏不会改变
  • 16. 十六、你在项目中碰到什么问题?怎么解决的?
  • 17. 十七、为什么利用多个域名来存储网站资源会更有效?
  • 18. 十八、浅析圣杯布局和双飞翼布局
    1. 18.1. 一、圣杯布局
    2. 18.2. 二、双飞翼布局
    3. 18.3. 三、圣杯布局与双飞翼布局的比较
  • 19. 十九、什么是同源策略?
  • 前端部分笔试题
    1. 0.1. 1、常用浏览器的内核分别是什么?
    2. 0.2. 2、每个HTML文件里开头都有个很重要的东西,Doctype,知道这是干什么的吗?
    3. 0.3. 3、div+css的布局较table布局有什么优点?
    4. 0.4. 4、为什么利用多个域名来存储网站资源会更有效?
    5. 0.5. 5、请描述一下cookies,sessionStorage和localStorage的区别?
  • |