Есть ли способ вызвать два изменения, нажав только одну метку?

Я играл с HTML и CSS, чтобы создать простую настольную игру с двумя игроками без использования JavaScript. Я использую метки, переключатели и флажки для создания разных состояний и имитирую какую-то логику, поэтому кусок будет перемещаться по доске.

Он работает "отлично", хотя удобство использования не очень велико. Например, после нажатия на кубик, плитка перемещается, и я показываю кнопку, чтобы перейти к следующему игроку (снова контролируется меткой и флажком)... что не очень хорошо, было бы лучше, если бы он изменил игрока "автоматически."

Проблема в том, что <label> может ориентироваться только на один элемент, и я не знаю, как запускать два "действия" (или побочные эффекты) одним щелчком мыши.

Следующий код - это mcve, чтобы лучше визуализировать проблему: есть два игрока (по очереди), доска с тремя фрагментами (представленная 6 переключателями: 1 на игрока и плитка) и две кнопки для изменения поворота игрока (только один видимый). Если вы нажмете кнопку изменения поворота, поворот перейдет к следующему игроку. (Более сложный пример можно найти здесь)

Проблема в том, что пользователи вынуждены нажимать кнопку, чтобы изменить поворот, иначе один и тот же игрок всегда будет активным. Есть ли способ сделать так, чтобы при нажатии на ярлык активизировалась не только плитка, но и поворот? Или в его отсутствие есть ли альтернатива для достижения этого? (без использования 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>

Ответ 1

Одна из идей - рассмотреть состояние :focus на ярлыке, которое позволит вам вызвать два изменения. Единственный недостаток заключается в том, что :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

Что касается вас, вопрос заключается в невозможности нацеливать несколько элементов с помощью атрибута for элемента html label.

Но если перезагрузка страницы прекрасна, чтобы начать новую игру, вам не нужно будет сразу нацеливать два входа на ярлык.

Здесь простая игра в кости, использующая только CSS:

.board {
  width: 100%;
  height: 200px;
  background: green;
  position: relative;
}

.board .title {
  color: white;
  font-weight: 300;
  text-align: center;
}

.board .title #p2-turn {
  display: none;
}

.dice {
  width: 50px;
  height: 50px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background: white;
  cursor: pointer;
  text-align: center;
}

.dice .pips {
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  animation: diceRoll 600ms infinite;
  z-index: 10;
}

.dice:active .pips {
  animation-play-state: paused;
}


.dice .pips:nth-child(2) { animation-delay: 100ms; }
.dice .pips:nth-child(3) { animation-delay: 200ms; }
.dice .pips:nth-child(4) { animation-delay: 300ms; }
.dice .pips:nth-child(5) { animation-delay: 400ms; }
.dice .pips:nth-child(6) { animation-delay: 500ms; }

.dice.dice--p2 {
  display: none;
}

.results {
  position: absolute;
  left: 0;
  top: 30px;
  bottom: 0;
  right: 0;
  background: black;
  color: white;
  display: none;
  text-align: center;
  line-height: 100px;
}

.results > .result {
  display: none;
}


@keyframes diceRoll {
  from { 
    z-index: 6;
  }
  to { 
    z-index: 1;
  }
}

/* LOGIC */

[name="p1-result"]:checked ~ .board .title #p1-turn {
  display: none;
}

[name="p1-result"]:checked ~ .board .title #p2-turn {
  display: block;
}

[name="p1-result"]:checked ~ .board .dice--p1 {
  display: none;
}

[name="p1-result"]:checked ~ .board .dice--p2 {
  display: block;
}

[name="p1-result"]:checked ~ [name="p2-result"]:checked ~ .results {
  display: block;
}



