html - 有什么方法可以通过单击一个标签来触发两个更改?

标签 html css css-selectors

我一直在尝试使用 HTML 和 CSS 来创建一个简单的 2 人棋盘游戏,而无需使用任何 JavaScript。我使用标签、单选按钮和复选框来创建不同的状态并模仿一些逻辑,这样棋子就会在棋盘上移动。

虽然可用性不是很好,但它工作得“很好”。例如,点击骰子后,瓷砖移动,我显示一个按钮来改变下一个玩家(再次用标签和复选框控制)......这不是很好,如果它改变玩家会更好“自动地。”

问题是 <label>只能针对一个元素,而且我不知道如何通过一次点击触发两个“ Action ”(或副作用)。

下面的代码是一个mcve为了更好地形象化问题:有两个玩家(由轮流指定),一个包含三个方 block 的棋盘(由 6 个单选按钮表示:每个玩家和方 block 各 1 个),以及两个用于更改玩家轮次的按钮(只有一个可见)。如果您单击回合更改按钮,回合将转到下一个玩家。 (可以找到更复杂的示例 here )

问题是用户必须按下按钮才能改变回合,否则同一位玩家将始终处于事件状态。有没有办法让点击标签时,不仅瓷砖被激活,而且转弯也改变了?或者在没有它的情况下,是否有替代方案来实现这一目标? (不使用 JS)

#p1:checked ~ [for=p1],
#p1:checked ~ [for^=tile-p2],
#p1:checked ~ [name^=tile-p2],
#p2:checked ~ [for=p2],
#p2:checked ~ [for^=tile-p1],
#p2:checked ~ [name^=tile-p1]
{ 
  display: none; 
}

/* more rules to hide/show more elements */
<h1>Players:</h1>
<input type="radio" id="p1" name="player" checked /> P1
<input type="radio" id="p2" name="player" /> P2

<h1>Board: </h1>
Player 1:
<input type="radio" id="tile-p1-1" name="tile-p1" checked />
<label for="tile-p1-1">P1 to 1</label>
<input type="radio" id="tile-p1-2" name="tile-p1" />
<label for="tile-p1-2">P1 to 2</label>
<input type="radio" id="tile-p1-3" name="tile-p1" />
<label for="tile-p1-3">P1 to 3</label>
<br/>
Player 2:
<input type="radio" id="tile-p2-1" name="tile-p2" checked />
<label for="tile-p2-1">P2 to 1</label>
<input type="radio" id="tile-p2-2" name="tile-p2" />
<label for="tile-p2-2">P2 to 2</label>
<input type="radio" id="tile-p2-3" name="tile-p2" />
<label for="tile-p2-3">P2 to 3</label>

<h1>Change of turn:</h1>
<label for="p2">Change to Player 2</label>
<label for="p1">Change to Player 1</label>

有没有办法通过只点击一个来触发两个“状态变化”<label><a>


解决这个问题的一些尝试:

我试着放一个 <a><label> 里面能够触发两个可读更改::target:checked (使用 :target 我会控制玩家的回合,使用 :checked 它将控制棋子的位置)。它似乎是有效的 HTML(至少根据 W3C 验证器),但是 it doesn't really work .例如,在下一个片段中,单击第一个链接将突出显示文本,单击第二个将标记框,并且(我希望)单击第三个将同时执行这两个操作......但它不会:

#test:target {
  color: red;
}

#cb:checked

a, label {
  display: block;
  text-decoration: underline;
  color: blue;
}
<input type="checkbox" id="cb" />
<div id="test">TEST</div>

<a href="#test">Highlight test</a>
<label for="cb">Check the box</label>
<label for="cb">
  <a href="#test">Highlight test AND check the box</a>
</label>

我还尝试使用不同的伪类::checked:invalid .它对复选框没有太大作用,因为它们会同时应用,而且根据我的测试,required不适用于单个 radio (但我可能做错了什么):

div {
  color: purple;
}

#radio1:checked ~ div {
  color: blue;
}

#radio2:checked ~ div {
  color: fuchsia;
}

#radio1:invalid ~ div {
  color: red;
}

#radio1:invalid + #radio2:checked ~ div {
  color: green;
}
<input type="radio" name="radio1" id="radio1" required />
<input type="radio" name="radio1" id="radio2" />

<div>Text to be green if radio2 is checked</div>

最佳答案

一个想法是考虑标签上的 :focus 状态,它允许您触发两个更改。唯一的缺点是 :focus 状态将仅在 mousedown 上启用,在 mouseup 上禁用。

举个例子

label:focus + #test {
 color: red;
}

