# 对 web 标准、可用性、可访问性的理解

可用性(Usability):产品是否容易上手,用户能否完成任务,效率如何,以及这过程中用户的主观感受可好,是从用户的角度来看产品的质量。可用性好意味着产品质量高,是企业的核心竞争力 可访问性(Accessibility):Web 内容对于残障用户的可阅读和可理解性 可维护性(Maintainability):一般包含两个层次,一是当系统出现问题时,快速定位并解决问题的成本,成本低则可维护性好。二是代码是否容易被人理解,是否容易修改和增强功能。

# 优雅降级和渐进增强

优雅降级(progressive enhancement):Web 站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会检查以确认它们是否能正常工作。由于 IE 独特的盒模型布局问题,针对不同版本的 IE 的 hack 实践过优雅降级了,为那些无法支持功能的浏览器增加候选方案,使之在旧式浏览器上以某种形式降级体验却不至于完全失效。

渐进增强(graceful degradation):从被所有浏览器支持的基本功能开始,逐步地添加那些只有新式浏览器才支持的功能,向页面增加无害于基础浏览器的额外样式和功能的。当浏览器支持时,它们会自动地呈现出来并发挥作用。

# 域名收敛和域名发散

域名收敛:就是将静态资源放在一个域名下。减少 DNS 解析的开销。 域名发散:是将静态资源放在多个子域名下,就可以多线程下载,提高并行度,使客户端加载静态资源更加迅速。

PC 时代为了突破浏览器的域名并发限制,有了域名发散。浏览器有并发限制,是为了防止 DDOS 攻击。

域名发散是 PC 端为了利用浏览器的多线程并行下载能力。而域名收敛多用与移动端,提高性能,因为 dns 解析是是从后向前迭代解析,如果域名过多性能会下降,增加 DNS 的解析开销。

# 首屏时间和白屏时间

Performance 接口可以获取到当前页面中与性能相关的信息。 该类型的对象可以通过调用只读属性 Window.performance 来获得。 白屏时间:

performance.timing.responseStart - performance.timing.navigationStart;

首屏时间

window.onload = () => {
  new Date() - performance.timing.responseStart;
};

# Flash、Ajax 各自的优缺点,在使用中如何取舍?

Flash:

  1. Flash 适合处理多媒体、矢量图形、访问机器
  2. 对 CSS、处理文本上不足,不容易被搜索

Ajax:

  1. Ajax 对 CSS、文本支持很好,支持搜索
  2. 多媒体、矢量图形、机器访问不足

共同点:

  1. 与服务器的无刷新传递消息
  2. 可以检测用户离线和在线状态
  3. 操作 DOM

# 知道的网页制作会用到的图片格式有哪些?

png-8,png-24,jpeg,gif,svg Webp:谷歌(google)开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有 JPEG 的 2/3,并能节省大量的服务器带宽资源和数据空间。Facebook Ebay 等知名网站已经开始测试并使用 WebP 格式。 Apng:全称是“Animated Portable Network Graphics”, 是 PNG 的位图动画扩展,可以实现 png 格式 的动态图片效果。04 年诞生,但一直得不到各大浏览器厂商的支持,直到日前得到 iOS safari 8 的支持, 有望代替 GIF 成为下一代动态图标准。

# 浏览器问题:浏览器怎么加载页面的?script 脚本阻塞有什么解决方法?defer 和 async 的区别?

ie 的某些兼容性问题(浮动 ie 产生的双倍距离,ie 双边距问题:在 ie6 下,如果对元素设置了浮动,同时又设置了 margin-left 或者 margin-right,margin 值会加倍。在这种情况下 ie 会产生 20px 的距离,解决方案是在 float 的标签样式控制中加入--*display:inline;将其转化为行内属性。*这个符号只有 ie6 会识别。)

# 静态文件的浏览器缓存如何实现?

# 网页禁止出现滚动条

<body scoll="no">
  全禁止
  <body style="overflow:scroll;overflow-y:hidden">
    禁止纵向滚动条
    <body style="overflow:scroll;overflow-x:hidden">
      禁止纵向滚动条
    </body>
  </body>
</body>

# 禁止缩放

<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no" />

# css 为什么有很多 web-kit 之类的前缀

# 实践:

css

  • 避免使用 table 布局
  • 将动画效果应用到 position 属性为 absolute 或 fixed 的元素上