#p1-result-2:checked ~ #p2-result-1:checked ~ .results #p1-results,
#p1-result-3:checked ~ #p2-result-1:checked ~ .results #p1-results,
#p1-result-4:checked ~ #p2-result-1:checked ~ .results #p1-results,
#p1-result-5:checked ~ #p2-result-1:checked ~ .results #p1-results,
#p1-result-6:checked ~ #p2-result-1:checked ~ .results #p1-results,
#p1-result-3:checked ~ #p2-result-2:checked ~ .results #p1-results,
#p1-result-4:checked ~ #p2-result-2:checked ~ .results #p1-results,
#p1-result-5:checked ~ #p2-result-2:checked ~ .results #p1-results,
#p1-result-6:checked ~ #p2-result-2:checked ~ .results #p1-results,
#p1-result-4:checked ~ #p2-result-3:checked ~ .results #p1-results,
#p1-result-5:checked ~ #p2-result-3:checked ~ .results #p1-results,
#p1-result-6:checked ~ #p2-result-3:checked ~ .results #p1-results,
#p1-result-5:checked ~ #p2-result-4:checked ~ .results #p1-results,
#p1-result-6:checked ~ #p2-result-4:checked ~ .results #p1-results,
#p1-result-6:checked ~ #p2-result-5:checked ~ .results #p1-results,

#p1-result-1:checked ~ #p2-result-2:checked ~ .results #p2-results,
#p1-result-1:checked ~ #p2-result-3:checked ~ .results #p2-results,
#p1-result-1:checked ~ #p2-result-4:checked ~ .results #p2-results,
#p1-result-1:checked ~ #p2-result-5:checked ~ .results #p2-results,
#p1-result-1:checked ~ #p2-result-6:checked ~ .results #p2-results,
#p1-result-2:checked ~ #p2-result-3:checked ~ .results #p2-results,
#p1-result-2:checked ~ #p2-result-4:checked ~ .results #p2-results,
#p1-result-2:checked ~ #p2-result-5:checked ~ .results #p2-results,
#p1-result-2:checked ~ #p2-result-6:checked ~ .results #p2-results,
#p1-result-3:checked ~ #p2-result-4:checked ~ .results #p2-results,
#p1-result-3:checked ~ #p2-result-5:checked ~ .results #p2-results,
#p1-result-3:checked ~ #p2-result-6:checked ~ .results #p2-results,
#p1-result-4:checked ~ #p2-result-5:checked ~ .results #p2-results,
#p1-result-4:checked ~ #p2-result-6:checked ~ .results #p2-results,
#p1-result-5:checked ~ #p2-result-6:checked ~ .results #p2-results {
  display: block;
}

#p1-result-1:checked ~ #p2-result-1:checked ~ .results #draw,
#p1-result-2:checked ~ #p2-result-2:checked ~ .results #draw,
#p1-result-3:checked ~ #p2-result-3:checked ~ .results #draw,
#p1-result-4:checked ~ #p2-result-4:checked ~ .results #draw,
#p1-result-5:checked ~ #p2-result-5:checked ~ .results #draw,
#p1-result-6:checked ~ #p2-result-6:checked ~ .results #draw {
  display: block;
}
<input type="radio" name="p1-result" id="p1-result-1" value="1">
<input type="radio" name="p1-result" id="p1-result-2" value="2">
<input type="radio" name="p1-result" id="p1-result-3" value="3">
<input type="radio" name="p1-result" id="p1-result-4" value="4">
<input type="radio" name="p1-result" id="p1-result-5" value="5">
<input type="radio" name="p1-result" id="p1-result-6" value="6">

<input type="radio" name="p2-result" id="p2-result-1" value="1">
<input type="radio" name="p2-result" id="p2-result-2" value="2">
<input type="radio" name="p2-result" id="p2-result-3" value="3">
<input type="radio" name="p2-result" id="p2-result-4" value="4">
<input type="radio" name="p2-result" id="p2-result-5" value="5">
<input type="radio" name="p2-result" id="p2-result-6" value="6">