label {
  display: block;
  text-decoration: underline;
  color: blue;
}
<input type="checkbox" id="cb" >

<label for="cb"  tabindex=-1>Check the box and highlight the text</label>
<div id="test">TEST</div>

更新

使用上面的逻辑并考虑这里骰子游戏的初始代码是使用动画的想法。诀窍是创建一个具有 2 个状态的暂停动画,然后在 :focus 上我让动画运行以便在状态之间切换。

当然,这不是 100% 准确,因为这取决于点击速度,但可以考虑一下:

.container {
  position: relative;
}

label {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 50px;
  height: 50px;
  line-height: 50px;
  background: #eeeeee;
  text-align: center;
  animation: changeOrder 0.6s infinite;
}

@keyframes changeOrder {
  from { z-index: 6;}
   to { z-index: 1; }
}
label:nth-of-type(1) { animation-delay: 0s; }
label:nth-of-type(2) { animation-delay: -0.1s; }
label:nth-of-type(3) { animation-delay: -0.2s; }
label:nth-of-type(4) { animation-delay: -0.3s; }
label:nth-of-type(5) { animation-delay: -0.4s; }
label:nth-of-type(6) { animation-delay: -0.5s; }


label:active {
  /*Mandatory to break the stacking context and allow 
       the pseudo element to be above everything*/
  position: static;
  /*For illustration*/
  margin-left: 50px;
  background: red;
}

label:active::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  z-index: 10;
}
.player {
  display:inline-block;
  margin-top:80px;
}

.player:before {
 content:"Player One";
 animation: player .3s infinite step-end;
 animation-play-state: paused;
}

label:focus ~ .player:before{
 animation-play-state: running;
}

@keyframes player {
  0% {
     content:"Player One";
  }
  50% {
     content:"Player Two";
  }

}
<input type="radio" name="cb" id="cb1" value="1">
<input type="radio" name="cb" id="cb2" value="2">
<input type="radio" name="cb" id="cb3" value="3">
<input type="radio" name="cb" id="cb4" value="4">
<input type="radio" name="cb" id="cb5" value="5">
<input type="radio" name="cb" id="cb6" value="6">
<div class="container">
  <label for="cb1" tabindex="-1">1</label>
  <label for="cb2" tabindex="-1">2</label>
  <label for="cb3" tabindex="-1">3</label>
  <label for="cb4" tabindex="-1">4</label>
  <label for="cb5" tabindex="-1">5</label>
  <label for="cb6" tabindex="-1">6</label>
  <span class="player" ></span>
</div>

如果你想要一个静态的永久效果,这很简单,因为你只需要使持续时间非常小并使用forwards

.container {
  position: relative;
}

label {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 50px;
  height: 50px;
  line-height: 50px;
  background: #eeeeee;
  text-align: center;
  animation: changeOrder 0.6s infinite;
}

@keyframes changeOrder {
  from { z-index: 6;}
   to { z-index: 1; }
}
label:nth-of-type(1) { animation-delay: 0s; }
label:nth-of-type(2) { animation-delay: -0.1s; }
label:nth-of-type(3) { animation-delay: -0.2s; }
label:nth-of-type(4) { animation-delay: -0.3s; }
label:nth-of-type(5) { animation-delay: -0.4s; }
label:nth-of-type(6) { animation-delay: -0.5s; }


label:active {
  /*Mandatory to break the stacking context and allow 
       the pseudo element to be above everything*/
  position: static;
  /*For illustration*/
  margin-left: 50px;
  background: red;
}

label:active::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  z-index: 10;
}
.player {
  display:inline-block;
  margin-top:80px;
}

.player:before {
 content:"Click the dice!";
 animation: player .1s forwards;
 animation-play-state: paused;
}

label:focus ~ .player:before{
 animation-play-state: running;
}

@keyframes player {
  2%,100% {
     content:"Dice clicked!";
  }

}
<input type="radio" name="cb" id="cb1" value="1">
<input type="radio" name="cb" id="cb2" value="2">
<input type="radio" name="cb" id="cb3" value="3">
<input type="radio" name="cb" id="cb4" value="4">
<input type="radio" name="cb" id="cb5" value="5">
<input type="radio" name="cb" id="cb6" value="6">
<div class="container">
  <label for="cb1" tabindex="-1">1</label>
  <label for="cb2" tabindex="-1">2</label>
  <label for="cb3" tabindex="-1">3</label>
  <label for="cb4" tabindex="-1">4</label>
  <label for="cb5" tabindex="-1">5</label>
  <label for="cb6" tabindex="-1">6</label>
  <span class="player" ></span>
