1

I am considering using the CSS :active selector to highlight buttons while the user is touching or clicking them. However, by default, its effects in Chrome Mobile seem to be out of sync with the obvious event sources. How do I add Javascript listeners for the changes in :active state?

(Three bonus questions: Can I get rid of the apparent ~130ms delay between touchstart() and :active? Why is this still happening in Chrome 108? I thought the touch delays were solved in 2015?)

<html>

<head>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<style>
html, body, pre {
  position:absolute; top:0; left:0; right:0; bottom:0;
  margin: 0; user-select: none;
}
pre {margin: 10px; overflow-y:auto}
pre:active {
  /* my goal is to highlight the content between touchstart and touchend...
     but in Chrome it's out of sync */
  background-color:#fee;
}
</style>
</head>
<body>
<pre id="ELEM"></pre>

<script>

ELEM = document.getElementById("ELEM")
ELEM.appendChild(document.createTextNode(""));

function Print(s)
{
  let t = (new Date() / 1000 % 60).toFixed(2).padStart(5,0);
  ELEM.firstChild.nodeValue += `${t}: ${s}\n`;
  ELEM.scrollTop = ELEM.scrollHeight;
}

Print("Hello, world!");
EVENTS = ["mouseup", "mousedown", "touchstart", "touchend", "click", "touchcancel", "mouseenter", "mouseout", "focusin"];
for (let e of EVENTS)
  document.body.addEventListener(e, () => {Print(e)});

</script>
</body>
</html>
personal_cloud
  • 3,943
  • 3
  • 28
  • 38

1 Answers1

0

I'm hoping there is a way to use the built-in :active selector. If not (or in the meantime) we can define an active class that corresponds directly to the simple JavaScript events. Then use .active instead of :active in the CSS:

<html>

<head>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<style>
html, body, pre {
  position:absolute; top:0; left:0; right:0; bottom:0;
  margin: 0; user-select: none;
}
pre {margin: 10px; overflow-y:auto}
pre.active {
  background-color:#fee;
}
</style>
</head>
<body>
<pre id="ELEM"></pre>

<script>

ELEM = document.getElementById("ELEM")
ELEM.appendChild(document.createTextNode(""));

function Print(s)
{
  let t = (new Date() / 1000 % 60).toFixed(2).padStart(5,0);
  ELEM.firstChild.nodeValue += `${t}: ${s}\n`;
  ELEM.scrollTop = ELEM.scrollHeight;
}

Print("Hello, world!");
EVENTS = ["mouseup", "mousedown", "touchstart", "touchend", "better-click", "touchcancel", "mouseenter", "mouseout", "focusin"];
for (let e of EVENTS)
  ELEM.addEventListener(e, () => {Print(e)});


// Touch delays were all solved in 2015...
// NOT! (https://stackoverflow.com/questions/74843213/)
let is_touch = false;
window.addEventListener('resize', ()=>is_touch=false);
function FastClick2022(el, cb)
{
  let cl       = el.classList;
  let active   = false;
  let Activate = v => {v ? cl.add("active") : cl.remove("active"); active=v;}

  el.addEventListener('mousedown',   () => Activate(true));
  el.addEventListener('mouseup',     () =>
              {is_touch || active && cb(); Activate(false)});
  el.addEventListener('mouseout',    () => Activate(false));
  el.addEventListener('touchstart',  () => Activate(true));
  el.addEventListener('touchend',    () => Activate(false));
  el.addEventListener('touchcancel', () => Activate(false));

  // touchleave polyfill
  // https://stackoverflow.com/questions/5748476
  el.addEventListener('touchmove',   (e)=> {
    if (!cl.contains("active"))
      return;
    let t = e.changedTouches[0];
    if (el !== document.elementFromPoint(t.pageX, t.pageY))
    {Print("touchleave(internal)"); Activate(false);}
  });

  // touchcancel polyfill
  // https://stackoverflow.com/questions/74844072/
  let to;
  let timeout = () => {Print("touchcancel(internal)");
               to = undefined; Activate(false);}
  el.addEventListener('touchstart', () => to = setTimeout(timeout, 700));
  el.addEventListener('touchend',   () => {
    is_touch = true;
    if (to === undefined)
      return;
    clearTimeout(to);
    to = undefined;
    cb();
  });
}

function elem_click()
{ELEM.dispatchEvent(new CustomEvent("better-click", {}));}

FastClick2022(ELEM, elem_click);

</script>
</body>
</html>
personal_cloud
  • 3,943
  • 3
  • 28
  • 38