<div class="board">
  <h2 class="title">
    Player
    <span class="turn" id="p1-turn">1</span>
    <span class="turn" id="p2-turn">2</span>
    turn 
  </h2>
  <div class="dice dice--p1">
    roll
    <label class="pips" for="p1-result-1"></label>
    <label class="pips" for="p1-result-2"></label>
    <label class="pips" for="p1-result-3"></label>
    <label class="pips" for="p1-result-4"></label>
    <label class="pips" for="p1-result-5"></label>
    <label class="pips" for="p1-result-6"></label>
  </div>

  <div class="dice dice--p2">
    <label class="pips" for="p2-result-1"></label>
    <label class="pips" for="p2-result-2"></label>
    <label class="pips" for="p2-result-3"></label>
    <label class="pips" for="p2-result-4"></label>
    <label class="pips" for="p2-result-5"></label>
    <label class="pips" for="p2-result-6"></label>
  </div>
</div>

<div class="results">
  <div class="result" id="p1-results">Player 1 won!</div>
  <div class="result" id="p2-results">Player 2 won!</div>
  <div class="result" id="draw">Draw!</div>
</div>

Ответ 3

Я честно не думаю, что есть какой-либо метод, который может переключать несколько состояний флажка, используя только HTML и CSS.

Это не означает, что с CSS нельзя было бы сделать более интуитивно понятным, стилизовав элементы таким образом, чтобы переключение между игроками стало более похожим на просто часть процесса.

Я взломал быстрый и грязный примерный фрагмент, который предоставляет метод реализации (используя базовую непрозрачность и стили курсора). Однако этот метод можно использовать во множестве различных подходов.

Например, вы можете полностью перемещать матрицу за пределы экрана или переключать div, чтобы заблокировать элементы от просмотра/щелчка (используя абсолютное позиционирование и z-индекс).

Фактически, подход z-index может использоваться для того, чтобы разрешить переключение игрока без перемещения курсора вообще, тем самым делая его более интуитивным с точки зрения игрока.

Die rolling.

Надеюсь, эти идеи помогут получить мяч - или умереть, катятся. 😁

/* Simple Checkbox Hack */

input[type=checkbox] {
  position: absolute;
  left: -9999px;
  }

.die { 
  position: absolute;
  height: 5em;
  width: 5em;
  background: lightgray;
  border: 1pt solid gray;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  line-height: 5em;
  margin: .5em;
  cursor: pointer;
  }



/* Default State */

.p1, .p2 {
  width: 30em;
  height: 2em;
  line-height: 2em;
  color: white;
  text-align: center;
  opacity: 0.3;
  cursor: not-allowed;
  }

.p1 {
  background: green;
  }

.p2 {
  background: blue;
  }



/* Toggled State */

input[type=checkbox]:checked ~ .p1 {
   opacity: 1;
   cursor: pointer;
}
input[type=checkbox]:checked ~ .die {
   opacity: 0.3;
   cursor: not-allowed;
}
<small style="color: gray;"> (For this example, die can be clicked more than once.) </small>
<br>
<input type="checkbox" id="toggle-1">
<label class="die" for="toggle-1">Roll me!</label>
<br> <br> <br> <br> <br> <br>
<div class="p1">Player 1 - Click to start.</div>
<div class="p2">Player 2 - Click to start.</div>

Ответ 4

Отредактированный ответ, чтобы отразить изменения в исходном вопросе:

Попробуйте установить разные состояния, в которых каждое состояние отражает как активный игрок, так и позицию частей, например:

input {
  position: absolute;
  bottom: 1em;
  right: 1em;
  margin: 2px;
}

.status {
  margin: 1em;
  font-family: sans-serif;
  display: none;
}
.active1:checked ~ #status1,
.active2:checked ~ #status2,
.win1:checked ~ #status3,
.win2:checked ~ #status4 {
  display: block
}

#board {
  position: relative;
  top: 0;
  left: 0;
  border: 1px solid black;
  padding: 2px 3px;
  margin: 1em auto;
  width: 27em;
  height: 12em;
}
#board:before {
  display: block;
  position: absolute;
  bottom: 0;
  left: 0;
  margin: 2px;
  height: 9em;
  width: 9em;
  background: silver;
  content: ' ';
}
#board:after {
  display: block;
  position: absolute;
  bottom: 0;;
  right: 0;
  margin: 2px;
  height: 9em;
  width: 9em;
  background: silver;
  content: ' ';
}

