I have this online game. It has a start button, but the button won’t work before all resources are loaded. It takes minutes to load so when the user clicks the button, it will result in INP penalty.
I have a progress animation, but still many people are clicking on it crazily even if the progress bar doesn’t meet 100%.
Can I let the button to shift one or two pixels when the user clicks on it to avoid INP penalty? I have tried this strategy but it seems it’s not working. Any solution for this?
Thanks!
INP measures the time from an interaction, until the JavaScript event handlers are run, and then the next paint is possible. So, if your event handlers are not attached to your button INP will not wait for them to be attached and count that time.
Similarly you do not need to do a paint to end INP, the metric will count the next opportunity to paint (i.e. when the main thread is free an a render is possible). So there is no need to resort to tricks like small paints. That is why that workaround is not helping.
So the question remains why your INP is so bad? I presume you can repeat this locally? Is the mere act of parsing and processing the JavaScript causing a large amount of blocking on the main thread? If so that could very well be the cause. Even if there is no event handler the browser might do some default changes on the button (e.g. the 3-D depress effect) and if these can't be painted to screen because the main thread is too busy then that will impact your INP. Or there simply is no room to paint.
Or is it the click on the button causes some JavaScript to wait until the main game is loaded and only then handle the click? If so, then as long as this is asynchronous it again shouldn't cause a problem.
But let's take a step back here. You are display a button that does not work - for minutes, and users are clicking on that button not knowing it won't do anything. And maybe rage-clicking at that point leading to potentially a queue of work. So I would question if this seems like a good pattern? Yes it's normally good to be able to render static content as soon as possible and not be dependent on JavaScript (especially large JavaScript bundles!) for that initial render to happen, but for interactive widgets like buttons you really need to ask yourself whether displaying an inert button is better than no button at all.
So rather than trying to persuade the users not to click that very tempting button you've put there with a progress animation I would say don't show the button at all. It's just annoying the users. Add the button when it's ready. But still reserve the space for the button (to avoid introducing CLS issues).
This may not completely solve the issue if there really is a tonne of JavaScript, but it will at least avoid users getting frustrated. And likely without seeing something to click on they will not try to click as much and so INP will not be as much of an issue.
Unlike previous web performance metrics of the past, the Core Web Vitals are user centric metrics. When they flag, you're first question should be: "is this a good user experience", rather than "how can I appease the metric". In many cases that will guide you in what to change to improve the situation, and then make the metric happy too.