本文会通过以下六个方面进行讲解,我们是怎么对腾讯文档进行无障碍化改造的。
无障碍概念
用户障碍类型
辅助工具如何识别网站
普通网站如何支持无障碍
腾讯文档支持无障碍遇到的问题和解决方案
对文档进行无障碍改造后的一些个人总结与建议
接下来,首先让我们先了解一下什么是无障碍。
无障碍化,Accessibility(A11Y)是指无论健全人还是残疾人,年轻人还是老年人都可以从我们所开发的网站上获取信息和服务,让互联网访问公平变得可能。
建设无障碍化网站是一项非常有意义且正确的事情,不单单是可以增加网站的受益群众,更是一个有情怀、有担当的开发者应该关注的方面,甚至在一些国家与地区支持无障碍化已经写入法律规定中。
在 W3C 上有一句话——"Web 根本目的是为了为所有的人服务,而不是受限于的硬件、软件、语言、文化、位置或身体或精神能力"(原文:The Web is fundamentally designed to work for all people, whatever their hardware, software, language, location, or ability..)
那么,即使只有部分浏览障碍的用户,我们在开发中也需要将他们的使用考虑到,可我们日常需要考虑的障碍类型有哪些呢?
根据 W3C 所著Web 内容无障碍指南(WCAG)中提到的,主要的障碍类型有一下四类:
类型 | 介绍 |
---|---|
视力障碍 | 指视力下降到一定程度,可能无法通过常规手段(眼镜)解决,主要包括盲人、低视力、色盲、色弱等用户。 |
认知障碍 | 是一种范围广泛的残疾类型,从能力最有限的智障人士到我们随着年龄增长和思考和记忆困难而出现的所有人。 主要包括患有精神疾病用户、癫痫病用户、因网站布局不一致引起的不良反应用户、学习障碍用户、阅读障碍用户、注意力缺陷用户、多动障碍用户等。 |
行动障碍 | 指无法使用他/她的肢体,或缺乏行走、抓取或抬起物体的力量。 |
听力障碍 | 指听觉部分或完全丧失,可能会使用 ATs,但在 Web 中并没有专门 ATs 可以使用 |
上述四种障碍类型中,视力障碍和认知障碍已有成熟的辅助软件或者开发守则,帮助我们解决或降低这些用户对网站使用困难问题。我们需要做到的是,在开发中遵守这些守则,根据 WCAG 尽最大的能力去完善网站支持这些辅助软件的使用。
视力障碍用户,会通过辅助工具来了解并使用网站。常见的辅助工具有放大镜,屏幕缩放以及屏幕阅读器。其中较为常用的屏幕阅读器有:
付费的产品:JAWS (Windows) 和 Dolphin Screen Reader (Windows)。
免费的产品:NVDA (Windows),ChromeVox (Chrome, Windows and Mac OS X)和 Orca (Linux)。
内置的产品:VoiceOver (macOS, iPadOS, iOS),Narrator (Microsoft Windows,ChromeVox (on Chrome OS)和 TalkBack (Android).
认知障碍用户,会因为我们遵守开发守则,而更容易使用网站。在MDN上有为认知障碍者总结的开发守则:
用多种方式展示内容,例如通过文本,语音或视频;
编写易于理解的内容,例如少用方言或者颜文字;
重要的内容要细心写;
尽量减少干扰,例如一些没什么用的功能与广告;
网页布局与导航要一致;
常规的元素样式,例如带下划线的链接(未访问时为蓝色)和访问时为紫色;
流程交互要具有进度以及步骤指示;
用户权限认证方式要简单;
错误信息要展示清楚;
表单要便于填写与操作
这个答案相当于我们需要知道辅助工具软件是如何对网站进行识别?大部分的网站为什么不能被辅助软件识别?我们可以通过这两个问题去知晓大部分网站不能自动支持无障碍化的原因。
当浏览器在渲染的时候构建 DOM 树,并根据 DOM 树上每个节点元素的语义,转换为 Accessibility Tree(无障碍树)。而,辅助工具识别的内容,就是这个无障碍树,按照 DOM 节点的顺序,而非视觉顺序从上往下依次进行读屏。无障碍树,我们可以通过打开控制台的 Elements -> Accessibility 中查看到:
浏览器可以将 DOM 树转变成无障碍树,是因为 DOM 树上大部分内容具有隐式语义含义。也就是说,采用的原生 HTML 元素能够被辅助软件识别,并且可以预测其在各类平台上的工作方式。因此,链接或按钮等原生 HTML 元素的无障碍功能可自动得到处理,被辅助软件识别。
但,随着网络应用变得越来越复杂和动态。现在,我们采用的元素虽然看上去像原生元素,实际却并非如此,如下图的按钮:
此“按钮”的实现方式多种多样,下面是其中一种方法:
<div class="button-fack">click button</div>
此“按钮”我们肉眼可见确实是一个按钮。但, <div>
- The Content Division element(内容的分割元素),是作为一个“纯”容器,该元素不代表任何东西。所以, div
虽然有含义,但没语义,辅助工具是无法对其识别。而且,其还无法通过键盘对焦,只能通过鼠标点击对焦。
也就是因为这种有含义无语义的元素,替换原生的 HTML 元素实现它们的功能,造成这些网站无法被辅助工具自动识别。
那么,我们应该如何去改造已有的网站,使其支持无障碍化?
根据 W3C 所著Web 内容无障碍指南(WCAG)与可访问的富 Internet 应用程序(WAI-ARIA),对 DOM 树上元素的语义(元素角色、状态与属性)、焦点进行补充完善,从而达到对网站的无障碍化改造。
Web 内容可访问性指南(WCAG)是由互联网的主要国际标准组织万维网联盟(W3C)的 Web 可访问性倡议(WAI)发布的一系列 Web 可访问性指南的一部分。
它们是一组使 Web 内容更易于访问的建议,主要针对残疾人,但也适用于所有用户代理,包括高度受限的设备,如移动电话。WCAG2.0,于 2008 年 12 月发布,并于 2012 年 10 月成为国际标准化组织标准,ISO/IEC 40500:2012。WCAG 2.1 于 2018 年 6 月成为 W3C 推荐标准。
WCAG 主要有如下四大原则:
原则 | 介绍 |
---|---|
可感知性 | 信息和用户界面组件必须以可感知的方式呈现给用户。例如:所有的非文本、时基媒体都要提供替代文本,因为并不是所有用户都可通过视觉感知内容,我们不能仅提供一种感知方式让所有用户都可以感知到网站内容。 |
可操作性 | 用户界面组件和导航必须可操作。所有功能都能够通过键盘进行操作,并提供帮助用户导航、查找内容定位的方法。 |
可理解性 | 信息和用户界面操作必须是可理解的。网站的信息应可读、可理解,让所有用户的理解保持一致性。 |
鲁棒性 | 内容必须健壮到可信的地被种类繁多的用户代理(包括辅助技术)所解释。最大化兼容当前和未来的用户代理。 |
WAI-ARIA(可访问的富 Internet 应用程序套件)是由万维网联盟(W3C)发布的一项关于 A11Y 技术应用规范。该规范定义了一种使残障人士更易于访问 Web 内容和 Web 应用程序的方法,增加 HTML,JavaScript 和相关技术开发的网站动态内容以及用户界面组件的可访问性。
WAI-ARIA 主要就是针对于上述的障碍类型以及 WCAG 要求的技术细则,它定义了一组附加的 HTML 属性,可将这些属性应用于元素以提供附加的语义并在缺少的地方,从而改变并完善 Accessibility Tree。运用好这些属性、技术细则,那么浏览障碍人士便能轻松访问我们的应用。在 WAI-ARIA 规范中,定义了三个主要功能与特征:角色、状态与属性:
角色,是指通过在元素上设置 role 属性方式确定元素具体角色,其作用是用于定义元素是什么或做什么。且,在WAI-ARIA Role中有详细介绍每个角色与其对应的属性是如何协作,以及如何以浏览器和辅助技术支持的方式使用它们。
如上图,role 可选属性值有点多,但其实主要就分了四类:
抽象角色
小部件角色
文件结构角色
地标角色
其主要作用为:
角色信息描述。
相关角色的等级信息。
角色上下文。
引用其他规范中的相关概念。
使用 OWL(Web Ontology Language)提供允许语义继承的类型层次结构。
每个角色支持的状态和属性。
举一个例子,进行角色改造:
以上述的“ click button ”按钮为例,该功能应为按钮,但由于使用 div 导致其无语义。对其改造,应添加角色为 button,使其被对焦时,辅助软件可以识别出这是一个按钮。
// 角色改造前,对焦时无法得知其语义
<div class="button-fack">click button</div>
// 角色改造后,对焦时辅助工具感知其为按钮
<div role="button" class="button-fack">click button</div>
WAI-ARIA 提供了可访问性状态和属性的集合,这些状态和属性用于支持各种操作系统平台上的平台可访问性 API,使我们可以对任何页面元素对无障碍树进行细微(乃至彻底的)修改。辅助技术可以通过公共的用户代理应用(例如读屏软件)DOM 或通过映射到平台可访问性 API 来访问这些信息。
当状态、属性、角色结合时,用户代理应用可以为辅助技术提供用户界面信息,以便随时传递给用户。状态或属性的更改将导致向辅助技术发出通知,这可能会警告用户发生了更改。WAI-ARIA 将状态与属性分为以下四类:
类型 | 属性 |
---|---|
小部件属性 | aria-checked (state) 、aria-disabled (state) 、 aria-expanded (state) 、 aria-haspopup 、aria-hidden (state) 、aria-invalid (state) 、aria-label 、aria-level 、aria-multiline 、aria-multiselectable 、aria-orientation 、aria-pressed (state) 、aria-readonly 、aria-required 、aria-selected (state) 、 aria-sort 、aria-valuemax 、aria-valuemin 、 aria-valuenow 、aria-valuetext |
实时区域属性 | aria-atomic、aria-busy (state) 、aria-live 、aria-relevant |
拖放属性 | aria-dropeffect 、 aria-grabbed(state) |
关系属性 | aria-activedescendant、aria-controls 、aria-describedby 、aria-flowto 、aria-labelledby 、 aria-owns 、aria-posinset 、 aria-setsize |
对于上述属性中,找几个常用的属性并举一个例子,让大家来了解一下它们的神奇之处:
<div id="image"/>
// css代码:
#image {
width: 200px;
height: 150px;
background: url(https://docs.idqqimg.com/tim/docs/desktop/image/list_logo-230232562f.svg);
background-size: contain;
background-repeat: no-repeat;
}
按照上述写法,当图片对焦时,辅助软件会识别出什么? --> “组”。因为 div 元素有含义无语义,只是一个单纯的内容分割元素,所以,它被识别为“组”。
那我们应该怎么改造让辅助软件识别的内容和我们肉眼看到的一致?
1、需要给此 div 元素赋予角色 role,告诉辅助软件这个是一个图片;
2、需要对图片添加图片内容说明,告诉辅助软件这个是一个什么图片。此时,我们需要用到 aria-label 属性。
aria-label 属性是用来解释当前元素的内容,但,不可在也有说明(如 alt、tiltle 等)的情况下添加,会造成冲突。辅助软件会将所有说明串接在一起,将会造成重复性对当前节点说明。
改造后的代码如下所示:
<div id="image" role="img" tabIndex="" aria-label="腾讯文档log"/>
效果如下图所示:
辅助工具会识别其为“腾讯文档 log 图像”。实际上如果我们用 html 原生元素 img ,只需要添加 alt 属性,即可。
<img src="https://docs.idqqimg.com/tim/docs/desktop/image/list_logo-230232562f.svg" alt="腾讯文档log" tabIndex="1" width="200px" height="150px" />
(若想继续看常用的角色与状态属性结合使用例子,可以直接拉到下面“腾讯文档支持无障碍”)
通过上述内容,相比大家已经对 WAI-ARIA 已经有了大致了解,它只能对无障碍树进行修改,补充元素语义,不能添加元素可对焦能力。所以,我们还需要额外的开发 DOM 树的焦点控制、导航能力。
WAI-ARIA 解决了元素无含义问题,焦点管理就是来解决 WCAG 的可操作性问题。通过焦点管理,让所有交互都是可聚焦,可通过键盘进行操作。
从上述内容中,可知:
辅助工具是依靠无障碍树对网站进行识别,而无障碍树是在 DOM 树基础上结合语义含义生成的。
辅助工具对网站内容识别的顺序,是按照 DOM 树的结构从上到下依次进行对焦识别,而非网站页面显示视觉顺序。
所以,网站的 DOM 顺序非常重要!但,我们的网站现在已经开发完毕,为了支持无障碍化能力,去改变已有的 dom 节点顺序,消耗人力、时间都很大,所以,直接从根源上解决识别顺序问题是不可能的,只能在以后的开发中尽量按照视觉效果在 DOM 树上对应位置添加 dom 节点。那么,我们就有以下三个问题:
如何让辅助工具按照页面显示顺序进行识别?
如何让辅助工具对一些 DOM 节点(网站装饰节点)不进行对焦识别?
如何让一些元素进行对焦呢?
使用 tabIndex 进行焦点管理
tabIndex 顾名思义就是指通过 按 tab 键,对元素进行对焦的顺序。
tabIndex 的值可以分为以下 3 类:
tabIndex value | 作用 |
---|---|
-1 | 使当前元素不可以被 tab 按键对焦,但是通过鼠标是可以进行点击对焦的,也可以通过 focus() 方法进行对焦。 |
0 | 按照 DOM 树的顺序进行对焦。 |
1~32767 | 对焦顺序高于 0。在 1 ~ 32767 范围内,对焦优先级从 1 开始依次递减。如果,设置了 0、1、2、3,那么识别的顺序是 1->2->3->0。 |
⚠️ 上述的情况下,当出现多个 tabIndex 值为一致时,将按 DOM 树的顺序依次对焦。
我在进行使用时,对上述[-1, 32767]以外的范围充满了好奇,因此进行了一些实验发现:
如果,我设置 tabIndex=-2,和-1 一样的效果无法通过 tab 按键进行对焦。如果,我设置 tabIndex=32768,超过最大值,浏览器不识别,但是如果继续往上增大 tabIndex=123456,则会发生和-1 的一样效果无法通过 tab 键盘对焦。所以,建议大家还是老老实实的写[-1, 32767],以防浏览器识别错误。
通过上述的解释,并不是很清楚具体的表现,那么我们来举一个例子,来实践一下 tabIndex 控制焦点:
<a href="https://docs.qq.com/desktop" tabindex="-1" title="无法被tab对焦"> tabIndex="-1" </a>
<a href="https://docs.qq.com/desktop" title="链接1"> tabIndex="0" </a>
<a href="https://docs.qq.com/desktop" tabIndex="1" title="链接2"> tabIndex="1" </a>
<a href="https://docs.qq.com/desktop" tabIndex="3" title="链接3"> tabIndex="3" </a>
<div tabIndex="2" id="divTabIndexTest">
红色的是一个div 且 tabIndex="2"
<br />
<a href="https://docs.qq.com/desktop" tabIndex="0" title="链接4"> tabIndex="0" </a>
<br />
<a href="https://docs.qq.com/desktop" tabIndex="1" title="链接5"> tabIndex="1" </a>
<br />
<a href="https://docs.qq.com/desktop" tabIndex="2" title="链接6"> tabIndex="2" </a>
</div>
<a tabIndex="2" href="https://docs.qq.com/desktop" title="链接7"> tabIndex="2" </a>
结果如下图所示:
先将所有的 tabIndex="1"的元素,按照 DOM 树的顺序依次对焦后,再去对焦 2、3 最后对焦 0 。-1 的元素无法使用 tab 键进行对焦。
文档通过改造后支持无障碍化能力,下面是改造后整体流程图:
具体实现步骤如下:
进入文档,判断是否开启无障碍开关;
未开启无障碍开关,用户操作文档正常响应,直到关闭文档结束,或开启无障碍开关进行下面步骤;
开启无障碍开关,用户操作正常响应,同时做内容区域与非内容区域支持辅助工具(读屏软件)识别用户操作结果的特殊处理;
用户操作在内容区域,对用户操作事件进行类型划分,同时按照流程上的内容变动、产生选区、光标移动的优先级,进行内容获取。再传递给读屏软件进行用户操作结果朗读;
用户对非内容区域操作,读屏软件直接根据对焦的节点的语义和注解进行用户操作朗读;
重复上述 3-5 步骤,直到关闭无障碍开关或退出文档结束。
大家是不是通过上述流程发现了文档支持无障碍的不一样点?文档对内容区域进行了单独处理。
因为,通过上述的 “怎么改造网站支持无障碍化?”那节的技术对文档进行改造时,发现了一些文档内容区域的特殊之处——各个品类的内容区域要么是用 canvas 实现,要么是采用繁多的 dom 节点实现。这些实现提升了文档的性能,但对支持无障碍化改造带来了问题:
对于 canvas 实现内容区域:辅助软件识别 canvas 为一张画布,无法识别具体内容。那么用户在 canvas 上操作后,辅助软件如何识别 canvas 上的响应结果呢?
对于普通 dom 节点实现的内容区域:dom 节点繁多,交互复杂,不好控制,若仅仅依靠修改节点属性进行控制,工作量大,兼容性不高,对后期发展并不友好。那么如何找一个工作量小、兼容性高、对后期发展友好的控制繁多 dom 节点的方法呢?
【答案】:我们发现两个问题的答案一致——对内容区域的交互进行统一处理,过滤划分用户操作结果,再通过一定的方法将结果存到某个节点,让辅助工具(读屏软件)识别。
对内容区域进行统一处理,这个统一监听用户操作事件即可,但是怎么控制读屏软件朗读呢?我们分为以下三步:
首先,我们需要解决如何让一个节点发生变化,读屏软件就能立即对其内容进行读屏?设置 aria-live 属性,其属性值与作用如下:
属性值 | 作用 |
---|---|
off | 关闭。当节点内容发生变化时,读屏软件不会识别读取。 |
polite | 等用户空闲时播报。读屏软件朗读的内容读完后,才会读当前 dom 元素的内容。 |
assertive | 随时播报。当前未读屏,直接读;若当前读屏软件正在朗读,直接打断读当前 dom 元素的内容。 |
然后,要解决如何让读屏软件完整的朗读变动的 dom 节点内容呢?设置 aira-atomic 属性,该属性值 true/ false 是控制朗读 dom 节点全部内容,还是只朗读发生变动的内容。
最后,这个存储用户操作结果的节点放到哪里呢?放到一个用户看不到的隐藏 dom 节点里,一个专门为读屏软件而创建的隐藏 dom 节点。详细代码如下所示:
具体解决方案(以用户对内容进行选区操作为例)如下图所示:
上图具体步骤如下所示:
用户对内容区域进行操作;
判断用户操作结果,抛出用户操作(accessibility)事件;
监听 accessibility 事件,获取用户操作结果;
将用户操作结果作为 a11yContentChange 事件参数抛出;
Accesibility 组件监听到 a11yContentChange 事件后,将隐藏 dom 节点内容替换为事件传递参数;
读屏软件监听到隐藏 dom 节点内容变动,朗读节点内容。
上述是让读屏软件读出用户的操作结果,但是用户内容区域进行操作时,可能会识别到背景水印、底纹等,显示在内容区域但是不想让用户在内容区域操作时知道的功能,那如何解决这个问题呢?我们需要对这些节点进行屏蔽。
对节点进行屏蔽,我们需要考虑屏蔽的是什么?是无法通过键盘对焦?还是让非交互内容从可读性树上移除?
例如上述说的对文档内容区域的水印、底纹等非交互性内容进行朗读屏蔽,即将其可访问性树上移除。我们在其节点上,添加 aria-hidden 属性,设为 true 从而控制其与子元素从可访问性树上移除,让读屏软件无法对其识别朗读。
但,对于像 iframe 这种外部插件,可交互内容,我们需要通过对 iframe 先屏蔽键盘对焦操作,设置 tabindex=-1;再对 iframe 内部非交互性元素设置 aria-hidden 属性。
上述的内容支持读屏、屏蔽多余内容都是对内容区域进行改造,下面我们来介绍以下对功能区域的改造。
功能区域就是用户对文档的控制交互部分,里面有涉及到弹出面板、关闭面板、打开下拉菜单、退出下拉菜单、选中、取消选中等等交互操作。想要障碍用户同普通用户一样使用,其实很简单,只需要做到以下四点:
每个交互功能可通过 tab 按键对焦;
可以被读屏软件朗读出该功能的具体作用与操作;
按键控制子功能开关;
功能切换时焦点正常移动;
若交互功能是由 button 等原生 html 交互元素实现的,都可以自动支持对焦,我们无须对其进行二次改造。
但,文档里面很多都不是交互元素实现的。例如按钮,大部分都是通过 svg 元素实现的,不支持对焦。我们需要通过设置 tabindex 强行控制其可以支持 tab 键对焦。
设置每个功能可对焦读屏后,我们需要保证其都能够被读屏软件朗读出,其作用与操作方法。
我们需要每个非原生 html 实现的元素,添加 role 属性,使得其角色正确。设置 aria-label 对每个功能节点添加功能注释,确保障碍用户可以像普通用户一样明白理解该功能。
功能区域有常见的打开面板、打开下来列表等等打开另外一个子功能的操作。例如,当障碍用户错误打开某个面板时,需要对整个面板进行全部对焦后,才能找到关闭按钮关闭面板。若面板内容繁多,那岂不是需要障碍用户听完所有内容后,才能找到关闭按钮,大概半个小时过去了吧......那么,如何让障碍用户快速打开与关闭子功能呢?
我们调研了一下互联网中已经支持无障碍的网站,发现它们通用的是 esc 退出子功能、空格键盘和回撤键打开子功能。所以,我们希望和它们保持统一,避免障碍用户的操作不适应。
我们为什么要对功能实现焦点控制?
首先,我们需要达成共识:普通用户可以看到整个页面概况,但障碍用户只能通过辅助工具(读屏软件)给予的提示得知当前功能。那么,代表着障碍用户只知道当前焦点位置的功能。
其次,我们要知道网站交互功能里面涉及到弹出面板、关闭面板、打开下拉菜单、退出下拉菜单、选中、取消选中等复杂交互操作。
那么结合上述两点,我们得出若障碍用户在打开某个功能时,不进行焦点控制让其焦点可以对焦到网站所有位置,那么会造成障碍用户以为所有可以对焦的内容都是属于该功能!产生严重的歧义!举一个例子让大家感受一下,下图是进入高级设置面板后的读屏操作,橙色方框就是读屏软件读取的内容。
如果我们不对“高级权限设置”面板焦点进行控制,那么就如上图所示,障碍用户跟着焦点获取面板内容,结果焦点整个网站到处跑!请问他们怎么知道哪些是面板的?哪些是非面板内容呢?因此,造成障碍用户和普通用户对功能产生严重歧义!
例如,对目录进行焦点控制:
障碍用户在打开目录功能时,我们需要对当前位置进行记录,然后获取目录数量。
障碍用户对目录进行 tab 键对焦时,我们需要进行条件判断操作前是否为最后一个目录标题,是,则强制 focus()到第一个目录标题;否,则让其按序自然对焦。
若用户对某个目录标题进行确认,则将焦点移到对应位置,同时屏蔽/关闭整个目录防止误触,直到用户通过开启目录开关再将焦点移动到目录。
若用户未选中任何目录标题,按 esc 退出目录功能,那么我们需要将焦点移到打开目录时的位置!
对上文的内容进行总结归纳,希望在以后的开发中大家能够注意:
在 DOM 树上新添加的节点位置,最好与视觉位置一一对应,防止辅助工具识别顺序错误;
开发中尽量遵守认知障碍者在 MDN上总结的开发守则;
对交互功能元素节点,添加功能说明;
面板、弹窗等交互需要在退出功能后,焦点需要回到原本触发位置;
对焦点过于复杂或无法获取具体操作,可通过添加隐藏 dom 节点,设置 aira-live、aira-atomic、aria-hidden 去做统一对用户操作进行处理;
多余节点或不需要障碍用户知道的节点,非交互性节点可以通过 aira-hidden 进行屏蔽,若交互性节点还需要添加 tabIndex=-1 进行按键对焦屏蔽。
当你对网站进行无障碍化改造时,切记不要为了无障碍而强行改动大量代码,造成网站页面变动、网站性能降低、后期难以维护、普通用户使用不适等负面影响。无障碍改造是锦上添花,不是兰芷萧艾!
https://developer.mozilla.org/zh-CN/docs/Web/Accessibility
https://developer.mozilla.org/en-US/docs/Learn/Accessibility/WAI-ARIA_basics
https://juejin.cn/post/6844904017127047182
https://www.zhangxinxu.com/wordpress/2017/05/html-tabindex/
https://developers.google.com/web/fundamentals/accessibility/
关于AlloyTeam
AlloyTeam 是国内影响力最大的前端团队之一,核心成员来自前 WebQQ 前端团队。 AlloyTeam负责过WebQQ、QQ群、兴趣部落、腾讯文档等大型Web项目,积累了许多丰富宝贵的Web开发经验。 这里技术氛围好,领导nice、钱景好,无论你是身经百战的资深工程师,还是即将从学校步入社会的新人,只要你热爱挑战,希望前端技术和我们飞速提高,这里将是最适合你的地方。 加入我们,请将简历发送至 alloyteam@qq.com,或直接在公众号留言~ 期待您的回复😁
最近文章: