推特 HTML 网页的前 10 行代码(译)
在过去的几周时间里,我一直在为我所就职的公司 Pibio 雇佣一名全栈工程师。由于我们公司是远程办公,因此所有的面试都是远程沟通。在这个过程中,我发现,很多面试人员尽管很擅长工作,但却不能很好的实时编码。因此,在大约一个小时的技术讨论中,我选择问他们一些关于网络生命周期、可访问性、不同浏览器的差异化或其它与网络有关的问题。我最喜欢问的一个问题是:“能向我解释一下推特 HTML 网页的前 10 行代码是什么意思吗?”
在我看来,这能够充分展示面试者的前端基础。接下来,我会给出这个问题的答案。
在对话中,我会共享我的屏幕,打开推特的网页,点击查看源代码。然后,请他们逐行进行解释,怎样解释,完全取决于面试者。在过程中,我会故意将文本放大,一方面,是为了使文本更加清晰,另一方面,就只能看到其中一部分的内容,但能够从中获得有效的信息。它大概是这样的:
你必须明白,当下的背景是技术讨论,因此,我并不期望任何人给出完美的答案,只要我能听到一些正确的关键词,我就能明白候选人是知道这个概念的,此时,我就会引导他表述更多的,我想听到的,正确的内容。
第一行: <!DOCTYPE html>
第一行关于 DOCTYPE 声明的代码实在太适合在面试中讨论了,因为,对声明的了解程度可以间接说明面试者的工作经验。我至今仍然记得在 Dreamweaver 的那些日子,必须使用 XHTML 长长的声明,就像克里斯在 2009 年一篇名为《通用声明定义》的文章中所写的那样。
完美的回答:我们通常会把这个文档类型的声明写在 HTML 文件的第一行。你可以认为这些信息是多余的,因为浏览器已经知道响应的 MIME 类型是 text/html 的,但在网景浏览器的时代,浏览器有一项艰巨的任务是选择使用哪个版本的 HTML 标准来解析并进行页面渲染。
最讨厌的是,不同版本的 HTML 标准会生成不同的页面布局,因此,使用这个标签是为了便于浏览器区分版本。曾经,浏览器的标签很长,甚至会包括规范的链接,有点儿像今天的 SVG。幸运的是,现在,简单的 <!DOCTYPE html>在 HTML5 中已经被标准化。
勉强可以接受的回答:这是 DOCTYPE 标签,告诉浏览器,这是一个 HTML5 的页面,应该按照相应的标准解析和渲染。
第二行:<html dir=”ltr” lang=”en”>
这一行可以让我知道候选人是否了解文件的可访问性和本地化。令人惊讶的是,很少有人知道 dir 属性的作用和意义(但这个属性对于阅读器而言却是至关重要的),但几乎每一个人都能清楚的表述 lang=”en” 的意思,即使他们之前从来没有用过这个属性。
完美的回答:这是 HTML 文档的根组件,整个 HTML 文档都会被嵌入到其中。它有两个属性,分别是“方向”和“语言”。“方向”属性的可选参数有 ltr(left-to-right)、 rtl(right-to-left)和 auto(automatic),分别表示用户代理程序会以怎样的方向展示内容。比如,阿拉伯语等语言就需要设置值为 rtl。如果你设置值为 auto,意味着你将选择权交给了浏览器。
“语言”属性的值为 “en”标签意味着告诉我们这个文档的内容都是英文的。你还可以将这个值设置为任何语言的标签,甚至可以区分是美式英语 ,还是国标英语。对于屏幕阅读器而言,“语言”属性的值是非常重要的。
第三行:<meta charset=”utf-8”>
完美的回答:源码中的 meta 标签用于表示文档支持的元数据类型。字符集(charset:character set 的缩写)属性告诉浏览器使用哪种字符编码,这里,推特使用标准的 UTF-8 编码。UTF-8 对字符的支持非常好,你可以在源代码中使用各种符号和表情符号。将此标记放在代码的前几行是非常重要的,这样浏览器就知道尽早知道以怎样的方式解释代码。为了防止做不必要的无用功,一般的规则是把这行代码放在源代码的前一千个字节中,但我觉得,最好把它放在<head>的前面。
顺便说一句,由于性能问题(减少代码量),推特似乎省略了<head>标签,但在我看来,<head>是应该被显示定义的,因为这样你就可以清楚的知道元数据、样式等信息。
第四行:<meta name=”viewport” content=”width=device-...”>
完美的回答:源码中这个的 meta 标签表示用合适的尺寸展示网页,即使是在像智能手机这样的小尺寸设备上。如果你还记得 iPhone 当初的文本演示,史蒂夫乔布斯在一个 4.5 英寸的小屏幕上展示了《纽约时报》网站的全部内容,你可以用手指拖动去阅读,当时,这是一个非常了不起的功能。
现在网站的设计完全是响应式的,宽度为设备宽度(width-device)指告知浏览器用 100% 的设备宽度作为视口,因此没有水平方向的滚动,你甚至可以用宽度的百分比作为标尺。标准的最佳实践是将初始比例设置为 1,将宽度设置为设备宽度,这样人们就可以根据需要进行缩放。
屏幕截图里虽然没有显示这些值,但最好知道:推特还应用了 user-scalable=0
,顾名思义,它禁用了缩放功能,这对访问不便,但会使网页更像是原生应用程度。出于同样的原因,它还设置了 maximum-scale=1
,这个属性还可以设置最小的缩放比例。一般来说,设置全宽和初始比例就足够了。
第五行: ****<meta property="og:site_name" content="Twitt...****
大约有百分之五十的候选人知道 og(Open Graph)标签,能够回答好这个问题的人一定对 SEO(搜索引擎优化)有一定的了解。
完美的回答:推特源码中 meta 的 og 标签表示这个网址支持这个特殊的协议(用了Meta Property=og标签,就是你同意了网页内容可以被其他社会化网站引用等,目前这种协议被SNS网站如Fackbook、renren采用。SNS已经成为网络上的一大热门应用,优质的内容通过分享在好友间迅速传播。为了提高站外内容的传播效率,2010年F8会议上Facebook公布 了一套开放内容协议(Open Graph Protocol),任何网页只要遵守该协议,SNS就能从页面上提取最有效的信息并呈现给用户。)。这个协议最初是由 Facebook 指定的,以便更轻松的对网页中的信息提取并预览,开发人员可以添加各种的信息或者封面图对其进行装饰。事实上,现在更常见的是使用 Puppeteer 之类的工具自动生成。(CSS-Tricks 用了一个 WordPress 插件来做这件事)。
另一个有趣的旁注是 site name 属性,但这是 OG 非标准的属性。我猜想这只有在 Facebook 中起作用?标题、链接、描述性的 Open Graph 标签似乎显得有些多余,因为我们已经有了响应的标签,但人们往往会为了安全而添加它们。如今,很多网站都会使用 Open Graph 属性和其它标签来为页面生成丰富的预览。
第六行****: <meta name="apple-mobile-web-app-title" cont...****
大多数候选人都不知道这一点,但有经验的开发者会针对如何优化苹果设备上的网站进行讨论,如点击苹果图标和 Safari 浏览器固定导航栏。
完美的回答:你可以将网站固定在 iPhone 的主屏幕上,使其像一个原生应用程序。Safari 浏览器不支持渐进式的 Web 应用程序,而且你也不能在 iOS 设备上使用其他浏览器的这个功能,因此,如果你想要那种原生的体验,就只能选择像推特这样。添加这个标签来告诉 Safari 浏览器这个应用的标题是推特。下一行的意思和这一行很类似,告诉控制台应用程序启动时的外观状态栏。
第八行****: <meta name="theme-color" content="#ffffff"...****
完美的回答:这是 Web 里的标准属性,等价于苹果的状态栏,目的是为了告诉浏览器,为 UI 设置什么样的主题。Android 上的 Chrome 和桌面端的 Brave 对这个属性的支持都很好,你可以在内容里填写任意的 CSS 颜色值,设置可以使用 Media 属性来对特定的设备设置特殊色,例如,支持深色主题。你还可以在 Web 应用清单上定义此属性和其它属性。
第九行 ****<meta http-equiv="origin-trial" content="...****
我所面试的候选人都不知道这个属性。我认为,只有你对新的标准有很深的了解才会知道这一点。
完美的回答:Origin 试用版让我们可以在我们的网站上使用新的试验性的功能,用户代理程序会跟踪用户行为,并将反馈报告给制定标准的 Web 社区,这个报告无需用户授权。例如,Edge 浏览器对双屏可折叠设备进行了实验,这个体验非常酷,因为你可以根据可折叠手机的打开状态来制作有趣的布局。
同样可以接受的回答:我对此一无所知。
第十行****: html{-ms-text-size-adjust:100%;-webkit-text...****
几乎没有人知道这个属性,除非你对 CSS 的一些不常用属性和优化非常了解。
完美的回答:假设你没有采用响应式布局,但你依然希望小屏幕能够展示内容,因此,浏览器必须能够调整文本的大小,使其在小屏幕中以更大的字体进行展示,便于阅读。CSS 中的 text-size-adjust
属性可以设置 none
,来关闭这个功能,也可以制定浏览器按照百分比对文本进行放大。
在现在的例子中,推特设置了最大值为 100%,因此文本不会变大变小,他们这样做,因为他们的网站已经做了响应式布局,并且他们不想冒险让浏览器使用更大的字体,从而破坏布局。这同样适用于 HTML 标签中的所有内容。由于这是一个实验性质的 CSS 属性,因为需要提供一个前缀来标明。此外,在这个 CSS 标签之前少了一个 <style>
标签,我猜是它在上一行中被缩进了。
可以接受的回答:这个属性的具体值,我并不清楚,但是其中的 -ms 和 -webkit- 分别是 IE 浏览器和基于 Webkit 内核的浏览器的前缀,用于非标准的属性。当 CSS3 出现时,我们曾要求使用这些前缀,但随着属性从实验到问题或被完全采用,这些前缀消失了,取而代之的是标准化的属性。
福利— 第是一行:body{margin:0;}
推特源代码中的这一行非常有趣,因为你可以清楚的知道格式化与网页展示之间的区别。
完美的回答:因为不同浏览器具有不同的默认样式,这里希望通过重置来进行统一,以便网站在不同设备上表现一致。在这个例子里,推特告诉浏览器,删除 body 标签的默认边距。但我更喜欢规范化样式而不是完全删除它们,即浏览器应用相同的默认值而不是完全删除它们。人们曾经使用 *{margin: 0} ,但这完全是矫枉过正,对性能没有任何好处,但好在现在有了类似 nomaliza.css 、reset.css 或者其它更新更好的。
更多内容
我总是喜欢用浏览器查看工具来查看网站是如何制作的,这就是我想出这个办法的原因。尽管我认为自己是 HTML 语义方面的专家,但每次这么做,我都会有新的收获。
由于推特主要是一个客户端的 React 应用程序,只有几十行源码,但即便如此,还是有很多东西可以学。推特源代码中还有一些有趣的行,读者们可以亲自去查看,看看自己能解释几个?
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Twitter">
告诉浏览器可以将推特添加为搜索引擎。
<link rel="preload" as="script" crossorigin="anonymous" href="<https://abs.twimg.com/responsive-web/client-web/polyfills.cad508b5.js>" nonce="MGUyZTIyN2ItMDM1ZC00MzE5LWE2YmMtYTU5NTg2MDU0OTM1" />
有许多可以讨论的有趣属性,尤其是 nonce。
<link rel="alternate" hreflang="x-default" href="<https://twitter.com/>" />
用于国际区登录页面。
:focus:not([data-focusvisible-polyfill]){outline: none;}
用于在不使用键盘导航栏时,移除聚焦的轮廓线。
## 原文