javascript

  • 避免频繁操作样式,可汇总后统一 一次修改
  • 尽量使用 class 进行样式修改
  • 减少 dom 的增删次数,可使用 字符串 或者 documentFragment 一次性插入
  • 极限优化时,修改样式可将其 display: none 后修改
  • 避免多次触发上面提到的那些会触发回流的方法,可以的话尽量用 变量存住

扩展: style 标签写在 body 后与 body 前有什么区别 写在 head 标签中利于浏览器逐步渲染(resources downloading->CSSOM+DOM->RenderTree(composite)->Layout->paint) 写在 body 标签后由于浏览器以逐行方式对 html 文档进行解析,当解析到写在尾部的样式表(外联或写在 style 标签)会导致浏览器停止之前的渲染,等待加载且解析样式表完成之后重新渲染,在 windows 的 IE 下可能会出现 FOUC 现象(即样式失效导致的页面闪烁问题)

# web 开发中会话跟踪的方法有哪些

  1. cookie
  2. session
  3. url 重写
  4. 隐藏 input
  5. ip 地址

# async 和 defer 的作用是什么?有什么区别?

defer 和 async 属性的区别: image 其中蓝色线代表 JavaScript 加载;红色线代表 JavaScript 执行;绿色线代表 HTML 解析 1)情况 1 <scriptsrc="script.js">

没有 defer 或 async,浏览器会立即加载并执行指定的脚本,也就是说不等待后续载入的文档元素,读到就加载并执行。

2)情况 2 <scriptasyncsrc="script.js"> (异步下载)

async 属性表示异步执行引入的 JavaScript,与 defer 的区别在于,如果已经加载好,就会开始执行——无论此刻是 HTML 解析阶段还是 DOMContentLoaded 触发之后。需要注意的是,这种方式加载的 JavaScript 依然会阻塞 load 事件。换句话说,async-script 可能在 DOMContentLoaded 触发之前或之后执行,但一定在 load 触发之前执行。

3)情况 3 <scriptdefersrc="script.js">(延迟执行)

defer 属性表示延迟执行引入的 JavaScript,即这段 JavaScript 加载时 HTML 并未停止解析,这两个过程是并行的。整个 document 解析完毕且 defer-script 也加载完成之后(这两件事情的顺序无关),会执行所有由 defer-script 加载的 JavaScript 代码,然后触发 DOMContentLoaded 事件。

defer 与相比普通 script,有两点区别:载入 JavaScript 文件时不阻塞 HTML 的解析,执行阶段被放到 HTML 标签解析完成之后;在加载多个 JS 脚本的时候,async 是无顺序的加载,而 defer 是有顺序的加载

# 如何实现文件断点续传

断点续传最核心的内容就是把文件“切片”然后再一片一片的传给服务器,但是这看似简单的上传过程却有着无数的坑。

首先是文件的识别,一个文件被分成了若干份之后如何告诉服务器你切了多少块,以及最终服务器应该如何把你上传上去的文件进行合并,这都是要考虑的。

因此在文件开始上传之前,我们和服务器要有一个“握手”的过程,告诉服务器文件信息,然后和服务器约定切片的大小,当和服务器达成共识之后就可以开始后续的文件传输了。

前台要把每一块的文件传给后台,成功之后前端和后端都要标识一下,以便后续的断点。

当文件传输中断之后用户再次选择文件就可以通过标识来判断文件是否已经上传了一部分,如果是的话,那么我们可以接着上次的进度继续传文件,以达到续传的功能。 有了 HTML5 的 File api 之后切割文件比想想的要简单的多的多。

只要用 slice 方法就可以了

var packet = file.slice(start, end);

参数 start 是开始切片的位置,end 是切片结束的位置 单位都是字节。通过控制 start 和 end 就可以是实现文件的分块

file.slice(0, 1000);
file.slice(1000, 2000);
file.slice(2000, 3000);
// ......

在把文件切成片之后,接下来要做的事情就是把这些碎片传到服务器上。 如果中间掉线了,下次再传的时候就得先从服务器获取上一次上传文件的位置,然后以这个位置开始上传接下来的文件内容。

# 如何确定服务端开启了 gzip

# 哪些地方会出现 css 阻塞,哪些地方会出现 js 阻塞?

js 的阻塞特性:所有浏览器在下载 JS 的时候,会阻止一切其他活动,比如其他资源的下载,内容的呈现等等。直到 JS 下载、解析、执行完毕后才开始继续并行下载其他资源并呈现内容。为了提高用户体验,新一代浏览器都支持并行下载 JS,但是 JS 下载仍然会阻塞其它资源的下载(例如.图片,css 文件等)。

