To be brutally frank -- Yeah, I know, me? Shocking! -- it's not something I would even worry about. Why? Because it's not something actual users do.
In testing, or as web development geeks, we might sit there opening and closing them going "ooh, neato" and so forth, but it's not something a normal user would do, and/or would even care about. If they're opening and closing them that much as a USER, there's something wrong with your UI.
Like pulling some sort of idiotic "wah wah teh pageluds r teh evilz" SPA rubbish.
All that said, you can cut down on the history pollution thus:
{
const
modalIds = [ "mainMenu" ],
isModal = (hash) => {
if (hash.length < 2) return false;
let e = document.getElementById(hash.substr(1));
return e && (
e.classList.contains("modal") ||
modalIds.includes(e.id)
) ? hash : false;
}, // isModal
modalClose = (e) => {
e.preventDefault();
if (depth < 0) {
history.go(depth);
depth = 0;
}
if (
location.hash.length > 1 ||
depthZeroHash
) {
history.replaceState(undefined, undefined, "");
depthZeroHash = false;
depth = 0;
}
}, // modalClose
modalOpen = (e) => { depth--; },
nonModalOpen = (e) => { depth = 0; };
let
depth = 0,
depthZeroHash = location.hash.length > 1;
for (let anchor of document.querySelectorAll("a[href^='#']")) {
if (anchor.classList.contains("modalClose")) {
anchor.addEventListener("click", modalClose);
} else {
let href = anchor.getAttribute("href");
if (href.length > 1) anchor.addEventListener("click",
isModal(href) ? modalOpen : nonModalOpen
);
}
}
}
Not 100% reliable, but it helps a lot. So many little corner cases to test for.
This assumes that your modals are either named .modal or have their ID in the array at the start, that your closing anchors are .modalClose. It will auto detect if your anchors are on-page links vs. modal on-page links.