nozzlegear
5 days ago
For anyone who didn't click through to the WebKit bug report the author submitted, a WebKit dev asked him to clarify why the BBC finds it beneficial to be able to detect that the event was sent from a keyboard. This is the author's response:
> Ironically, I want interoperability on this to help with use cases relating to accessibility.
> I work at the BBC and, on our UK website, our navigation bar menu button behaves slightly differently depending on if it is opened with a pointer or keyboard. The click event will always open the menu, but:
> - when opening with a pointer, the focus moves to the menu container.
> - when opening with a keyboard, there is no animation to open the menu and the focus moves to the first link in the menu.
> Often when opening a menu, we don't want a slightly different behaviour around focus and animations depending on if the user 'clicks' with a pointer or keyboard.
> The 'click' event is great when creating user experiences for keyboard users because it is device independent. On keyboards, it is only invoked by Space or Enter key presses. If we were to use the keydown event, we would have to check whether only the the Space or Enter keys were pressed.
amluto
5 days ago
This is fascinating, because the naive English interpretation of the code and the comment on that WebKit bug don't match the actual structure of the code. Here's the relevant code:
const isInvokedByMouse = event => event.screenX > 0 || event.screenY > 0;
const isInvokedByKeyboard = event => isEnterKey(event) || isSpaceKey(event);
Ignoring the actual conditions entirely, this code seems to be trying to categorize the event into one of two categories: mouse or keyboard. But what it actually does is to categorize into one of four categories: (mouse and not keyboard), (keyboard and not mouse), (keyboard and mouse), and (neither keyboard nor mouse). And, as the original bug shows, (neither keyboard nor mouse) is handled inappropriately. One might wonder whether (keyboard and mouse) works well.Either the code should be deliberate about the fact that (is it a keyboard) and (is it a mouse) are separate booleans, or the code should be structured so that the actual categories are mutually exclusive. For example:
const isInvokedByMouse = ...
and use !isInvokedByMouse to check for keyboardiness, or: const eventSource = ... (returns "keyboard" or "mouse")
or, perhaps even better: const eventSource = ... (returns "keyboard", "mouse", or "not sure")
nightpool
5 days ago
This is a great comment ^ whenever you use two booleans like this, you're opening yourself up to "unrepresentable state" logic errors. Finding and noticing this in code can be tricky, but it's a great example of something that should be caught during code review.
politelemon
5 days ago
Not sure if exactly the same thing but reminds me of "Booleans are a trap"
lvturner
5 days ago
Wait—that last state doesn't make sense. With a real door, you can technically turn the key while it's open, but does that meaningfully change its state? Yet our model allows this impossible combination.
Funnily enough, I have a physical door & lock that OFTEN gets in to this state - it's exactly as irritating as it sounds, and it has very meaningful impact on it's state (it then can't be closed without first unlocking the lock!)
pryelluw
4 days ago
I’ve come to the conclusion that most programming problems like this can be solved my having programmers work as building superintendents for 3 months. Practical experience will open their eyes to how the world really works.
lvturner
4 days ago
This leads to another wonderful gap, where programmers are expected to understand the world[0], but the world isn't expected to understand programming[1]
[0] Business, etc
[1] System design, security, database management, cost vs speed trade-offs, SCM, etc etc etc
enugu
4 days ago
This is a good account of a software modelling process. But, this is not specific to booleans. Database constraints involve the same issue. One motivation for encapsulation in software was to preserve constraints in the data (or in other words, disallow improper states). Encapsulation allows only internal functions to manipulate the data, and the developer just needs to checks that these functions are doing it correctly.
Or, as pointed out in the post where multiple booleans are merged into a single enum, encode the constraints into the data itself ie. use the constraints of the host programming language.
But this wont be possible in general - for instance if your language doesn't have sets/dictionaries, how would you encode uniqueness of values directly using arrays and lists? It would have to be done using interface functions.
iwontberude
5 days ago
Yet another article prematurely optimizing. It’s like these people have nothing better to do. I’ll wait for my code to get into stupid edge cases first and then fix it. Even if you spend your time avoiding booleans you will still find yourself with some new contradictory state and have to fix it differently anyways.
lmm
5 days ago
Coming up with proper representation for your state is almost always worth it. If anything it's the opposite of premature optimisation - normalise first, only denormalise after you've proven that it's needed.
amluto
5 days ago
Huh? This isn’t premature optimization unless you consider trying to write correct code “optimizing”.
liontwist
5 days ago
The issue isn’t booleans the issue is that the code doesn’t handle all the states described by the two booleans, when all are possible.
cma
5 days ago
Make the impossible states unrepresentable using an enum of only the possible boolean combinations.
dpig_
4 days ago
Isn't that exactly what the article prescribes?
liontwist
4 days ago
Did you read the context?
cma
4 days ago
No I read wrong and missed it. If all four states are actually possible an enum can still be a win if you have a compiler that can check for exhaustive switch case statements. Or especially if updating a system where it used to be only three were valid and now something changed so that all four are.
robocat
5 days ago
And just to add an extra corner case, Mobile Safari changes the click behavior if an onclick handler is registered - even if the click handler is an empty function that does nothing. The onclick handler itself acts as another Boolean that affects the browser's behavior. I don't remember the exact details because it was a corner case (I think to do with scrolling or popovers or touchcancel - I know it was surprisingly nasty). This page mentions something else http://www.quirksmode.org/blog/archives/2010/09/click_event_... "Fortunately it’s pretty easy to solve: you have to make the element clickable by giving it an onclick event handler of its very own. That handler can be empty; as long as it’s present it will make any element clickable.".
taneq
5 days ago
Well said. I usually go through several phases when dealing with this kind of thing, I start with "flags for different conditions" type logic, then when things get too complex I refine this into "set of explicitly defined states", and then as the state code evolves from 'ideal happy path' to 'production-tested code' I gradually realise that most of the original combinations represented by the original flags actually CAN happen in weird edge-cases.
chii
5 days ago
> "set of explicitly defined states"
this is called algebraic data type (https://en.wikipedia.org/wiki/Algebraic_data_type), and it is the best way, imho, to reduce bugs in code.
By making it easy to pattern match, it reduces the possiblity of producing an invalid state, because at the time of definition, you have to figure out how to get that type (and checked by compiler).
klysm
4 days ago
I frequently use algebraic thinking to verify my sanity with types. Bool times bool is 4. We have two states we want to represent so bool times bool so the wrong thing.
O-stevns
5 days ago
Seems like a non bug to me.
The first mistake the developer made, was that he wanted to create a different user experience between keyboard and mouse. Stick to what you get by default and design your components so they work for both usecases. Don't try to be smart when it comes to accessibility.
What he ended up doing is what I would have considered a hack. A solution that inevitably breaks or has side effects.
The reason there rarely are good handles to do things differently in accessibility context, is because it's not something that's meant to be handled differently.
willwade
5 days ago
See I work in accessibility. Like I provide and create solutions direct to end users with complex needs. Not regular web accessibility. I get the view of this. It’s the same idea of universal access. But actually I don’t fully agree. Yes. If you can stick to this principle - and do try / but I promise you edge cases - which in itself is what accessibility users are all about - cause headaches. At some level you have to do custom stuff. It’s the best way. Take for example switch users. Yes. If your ui is tab able - great. But what if you need your items scannable in frequency order. Your tab index needs to change to meet the end users needs. Or eye gaze users. The accuracy level changes. Add in cognitive issues. You can’t just make a one size fits all interface. At some stage you need to significantly customize it. You can’t rely on a user just learning a complex system level interaction technique- if they can’t do that you have to customise on an individual level.
O-stevns
5 days ago
Of course there are edge cases, I work with accessibility too, for an app in the public sector where WCAG rules are no joke, so I know this as well but even so, we don't build custom accessibility UI for our users. We (try to) build the UI with accessibility in mind so it's scalable, can be used and navigate properly by voice over and keyboard.
On mobile it's not perfect either but in general you do have features to change stuff like. focus, grouping of elements, how the keyboard navigate the view stack, how to access a button through custom actions and like you mention, change the tab index programmatically.
Even so, not everything can be fixed or handled through standard accessibility means and as such hacks will inevitably make it into the products.
I get what you're saying but I still think that making things accessible and designing with common accessibility in mind should be default and as such it has to be thought about when designing and developing from the get go. Having to create custom interfaces to fulfill a specific need might be a good fit for some things but not when developing apps and websites unless you're targeting that user-group specifically.
joshtumath
5 days ago
Well said! It certainly applies to web development as well. Sadly, sometimes more complex solutions are needed - especially when based on user research.
hinkley
5 days ago
Also note, it’s been about 10-15 years since the rules changed and if you want to work on a government contract, accessibility is mandatory.
joshtumath
5 days ago
I am the author.
> The first mistake the developer made, was that he wanted to create a different user experience between keyboard and mouse. Stick to what you get by default and design your components so they work for both usecases.
We have. The behaviour is mostly the same whether you're using the keyboard or a pointer (mouse/touch/pen). The only difference is that, for keyboard users, we want to turn off the animation and move the focus to the first link in the menu instead of focussing on the menu's parent <ul>.
The problem was that, as various devs have iterated on the menu over the years, it's broken the fallback behaviour. For my colleague on the funny multi-monitor set up, it should have fallen back to the keyboard no-animation behaviour with no real major difference to the UX, but instead it fell back to the no-JS experience.
So yes, generally don't try to be smart with accessibility, avoid ARIA attributes except where necessary, etc, but click events are the universal input event and work on any kind of input device and have perfect browser support. It's far better for accessibility using them instead of a mix of keydown and mousedown or pointerdown, and potentially missing other kinds of input events.
As I stated in another comment, if it was a scenario where there needs to be a major difference in behaviour between keyboard and pointers, then I would rather use separate keydown and pointerdown events.
O-stevns
5 days ago
The _mostly_ same behavior is what caused the problem though :P I'm curious, did these solutions come to pass because you had to make adjustments based on actual user feedback or was it just a developer trying to think ahead? I'm questioning whether forcing the user to tab to get to the menu item is a hindrance at all or whether the animation was a problem.
Maybe the former could have been solved using ARIA tags or maybe it would require bigger changes to the component itself. Accessibility is a roller-coaster for all these reasons alone.
abtinf
5 days ago
> we want to turn off the animation and move the focus to the first link in the menu instead of focussing on the menu's parent
Why not just always turn off the animations? Why not just always move the focus to the link?
What is the benefit of the animation to the user? What is the benefit of focusing on the menu’s parent to the user?
One rule of thumb with accessibility is that accessible products are usually better for everyone.
yreg
5 days ago
> What is the benefit of the animation to the user?
Animations enhance experience by drawing attention to state changes and providing intuitive feedback to user actions.
If you don't find them engaging or useful, that's fine - and you can set prefers-reduced-motion to true on your client - , but many people do.
> What is the benefit of focusing on the menu’s parent to the user?
The first item was not interacted with nor navigated to, therefore it shouldn't be focused under normal circumstances. It would be unexpected behavior.
Focusing the first item in keyboard interactions is an accessibility hack recommended by W3C:
deathanatos
4 days ago
> Animations enhance experience by drawing attention to state changes and providing intuitive feedback to user actions.
> If you don't find them engaging or useful, that's fine - and you can set prefers-reduced-motion to true on your client - , but many people do.
The question here is not "does an animation have worth", but how is that worth tied to whether an onclick event originated from the mouse or the keyboard? Your reasoning applies equally to both, and thus leaves us still confused: why are we varying the animation by input device?
yreg
4 days ago
The question was "Why not just always turn off the animations?"
---
> why are we varying the animation by input device?
Another user explains it here: https://news.ycombinator.com/item?id=42176540
I don't actually agree, I think you can keep the animation and still make the content available immediately for screen readers. (And of course, keyboard navigation is not just for screen reader users!) Maybe someone else knows of some issue I don't.
that_guy_iain
5 days ago
> The first mistake the developer made, was that he wanted to create a different user experience between keyboard and mouse.
No, they wanted to make them the same. It's just to give a blind person the same experience as a seeing person requires different things because they operate differently for obvious reasons. For example, a blind person can't see when an animation has finished. They expect that menu to be available once they've triggered it. However, seeing people see the dropdown appearing and then go to use it once it's ready.
> Don't try to be smart when it comes to accessibility.
In all seriousness, considering the state of accessibility as is, I think going outside the box isn't trying to be smart. It's actually being smart. The BBC frontend team is probably at the forefront of making high-traffic websites extremely usable.
O-stevns
4 days ago
> a blind person can't see when an animation has finished. They expect that menu to be available once they've triggered it. However, seeing people see the dropdown appearing and then go to use it once it's ready.
A blind person can and should get cues from their assistive technologies that an item is is being loaded and is shown, either using announcements or aria tags that provide this information to the user.
While its fine to expect that something is available immediately, that's rarely a realistic expectation, whether you're blind or not.
that_guy_iain
4 days ago
If you remove the can, I would agree.
pwg
5 days ago
> For example, a blind person can't see when an animation has finished. They expect that menu to be available once they've triggered it. However, seeing people see the dropdown appearing and then go to use it once it's ready.
For my two-cents, the BBC was simply trying too much to be "cutesy". Don't animate anything, because the silly animation on mouse click simply makes the website feel slower overall. Just open the menu as fast as the user's browser will open it.
unclad5968
5 days ago
That wouldn't change anything. They want the first element of the menu to be focused when "clicked" from a keyboard but not from a mouse. The animation doesn't affect that.
j16sdiz
5 days ago
> Don't animate anything
Animation helps to correlate screen elements. Without animation it actually takes longer to establish the mental relationship between the action and the result.
hombre_fatal
4 days ago
We as developers think we like zero animation. Probably not least because animation is harder for us to implement than just view(state).
But it's very easy to create cases where the UX sucks because things happen instantly especially as inherent complexity of the app increases.
f1shy
5 days ago
> Don't try to be smart when it comes to accessibility.
“Don't try to be smart” alone is good advice in general and everywhere. Also in UI “don’t try to be original”
josephg
5 days ago
I prefer the line: “make it as simple as possible, but no simpler”
Sometimes complexity is simply the right tool for the job. Complexity is essential and valuable in all sorts of places - like fuzzers, LLMs, compilers, rendering engines, kernel schedulers and so on. But projects only have so much complexity budget to spend. I think I've spent my whole career trying to figure out how to spend complexity wisely. And I could spend decades more on it.
afandian
5 days ago
The BBC site has a "search box" that's actually a button that brings up the real search box. Always feels confusing. At least it's consistent across News / Sounds / iPlayer.
eCa
4 days ago
This is becoming more and more common. Can’t say I’m a fan either.
cryptonector
4 days ago
I think there is no browser bug here, though using negative screen coordinates is probably going to be surprising to a lot of folks.
However, the BBC's intent seems quite sound to me from an a11y point of view, and their commitment to a11y is commendable. Though it's likely that for some browsers their attempts at defining their own a11y experience will result in a bad UX anyways.
kypro
5 days ago
Does anyone else find this write up confusing?
My understanding from this is that BBC want slightly different behaviour depending on whether it's a mouse or keyboard "click" (keyboard shouldn't show the animation and should focus the first link in the menu).
However, they also want the ease of binding to a single event and while binding to "click" can do this, they have no way to tell whether it was a mouse click or keyboard press which triggered the event.
To solve this they're using an unreliable heuristic after realising in Chrome if the mouse position is screenX=0, screenY=0 it means the event was either triggered by a mouse click at screenX=0, screenY=0 or a keyboard.
As someone whose worked on accessibility projects in the past, this is a really stupid idea imo, and had I reviewed a PR with something like this I would have asked it to be reworked. While I agree browsers should ideally do the same thing, the real issue here seems to me that screenX and screenY make little sense on "click" triggered by a keyboard.
The solution ideally would be a new event ("trigger" or something) which doesn't emit a "MouseEvent", but something more generic which could apply to both a keyboard and mouse event and provide information about the "trigger" source. Imo keyboard "clicks" are weird to begin with and would ideally be fixed with a more appropriate event.
That said, I understand this doesn't currently exist in the spec and a solution is needed now. Therefore I don't see why they couldn't also bind to a "keydown" event then if the click is triggered alongside the "keydown" on the same element, assume it was a keyboard press. That would be far more reliable and far less hacky than what they're doing, and would allow them to trigger from the single event with a bit of extra code to detect if it was a keyboard or mouse.
joshtumath
5 days ago
Hello I am the author and, yes, I totally agree some generic 'trigger' event would be far better.
To use the keydown event means we have to assume that the 'Enter' and 'Space' are the only keys we need to check for. Using 'click' is far safer from an accessibility point of view because it will always respect what your device considers to be some kind of input trigger.
As stated in the UI Events spec:
> For maximum accessibility, content authors are encouraged to use the click event type when defining activation behavior for custom controls, rather than other pointing-device event types such as mousedown or mouseup, which are more device-specific. Though the click event type has its origins in pointer devices (e.g., a mouse), subsequent implementation enhancements have extended it beyond that association, and it can be considered a device-independent event type for element activation.
And to be clear, I would not want to do it this way if it was for some really critical difference in behaviour between pointer or keyboard interactions. I'm OK with this strange mechanism here because the fallback behaviour is not that different. If you're on Safari, for example, which can't check for `screenX === 0`, then all that happens is that there will be an animation when you open the menu.
However, sadly, because of the ways various developers have added to this code over the years, it's broken that fallback behaviour and stopped it working entirely. So I've just finished a refactor to sort that out and it will hopefully be going live soon.
yreg
5 days ago
I suspect you are checking for the coordinates because you can't fully trust the event type.
I currently have an open semi-related bug, also in a menu dropdown component (where we also want to focus the first item when triggered via keyboard). My issue is that when Windows Narrator is used, the space/enter triggers a mocked click event instead of the keydown. We could check for the position like you do.
Unfortunately, accessibility is often hacky both on the content side, but also on on the browser/screen reader side.
Sayrus
5 days ago
While I can understand the author's need for screenX and screenY, the question remains. Why would screenX return the real screenX position instead of the position within the renderer (I don't think that exists?) or the rendered page (layerX and layerY)? The author's need would be met the same with the renderer position and window positions wouldn't be leaked to all visited websites.
tshaddox
5 days ago
> Often when opening a menu, we don't want a slightly different behaviour around focus and animations depending on if the user 'clicks' with a pointer or keyboard.
Is the word “don’t” a mistake which gives the sentence the opposite of the intended meaning?
joshtumath
5 days ago
Hello I am the author and that was indeed a mistake. Whoops!