.piece {
  position: absolute;
  z-index: 2;
  width: 1em;
  height: 1em;
  padding: 1em;
  margin: 1px;
  border-radius: 666em;
  line-height: 1em;
  text-align: center;
}
#piece1 {
  background: white;
  color: black;
  border: 1px solid black;
}
#piece2 {
  background: black;
  color: white;
  border: 1px solid white;
}
.win2:checked ~ #piece1,
.win1:checked ~ #piece2 {
  display: none;
}
.active1:checked ~ #piece1,
.active2:checked ~ #piece2 {
  border: 1px solid red;
}
.p1_1:checked ~ #piece1,
.p2_1:checked ~ #piece2 {
  left: 3em;
  bottom: 3em;
}
.p1_2:checked ~ #piece1,
.p2_2:checked ~ #piece2 {
  left: 12em;
  bottom: 3em;
}
.p1_3:checked ~ #piece1,
.p2_3:checked ~ #piece2 {
  right: 3em;
  bottom: 3em;
}

label {
  display: none;
  position: absolute;
  bottom: 0;
  z-index: 3;
  width: 9em;
  height: 9em;
  margin: 2px;
  text-indent: -666666em;
  /*background: green;*/
  opacity: .25;
  cursor: pointer;
}
label.pos1 {
  left: 0;
}
label.pos2 {
  left: 9em;
  margin: 2px 3px;
}
label.pos3 {
  right: 0
}
label.restart {
   top: 0;
   left: 0;
   width: 27em;
   height: 12em;
   padding: 0 1px;
   /*background: orange;*/
}
label.win1,
label.win2 {
  /*background: blue;*/
}
.active1.p2_1:checked ~ label.active1.opp1,
.active1.p2_2:checked ~ label.active1.opp2,
.active1.p2_3:checked ~ label.active1.opp3,
.active2.p1_1:checked ~ label.active2.opp1,
.active2.p1_2:checked ~ label.active2.opp2,
.active2.p1_3:checked ~ label.active2.opp3 {
  display: block;
}
.active1.p1_1:checked ~ label.active1.pos1,
.active1.p1_2:checked ~ label.active1.pos2,
.active1.p1_3:checked ~ label.active1.pos3,
.active2.p2_1:checked ~ label.active2.pos1,
.active2.p2_2:checked ~ label.active2.pos2,
.active2.p2_3:checked ~ label.active2.pos3 {
  display: none;
}
.active1.p2_1:checked ~ label.win1.pos1,
.active1.p2_2:checked ~ label.win1.pos2,
.active1.p2_3:checked ~ label.win1.pos3,
.active2.p1_1:checked ~ label.win2.pos1,
.active2.p1_2:checked ~ label.win2.pos2,
.active2.p1_3:checked ~ label.win2.pos3 {
  display: block;
}
.win1:checked ~ label.restart,
.win2:checked ~ label.restart {
  display: block;
}
<html>
  <head>
    <meta charset="utf-8">
    <title>some game</title>
  </head>
  <body>
    <div id="board">
      <input id="s1" class="active1 p1_1 p2_2" type="radio" name="state" value="1">
      <input id="s2" class="active1 p1_1 p2_3" type="radio" name="state" value="2" checked="checked">
      <input id="s3" class="active1 p1_2 p2_1" type="radio" name="state" value="3">
      <input id="s4" class="active1 p1_2 p2_3" type="radio" name="state" value="4">
      <input id="s5" class="active1 p1_3 p2_1" type="radio" name="state" value="5">
      <input id="s6" class="active1 p1_3 p2_2" type="radio" name="state" value="6">
      <input id="s7" class="active2 p1_1 p2_2" type="radio" name="state" value="7">
      <input id="s8" class="active2 p1_1 p2_3" type="radio" name="state" value="8">
      <input id="s9" class="active2 p1_2 p2_1" type="radio" name="state" value="9">
      <input id="s10" class="active2 p1_2 p2_3" type="radio" name="state" value="10">
      <input id="s11" class="active2 p1_3 p2_1" type="radio" name="state" value="11">
      <input id="s12" class="active2 p1_3 p2_2" type="radio" name="state" value="12">
      <input id="s13" class="win1 p1_1" type="radio" name="state" value="13">
      <input id="s14" class="win1 p1_2" type="radio" name="state" value="14">
      <input id="s15" class="win1 p1_3" type="radio" name="state" value="15">
      <input id="s16" class="win2 p2_1" type="radio" name="state" value="16">
      <input id="s17" class="win2 p2_2" type="radio" name="state" value="17">
      <input id="s18" class="win2 p2_3" type="radio" name="state" value="18">
      <div id="status1" class="status">Player 1:</div>
      <div id="status2" class="status">Player 2:</div>
      <div id="status3" class="status">Player 1 won!</div>
      <div id="status4" class="status">Player 2 won!</div>
      <div id="piece1" class="piece">p1</div>
      <div id="piece2" class="piece">p2</div>
      <label for="s1" class="active2 pos2 opp1">Player 2: move piece to position 2</label>
      <label for="s2" class="active2 pos3 opp1">Player 2: move piece to position 3</label>
      <label for="s3" class="active2 pos1 opp2">Player 2: move piece to position 1</label>
      <label for="s4" class="active2 pos3 opp2">Player 2: move piece to position 3</label>
      <label for="s5" class="active2 pos1 opp3">Player 2: move piece to position 1</label>
      <label for="s6" class="active2 pos2 opp3">Player 2: move piece to position 2</label>
      <label for="s7" class="active1 pos1 opp2">Player 1: move piece to position 1</label>
      <label for="s8" class="active1 pos1 opp3">Player 1: move piece to position 1</label>
      <label for="s9" class="active1 pos2 opp1">Player 1: move piece to position 2</label>
      <label for="s10" class="active1 pos2 opp3">Player 1: move piece to position 2</label>
      <label for="s11" class="active1 pos3 opp1">Player 1: move piece to position 3</label>
      <label for="s12" class="active1 pos3 opp2">Player 1: move piece to position 3</label>
      <label for="s13" class="win1 pos1">Player 1: move piece to position 1</label>
      <label for="s14" class="win1 pos2">Player 1: move piece to position 2</label>
      <label for="s15" class="win1 pos3">Player 1: move piece to position 3</label>
      <label for="s16" class="win2 pos1">Player 2: move piece to position 1</label>
      <label for="s17" class="win2 pos2">Player 2: move piece to position 2</label>
      <label for="s18" class="win2 pos3">Player 2: move piece to position 3</label>
      <label for="s2" class="restart">Restart game</label>
    </div>
  </body>
</html>

Ответ 5

Это то, что вы ищете?

.boxes {
  height: 80px;
  width: 80px;
  background-color: white;
  border: 1px solid black;
  position: relative;
}

.boxes span {
  position: absolute;
  width: 100%;
  height: 100%;
}

.boxes a div {
  display: none;
}

.boxes a:target div {
  display: block;
  height: 80px;
  width: 80px;
  background-color: black;
  border: 1px solid black;
  position: absolute;
  margin-left: 150px;
}

.boxes a:target span {
  background-color: black;
}

a {
  color: white;
}
<div class="boxes">
  <a href="#firstgroup" id="firstgroup">
    <span>Box A</span>
    <div>Box B</div>
  </a>
</div>

<div class="boxes">
  <a href="#secondgroup" id="secondgroup">
    <span>Box C</span>
    <div>Box D</div>
  </a>
</div>

Ответ 6

Ваша :invalid попытка не работает, потому что required параметр в переключателе будет проверять, выбрана ли какая-либо из кнопок в группе (кто-то с тем же name)

В качестве альтернативы вы можете использовать :not selector with :checked вместо

#radio1:not(:checked) + #radio2:checked ~ div

div {
  color: purple;
}

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

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

#radio1:not(:checked) ~ div {
  color: red;
}

#radio1:not(:checked) + #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>