一个浏览器工程师实现Web元素的经历

在过去的2个月,我用了很多时间在Gecko中补充了<dialog>标签的支持使其符合大部分的标准,能够在Nightly中默认开启,但还不能在Release中开启,因为当前的实现并不完美。这是我第一次实现Web标准,写下这篇文章来进行一个总结,顺便也可以帮助大家了解到浏览器工程师是如何工作的。

Spec(标准)的理解是第一步也是最重要的一步。浏览器工程师需要大量的时间来阅读Web标准,很多时候还需要跟别的引擎开发团队进行讨论和修改。拿<dialog>标签来举例,我所做的第一件事情,就是阅读跟<dialog>相关的文档,而一项标准往往和别的标准相关联,<dialog>就跟top layer的标准联系很大,所以top layer也是需要被掌握的内容。当<dialog>在进入modal状态下的时候,需要被focus的元素也在标准中明确声明了,因此也需要阅读focus相关的文档。

多个引擎团队同时支持的标准往往更可靠或者更加完美一点。<dialog>是仅仅在blink中实现了的,所以我在为Gecko所做的工作,就像是复查了一遍相关的标准。当然,标准并不是完美的,里面经常有模糊的地方和需要改进的地方。例如,<dialog>centered alignment模式就非常的难以理解且繁琐,与此同时<dialog>的focus逻辑对accessbility的支持并不是很好。以上这些则需要大量的时间来进行讨论,从而选择出大家都同意的解决方法,再放进Web标准中,最后浏览器再跟进进行修改。

很多时候我们需要参考别的浏览器的实现,来维持更好的一致性。<dialog>在Blink中已经有相关的实现了,所以我在做Gecko的实现的时候,对于模糊的和不确定的选择,也会参考blink中的实现。例如在实现‘支持用escape键关掉modal dialog’的时候,我并不是很确定如果modal dialog 和一个全屏元素同时出现的话,应该先关掉哪个。并且这些是没有在标准中明确提出的,因此我参考了Blink的行为,从而做了相同的行为在Gecko中。还有的时候,blink的行为与标准并不相符。这个时候我会去请教blink的工程师,从而了解这是bug还是blink有意做出的改变。

Web标准大体上就是这样,简单来说就是个理解和修改的过程,下一步就是把标准中的要求放在浏览器中实现。

大部分Web元素的实现,主要跟两个模块打交道,Layout和DOM。Layout主要负责元素在页面中样式的实现,DOM主要负责的就是元素逻辑方面的实现。如果这个元素可以被CSS所解释,那实际上主要做的就是DOM逻辑上的实现,因为几行CSS就可以把元素放到正确的位置上了。

但很不幸的是,dialog并不能被CSS所解释,而要实现标准中的要求,则需要在Layout模块中加入一些hack。一开始我们以为只需要少量的hack就可以解决排版方面的要求,但后来发现需要的hack越来越多,我们也就越来越头疼,就又开始重新思考modal dialog的排版。最后我们决定先实现一个临时的与标准不同但更合理的方案,然后再尝试把这个方案放入标准里面。因此有些时候,引擎开发团队会根据自身的情况选择不同的方案,然后再与别的引擎团队进行讨论,这也是大家共同合作统一的标准,从而使Web更好的发展。

相比较Layout方面,DOM方面需要做的修改则直接很多,主要就是<dialog>的行为代码,如focus行为、returnValue返回正确的值和支持用escape关掉dialog之类的。

相对于标准的理解来说,实际上需要编写的代码要简单许多。

最后一步就是确认你所写的代码是否正确。Web的标准是拥有大量的测试实例的,都在一个叫web-platform-test (WPT)的仓库中。这些测试是引擎开发商共同来维护的。例如我们要求能放入WPT的测试,最好都放入到WPT中。因为这样可以同时测试别的引擎的行为,从而维护一致性,达到共益。Gecko中有一个WPT的copy,每天都会加入最新的修改,然后我们在Gecko的WPT做出的修改,也会自动放入主WPT仓库中。因为有blink早已加入的现成测试实例可以用,所以我这次做<dialog>就方便许多。当然,我也发现了现有实例的bug,所以有时候修改也是不可避免的。

以上就是一个Web元素是如何在浏览器中实现的过程。