Indeed, image maps seemed to be the simplest way to implement this, fitting into my goal of reducing the complexity of the content rendered on the web client. I still use CSS, but only in one place (for showing the cached timestamp in the corner). Technically I do use JavaScript, although only for getting the window dimensions, and it is optional.
An absolutely positioned CSS div is an interesting idea, if I recall correctly I actually tried this first, but ran into various problems (with scaling as the page is zoomed in/out, I think) and the image map worked perfectly. area shape="rect" works well as it translates directly from puppeteer's await page $$('a') boundingBox().