para name metadatos keywords etiquetas etiqueta ejemplos buscadores html css html5 css3 css-selectors

name - metadatos html para buscadores



¿Hay alguna forma de activar dos cambios haciendo clic en una sola etiqueta? (6)

He estado jugando con HTML y CSS para crear un juego de mesa simple para 2 jugadores sin usar JavaScript. Utilizo etiquetas, botones de radio y casillas de verificación para crear diferentes estados e imitar algunas lógicas para que la pieza se mueva alrededor del tablero.

Funciona "bien", aunque la usabilidad no es muy buena. Por ejemplo, después de hacer clic en los dados, la ficha se mueve, y muestro un botón para cambiar al siguiente jugador (controlado nuevamente con una etiqueta y una casilla de verificación) ... lo cual no es excelente, sería mejor si cambiara el jugador "automáticamente."

El problema es que la <label> solo puede apuntar a un elemento, y no sé cómo activar dos "acciones" (o efectos secundarios) con un solo clic.

El siguiente código es un mcve para visualizar mejor el problema: hay dos jugadores (especificados por turnos), una tabla con tres fichas (representadas por 6 botones de radio: 1 por jugador y ficha), y dos botones para cambiar el giro del jugador (solo uno visible). Si haces clic en el botón Cambiar turno, el turno irá al siguiente jugador. (Un ejemplo más complejo se puede encontrar here )

El problema es que los usuarios se ven obligados a presionar el botón para cambiar de turno, de lo contrario, el mismo jugador siempre estará activo. ¿Hay alguna forma de hacer que cuando se hace clic en una etiqueta, no solo se active el mosaico, sino que también se cambie el giro? O en su ausencia, ¿hay alguna alternativa para lograrlo? (sin usar 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>

¿Hay alguna forma de activar dos "cambios de estado" haciendo clic en una sola <label> o <a> ?

Algunos intentos de resolver esto:

Intenté colocar una <a> dentro de una <label> para poder activar dos cambios legibles :target y :checked (con el: target I controlaría el turno del jugador, y con la opción marcada sería la posición de la pieza) . Parece ser un HTML válido (al menos de acuerdo con el validador W3C), pero realmente no funciona . Por ejemplo, en el siguiente fragmento, al hacer clic en el primer enlace se resaltará el texto, al hacer clic en el segundo se marcará el cuadro, y (espero) al hacer clic en el tercero se harán ambas cosas ... pero no:

#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>

También intenté jugar con diferentes pseudo-clases :checked y :invalid . No hizo mucho por una casilla de verificación, ya que ambas se aplicarían al mismo tiempo, y según mis pruebas, el required no se aplica a una sola radio (pero es posible que esté haciendo algo mal):

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>


¿Es esto lo que estás buscando?

.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>

Esto usa :target para cambiar los atributos de múltiples elementos con solo un disparador.


Con respecto a su pregunta, es imposible apuntar a múltiples elementos a través del atributo for de un elemento de etiqueta html.

Pero si una recarga de la página está bien para comenzar un juego nuevo, realmente no necesitarás apuntar dos entradas a la vez con una etiqueta.

Aquí hay un juego de dados simple usando solo 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>

Esto podría adaptarse fácilmente para mostrar las fichas actuales de los jugadores y determinar un determinado resultado.


Honestamente, no creo que haya ningún método que pueda alternar múltiples estados de casilla usando solo HTML y CSS.

Eso no quiere decir que no se pueda hacer más intuitivo con CSS al diseñar los elementos de una manera que haga que el cambio entre jugadores se sienta más como si simplemente fuera parte del proceso.

Preparé un fragmento de ejemplo rápido y sucio que proporciona un método de implementación (utilizando la opacidad básica y los estilos de cursor). Sin embargo, este método se puede utilizar a través de varios enfoques diferentes.

Por ejemplo, podría mover el troquel fuera de la pantalla por completo, o alternar un div para evitar que los elementos se vean / hagan clic (utilizando la posición absoluta y el índice z).

De hecho, el enfoque del índice z podría utilizarse para permitir el cambio de jugador sin tener que mover el cursor, lo que lo hace más intuitivo desde la perspectiva del jugador.

Esperemos que estas ideas ayuden a obtener la pelota, o mueran, rueden. 😁

/* 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>


Tu :invalid intento no :invalid no funciona porque un parámetro required en un botón de radio validará si se selecciona alguno de los botones del grupo (cualquiera que comparta el mismo name )

Como alternativa, puede usar :not selector con :checked lugar

#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>

Tal vez esto sea suficiente para hacer que tu juego funcione :)


Una idea es considerar el :focus estado de :focus en la etiqueta que le permitirá activar dos cambios. El único inconveniente es que :focus estado de :focus se habilitará solo en el mousedown y se desactivará en el mouseup .

Aquí hay un ejemplo

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>

ACTUALIZAR

Usar la lógica anterior y considerar el código inicial del juego de dados aquí es una idea que usa animación. El truco consiste en crear una animación pausada con 2 estados y encendido :focus Hago que la animación se ejecute para cambiar entre los estados.

Por supuesto, esto no es 100% preciso, ya que dependerá de la velocidad del clic, pero puede ser una idea a tener en cuenta:

.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>

En caso de que quiera un efecto permanente estático, es bastante simple, ya que solo necesita hacer que la duración sea muy pequeña y usar 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>

ACTUALIZACIÓN 2

Aquí hay otra idea que depende de la transición y es más precisa, PERO necesito confiar en dos dados, ya que cada uno activará un estado específico para cambiar el texto, así que necesitamos encontrar una manera de hacer que ambos dados estén uno encima del otro. y cambiar su orden al hacer clic:

.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>

Como nota al margen, he usado :focus y :active para que podamos confiar en esos estados, ya que pueden activarse juntos incluso con el elemento anidado:

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>


Respuesta editada para reflejar los cambios a la pregunta original:

Intenta establecer diferentes estados donde cada estado refleje tanto el jugador activo como la posición de las piezas, como:

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>

Este es solo un ejemplo muy simple, en el que cada jugador puede mover su pieza a cualquier campo que desee y si la pieza de su oponente "pasa" a estar en ese campo, gana.

En un escenario del mundo real, podría considerar el uso de algunos preprocesadores HTML y CSS, como Pug / Jade y Sass para iterar sobre todas las combinaciones de estados posibles.

Actualizar

No podía sacarme esto de la cabeza, así que jugué un poco ...

:focus parecía ser un buen punto de partida, así que lo intenté (sugerencia: asegúrese de establecer tabindex="0" en la <label> s). Pero siempre hay un cierto orden en las cosas y no pude encontrar una manera de lograr relaciones bidireccionales usando ~ .

Así que volví a mi comentario de ayer, acerca de hacer que la UX del botón del "siguiente jugador" sea más "fluida". Here está mi código (la idea básica es cambiar el botón "siguiente jugador" a un estado de "confirmar movimiento", donde el jugador puede confirmar su movimiento o elegir otro azulejo para moverse). No, no es una respuesta a su pregunta , pero parece ser una solución a su problema (y se escala ''muy bien'' más o menos, al menos lineal, no cúbico). html / css parece un poco voluminoso para publicar aquí y Jade / Sass no pude ponerme a trabajar, así que aquí están los enlaces a esos archivos: