Jerry的反省:程序员不要轻易说出"这个功能技术上无法实现"
这是Jerry 2020年的第81篇文章,也是汪子熙公众号总共第263篇原创文章。
Jerry之前的文章 从医院到家,再重返SAP成都研究院,Jerry还没死 提到,我手术后重返SAP成都研究院,加入了Global的Spartacus开发团队,开始从事SAP Commerce Cloud新一代Storefront的开发工作。文章 SAP Spartacus简介,对SAP Spartacus做了一个概要介绍。
本文给大家分享Jerry上周处理一个Spartacus issue的经历。
本来Jerry也自诩是一位SAP全栈开发工程师——我能熟练使用SAP UI5,SAP Fiori Elements,SAP WebClient UI,SAP ABAP Webdynpro进行全栈开发,并且深入了解这些工具/框架的底层工作原理。
不过,当最近处理Spartacus的Accessibility issue时,我还是觉得自己的前端知识远远不够用。
满足Accessibility(可访问性)的应用,即应用以“所有人”为核心(包括某些残疾人),能在更广阔的场景下毫无障碍地被使用。
互联网的力量存在于它的普适性中,让包括残疾人在内的所有人都能访问互联网, 是普适性中必不可少的一部分。
The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect.
Tim Berners-Lee
Inventor of the World Wide Web
Accessibility也是SAP Product Standard(产品标准)之一,在SAP产品从设计到开发,测试,直至最后发布的整个流程中,确保产品对Accessibility的良好支持,是每位SAP开发人员致力的目标之一。
Accessibility听起来有点抽象?SAP产品为了满足Accessibility,到底需要做什么具体的开发工作?的确,Accessibility是一个比较笼统的范畴,比如Jerry目前工作的Spartacus Accessibility, 落实到编程层面的实现,总共分为下图几类(Accessibility缩写为a11y). 而我上周手头上处理的一个issue, 是关于键盘的可访问性支持(Keyboard Accessibility). 简单来说,就是用户能用鼠标操作Spartacus完成的功能,用键盘也必须同样能完成。
“移动-点击”的鼠标交互模式对于普通用户来说,是最为简便高效的网页定位方式。然而对于视觉存在障碍的用户来说,用肉眼定位鼠标箭头的位置, 不是一件容易的事情。而对于某些存在肢体障碍的用户来说,使用鼠标甚至都是一件非常困难的事情(这一点Jerry刚刚被推出手术室后的头七天简直深有体会)。
对这些由于某种原因无法使用鼠标来访问浏览器应用的特殊用户来说,如何将鼠标的“移动-点击”的交互模式转换成其他更易操作的步骤呢?
我们利用键盘的tab键,按次序遍历页面上的元素。
通过这种方式,将原本用鼠标选择页面元素的方式,切换成了用键盘Tab键来代替。
当按下Tab键遍历到某个元素时,该元素获得焦点(focus), 触发onfocus事件。Jerry处理的issue, 如下图所示,问题症状就是Spartacus Organization Unit List这个列表的行项目,获得焦点时的轮廓线(outline)显示不尽如人意,视觉效果需要改进。
列表行项目第一列的实现,是一个自定义复合控件(Composite Control, SAP UI5也有类似概念,叫做Reusable Control), 由一个a标签和一个button标签构成,其中a标签通过自定义管道cxUrl在页面渲染时动态生成一个url, 指向该行项目对应的Organization Unit明细页面。当a标签持有focus时,鼠标点击或者回车键按下之后,跳转到Org Unit明细页面。
Button标签结合自定义的cx-icon标签一起,二者共同实现一个三角箭头。点击后,会展开和收拢该Org Unit的子Unit列表。
Issue描述的问题
当行项目复合控件内的a标签被tab键focus之后,因为a标签的css设置,它本身会显示被focus的轮廓线效果。同时,a标签的父节点,tr标签设置了伪类focus-within, 其效果是,一旦tr有任意子节点得到focus, tr本身也会得到focus.
如此一来,a标签得到focus时,列表行项目就会同时出现两套轮廓线,一套是标签a focus之后显示的outline , 另一套是标签tr的focus outline.
由于这个列表行项目一些另外的bug, 这两套轮廓线的叠加显示,视觉效果不佳。更糟糕的是,在不同宽度的屏幕下,a标签自身的focus轮廓线还会有差异:只有当窄屏时,才能显示完整的上下左右四条轮廓线。
我刚刚加入团队时,团队的开发经理给我分配了一位开发大佬,负责解答我开发过程中遇到的技术问题。据开发经理介绍,这位大佬是Spartacus的元老级人物,从Spartacus立项到现在最新的3.0版本一直参与其中。这位大佬第一次和我电话里互相介绍彼此时,给我学习Spartacus的建议大意就是,“遇到问题尽量自己多思考,多想办法,而不是马上就在Slack上
问我,这样你会成长很快”。
这正好和Jerry每当进入一个SAP新的领域时的学习方法一致,我也没觉得什么不妥。
所以当我打算先把我correction的思路和大佬讨论时,大佬直接回复我一波三连击:
我期望的行为是XXX
make it happen
show me the PR
我当时看到大佬提出的需求,第一反应就是: 1 border when highlighting the row这个需求,技术上无法实现啊! 我当时的想法是,伪类focus-within不就是通过被修饰元素的子节点接收到focus, 从而达到自身也被focus的效果吗?这意味着Org Unit List行项目内,只要有任意一个元素被focus, 整个行项目必定有两套focus轮廓线出现,而不是大佬要求的一套。所以,大佬这个需求技术上无法实现啊。
于是,我向大佬表达了我的看法:我认为这个需求技术上无法实现。
大佬没有理我。
后来我把这个issue涉及到的一些知识点罗列了一下,通过google和stackoverflow逐一进行了学习:
scss的工作原理
scss里%和&的用法
scss里@minxin的用法
scss里@include, @extend的用法
pseudo class :focus和:focus-within的区别
tabindex的使用方法
onfocus和onblur的关联
css specificity的含义和calculation rule
a标签能接收focus事件的前提条件
页面元素margin, padding和border的区别,各自使用场景
几种css选择器和优先级
学习完这些知识点之后,我立即后悔了,觉得当初不该对大佬说出“这个功能技术上无法实现”这句傻话。事实上,要实现行项目focus时只显示一套focus轮廓线的需求,方法简直太多太多了。
第一次尝试
我把a标签的tabindex设置成-1, 这样a就不会收到focus了。a标签的兄弟节点,button标签收到focus时,其父节点即tr通过:focus-within,也收到focus, 效果如下:
然而,因为a标签的tabindex为-1, 意味着它不能再接收focus事件,所以回车之后无法触发跳转到unit明细页面的操作了,这条路行不通。
第二次尝试
我想通过调整a:focus的outline-offset值,设法让其和tr的focus轮廓线完全重合,这样focus事件发生时,视觉上讲,用户也只会看见一套轮廓线。
然而我观察了现有的tr轮廓线,发现有计算逻辑参与在里面,而a标签并没有。简单评估了一下,如果要让a标签在不同的屏幕尺寸下的轮廓线和tr标签的轮廓线始终保持重合,代价太大,得不偿失,所以我放弃了。
第三次尝试
直接隐藏a标签的focus轮廓线。这样,技术上来说,虽然标签a得到focus时,它会和父标签tr同时被赋予各自的focus轮廓线,但前者的轮廓线被设置成隐藏,因此视觉效果上行项目只有一条轮廓线,这就满足了大佬的需求。
最后行项目得到focus时的轮廓线效果如下:
虽然通过这个issue我学到的css相关知识,在前端开发大佬们眼中不值一提,但这些确实是我以前不了解或者没有理解透彻的,因为以前一直做SAP UI5和SAP WebClient UI的应用层开发,99%的情况下不会直接操作css和scss.
我也非常感谢给我提出需求的开发大佬,在我贸然说出"这个需求技术上无法实现"的时候,没有立即怼我,而是选择了直接无视,这才给我创造了通过google和stackoverflow充实自己的机会。
通过这个issue我的体会就是,程序员在自己尚不完全熟悉的领域工作时,如果没有十足的把握,最好别贸然说出“这个功能技术上无法实现”这种话,否则,后续可能会被打脸。
感谢大家有耐心读完我工作中的发生的这件琐事,希望对大家有一点点启发,感谢阅读。