You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仅使用CSS能否检测用户未离开触摸屏的持续触摸状态?

示例代码

CSS 代码

:root {
  font-family: Avenir, Helvetica, Arial, sans-serif;

  --form:  300px;
  --half:  150px;
  --size:   60px;
  --pad:     8px;
  --top:   calc((var(--half) - var(--size)) / 2 - var(--pad));
  --left:  calc((var(--form) - var(--size)) / 2 - var(--pad));
  --end:    10px;
  --gap:     4px;
  --line:    1px;

  --white: #fff;
  --light: #ddd;
  --dark:  #222;
  --btn:   #060;
  --bg:    #030;
  --red:   #f33;
  --lava:  #600;
  --deep:  #300;
  --brdr:  #fff6; /* button-color-agnostic border color */

  --time:   10s;
}

/* Place main in the center */
body {
  margin: 0;
  padding: 0;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  color: var(--light);
  background-color: var(--dark);
}

/* Style both the Start and Play Again buttons */
button,
.button {
  border: var(--line) outset var(--brdr);
  border-radius: var(--pad);
  padding: var(--pad);
  cursor: pointer;
  background-color: var(--btn);
}

button {
  --bg: var(--deep);
  background-color: transparent;
  color: inherit;
}

button:hover,
.button:hover {
  color: var(--white);
}

button:hover:active,
.button:hover:active {
  border-style: inset;
  background-color: var(--bg);
}

/* Make form the default size for an iframe */
form {
  position: relative;
  width: var(--form);
  height: var(--half);
  border: var(--line) solid var(--white);
  border-radius: var(--pad);
  box-sizing: border-box;
  overflow: hidden;
}

/* Take the checkbox out of the flow of the page
 * and show it in front of the .lava younger sibling
 * so that it will be a safe place for the mouse.
 */
input {
  position: absolute;
  z-index: 2;
}

/* Fill the form element with .lava */
.lava {
  position: absolute;
  width: 100%;
  height: 100%;
  background: var(--bg); /* <<<< No eruption yet */

  /* Style the "You Lost" span and the link... */
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  
  p {
    font-size: var(--size);
    margin: 0;
    color: var(--red);
  }

  /* ... but hide them and make them inactive */
  * {
    opacity: 0;
    pointer-events: none;
  }
}

/* Place a round Start button in the center with an invisible
 * .blocker in front of it. Move them both in front of the lava.
 */
.blocker,
.start {
  position: absolute;
  z-index: 1;
  top: var(--top);
  left: var(--left);
  width: var(--size);
  height: var(--size);
  line-height: var(--size);
  border-radius: var(--size);
  text-align: center;
}
.start::after {
  content: "Start";
}
/* Make the .blocker invisible and inactive at the start */
.blocker {
  opacity: 0;
  pointer-events: none;
}

/* When the game starts, shrink both the .start button
 * and the .blocker, and move them together towards 
 * the input element in the top left corner.
 */
 label:has(:checked) {
  .start,
  & ~ .blocker {
    top: var(--gap);
    left: var(--gap);
    width: var(--end);
    height: var(--end);
    padding: 0px;
    font-size: 0px;
    line-height: var(--end);
    transition: all var(--time);
  }
}

input:checked ~ .start::after {
  content: "Panic!";
}


/* When the game starts, make the .lava active */
label:has(input:checked) {
  & ~ .lava {
    background-color: var(--lava);

    &:hover {
      z-index:2;

      * {
        opacity: 1;
        pointer-events: all;
      }
    }
  }

  /* Prevent .start button from toggling the input */
  & ~ .blocker {
    pointer-events: all;
  }
}

/* Show the GitHub logo */
a.github {
  width: 0;
  height: 0;

  img {
    position: absolute;
    right: 3px;
    bottom: 3px;
    width: 32px;
    height: 32px;
    filter: grayscale(1);
    opacity: 0.25;

    &:hover {
      opacity: 1;
    }
  }
}

HTML 代码

<form>
  <label>
    <input type="checkbox">
    <span class="start button"></span>
  </label>
  <span class="blocker button"></span>

  <div class="lava">
    <p>You Lost!</p>
    <button type="reset">Play again</button>
  </div>

  <a class="github" href="https://github.com/MERNCraft/lava">
    <img src="github.svg" alt="github">
  </a>
</form>

问题背景

用JavaScript可以检测touch事件的结束,但在CSS里,用户触摸屏幕时,浏览器会为被触摸元素及其所有父元素添加:hover伪类(至少作用于<html>元素),而且在Android版Chrome中,即使用户停止触摸,这些元素上的:hover伪类也会保留。

浏览器还会生成:active伪类,用户停止触摸时这个伪类会消失;鼠标用户松开按键时,:active同样会消失,哪怕鼠标还停在元素上处于hover状态。

我正在做一款迷宫游戏,要求玩家沿路径移动且不能越线。用鼠标时可以通过检测持续hover路径来判断,但触摸屏用户只要抬起手指再点击终点就能完成游戏,这不符合规则。

问题

仅使用CSS能否检测玩家的手指从起点到终点全程未离开屏幕?

回答

仅靠纯CSS无法实现这种检测。

原因如下:

  • CSS的:hover伪类在触摸后会持续保留,无法区分用户是一直触摸还是已经抬起手指;
  • :active伪类仅在触摸按压期间生效,但一旦手指滑动到其他元素上,原元素的:active会消失,无法追踪整个触摸路径的连续性;
  • CSS没有原生机制追踪触摸事件的完整生命周期(从按下到持续滑动再到抬起的全程状态),也无法判断触摸点是否始终保持在指定路径范围内。

要实现这种需求,必须结合JavaScript监听touchstart、touchmove、touchend等事件,实时追踪触摸位置是否始终在合法路径上,一旦触摸离开路径或抬起手指,就判定游戏失败。


内容的提问来源于stack exchange,提问作者James Newton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 13:10:55