由于浏览器为了防止出现 JS 修改 DOM 树,需要重新构建 DOM 树的情况,所以就会阻塞其他的下载和呈现。嵌入 JS 会阻塞所有内容的呈现,而外部 JS 只会阻塞其后内容的显示,2 种方式都会阻塞其后资源的下载。也就是说外部样式不会阻塞外部脚本的加载,但会阻塞外部脚本的执行。

CSS 怎么会阻塞加载了?CSS 本来是可以并行下载的,在什么情况下会出现阻塞加载了(在测试观察中,IE6 下 CSS 都是阻塞加载)当 CSS 后面跟着嵌入的 JS 的时候,该 CSS 就会出现阻塞后面资源下载的情况。而当把嵌入 JS 放到 CSS 前面,就不会出现阻塞的情况了。根本原因:因为浏览器会维持 html 中 css 和 js 的顺序,样式表必须在嵌入的 JS 执行前先加载、解析完。而嵌入的 JS 会阻塞后面的资源加载,所以就会出现上面 CSS 阻塞下载的情况。

嵌入 JS 应该放在什么位置?

  1. 放在底部,虽然放在底部照样会阻塞所有呈现,但不会阻塞资源下载。
  2. 如果嵌入 JS 放在 head 中,请把嵌入 JS 放在 CSS 头部。
  3. 使用 defer(只支持 IE)
  4. 不要在嵌入的 JS 中调用运行时间较长的函数,如果一定要用,可以用 setTimeout 来调用

# 图片 base64 之后利弊

# document load 和 ready 的区别

# window.history 属性描述

# 如何做到修改 url 参数页面不刷新

HTML5 引入了 history.pushState() 和 history.replaceState() 方法,它们分别可以添加和修改历史记录条目。

let stateObj = {
  foo: 'bar',
};

history.pushState(stateObj, 'page 2', 'bar.html');

假设当前页面为 foo.html,执行上述代码后会变为 bar.html,点击浏览器后退,会变为 foo.html,但浏览器并不会刷新。 pushState() 需要三个参数: 一个状态对象, 一个标题 (目前被忽略), 和 (可选的) 一个 URL. 让我们来解释下这三个参数详细内容:

状态对象 — 状态对象 state 是一个 JavaScript 对象,通过 pushState () 创建新的历史记录条目。无论什么时候用户导航到新的状态,popstate 事件就会被触发,且该事件的 state 属性包含该历史记录条目状态对象的副本。状态对象可以是能被序列化的任何东西。原因在于 Firefox 将状态对象保存在用户的磁盘上,以便在用户重启浏览器时使用,我们规定了状态对象在序列化表示后有 640k 的大小限制。如果你给 pushState() 方法传了一个序列化后大于 640k 的状态对象,该方法会抛出异常。如果你需要更大的空间,建议使用 sessionStorage 以及 localStorage. 标题 — Firefox 目前忽略这个参数,但未来可能会用到。传递一个空字符串在这里是安全的,而在将来这是不安全的。二选一的话,你可以为跳转的 state 传递一个短标题。 URL — 该参数定义了新的历史 URL 记录。注意,调用 pushState() 后浏览器并不会立即加载这个 URL,但可能会在稍后某些情况下加载这个 URL,比如在用户重新打开浏览器时。新 URL 不必须为绝对路径。如果新 URL 是相对路径,那么它将被作为相对于当前 URL 处理。新 URL 必须与当前 URL 同源,否则 pushState() 会抛出一个异常。该参数是可选的,缺省为当前 URL。 格式化金钱,每千分位加逗号

function format(str) {
  let s = '';
  let count = 0;
  for (let i = str.length - 1; i >= 0; i--) {
    s = str[i] + s;
    count++;
    if (count % 3 == 0 && i != 0) {
      s = ',' + s;
    }
  }
  return s;
}
function format(str) {
  return str.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
}

# iframe 的优缺点?

  1. <iframe> 优点:

    • 解决加载缓慢的第三方内容如图标和广告等的加载问题
    • Security sandbox
    • 并行加载脚本
  2. <iframe> 的缺点:

    iframe 会阻塞主页面的 Onload 事件:

    • 即时内容为空,加载也需要时间
    • 没有语意