</div>

更新 2

这是另一个依赖转换的想法,并且更准确但是我需要依赖两个骰子,因为每个骰子都会触发特定状态以更改文本,所以我们需要找到一种方法来制作两个骰子在彼此之上并在点击时改变他们的顺序:

.container {
  position:relative;
  margin-top:20px;
  overflow:hidden;
  min-height:50px;
}

label {
  display:block;
  position: absolute;
  top: 0;
  left: 0;
  width: 50px;
  height: 50px;
  line-height: 50px;
  background: #eeeeee;
  text-align: center;
  animation: changeOrder 0.6s infinite;
}
label:active {
  /*Mandatory to break the stacking context and allow 
       the pseudo element to be above everything*/
  position: static;
  width:0;
  height:0;
  overflow:hidden;
}

label:active::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  z-index: 10;
}

@keyframes changeOrder {
  from { z-index: 6;}
   to { z-index: 1; }
}
label:nth-of-type(1),label:nth-of-type(7) { animation-delay: 0s; }
label:nth-of-type(2),label:nth-of-type(8) { animation-delay: -0.1s; }
label:nth-of-type(3),label:nth-of-type(9) { animation-delay: -0.2s; }
label:nth-of-type(4),label:nth-of-type(10) { animation-delay: -0.3s; }
label:nth-of-type(5),label:nth-of-type(11) { animation-delay: -0.4s; }
label:nth-of-type(6),label:nth-of-type(12) { animation-delay: -0.5s; }



label.second {
  left:100px;
}

.player {
  display:inline-block;
  margin-top:80px;
  height: 18px;
  overflow:hidden;
}
.player span {
  display:block;
  margin-top:-18px;
  transition:1000s;
}



label.first:focus ~ .player span{
  margin-top:0;
  transition:0s;
}
label.second:focus ~ .player span{
  margin-top:-36px;
  transition:0s;
}
<input type="radio" name="cb" id="cb1" value="1">
<input type="radio" name="cb" id="cb2" value="2">
<input type="radio" name="cb" id="cb3" value="3">
<input type="radio" name="cb" id="cb4" value="4">
<input type="radio" name="cb" id="cb5" value="5">
<input type="radio" name="cb" id="cb6" value="6">
<div class="container">
<label class="first" for="cb1" tabindex="-1">1</label>
<label class="first" for="cb2" tabindex="-1">2</label>
<label class="first" for="cb3" tabindex="-1">3</label>
<label class="first" for="cb4" tabindex="-1">4</label>
<label class="first" for="cb5" tabindex="-1">5</label>
<label class="first" for="cb6" tabindex="-1">6</label>
  
<label class="second" for="cb1" tabindex="-1">1</label>
<label class="second" for="cb2" tabindex="-1">2</label>
<label class="second" for="cb3" tabindex="-1">3</label>
<label class="second" for="cb4" tabindex="-1">4</label>
<label class="second" for="cb5" tabindex="-1">5</label>
<label class="second" for="cb6" tabindex="-1">6</label>

<div class="player">
 <span> Player One Clicked<br>
  Which player?<br>
  Player Two clicked
 </span>
</div>
</div>

作为旁注,我使用了 :focus:active 因此我们可以依赖这些状态,因为即使嵌套元素也可以一起触发它们:

div {
  display:block;
  outline: none;
  padding:10px 0;
}
.first:active + div{
  color:red
}
.second:active + div{
  color:red
}

.first:focus + div{
  border:1px solid red
}
.second:focus + div{
  border:1px solid red
}
<div class="first" tabindex=-1 >
  Click me (only last text will change)
  <div class="second" tabindex=-1 >
    Click me (both text will change)
  </div>
  <div>
    I will be updated
  </div>
</div>
<div>
  I will be updated
</div>

关于html - 有什么方法可以通过单击一个标签来触发两个更改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51484582/

相关文章:

javascript - 滚动时更改导航栏的背景颜色

html - 使用选择器将内容包装在 div 中

jquery - jQuery 有类似 :any or :matches pseudo-class? 的东西吗

javascript - 从内联 css 和 JavaScript 按钮图像的点击更改

css - 如何使用 CSS 为子 div 设置相同的高度

php - 为什么我的 <hr/> 标签之一比其他标签小得多?

css - 我可以定位 :before or :after pseudo-element with a sibling combinator?

html - 如何在 XML 中转义 & 符号,以便将它们呈现为 HTML 中的实体?

html - 将有序列表标记为从 1 之后的点开始

html - 如何使文本适合所有 div 的宽度?