Desplegar y plegar con un clic usando CSS. Crear spoilers con INPUT | Oloblogger Para ocultar elementos de una página y hacerlos aparecer (o viceversa) a voluntad, lo más socorrido ...

22 de julio de 2014

Desplegar y plegar con un clic usando CSS. Crear spoilers con INPUT

Para ocultar elementos de una página y hacerlos aparecer (o viceversa) a voluntad, lo más socorrido es usar JavaScript. Con este lenguaje podemos controlar fácilmente gracias al evento onclick, cuándo algo es pulsado y en ese momento llamar a una función que haga un cambio de clase/estilo para hacer visible o invisible el elemento en cuestión (1) (2) (3). También tenemos los eventos onmouseover y onmouseout que a su vez nos permiten detectar si el puntero pasa por encima de algo o si al contrario, se quita de encima.

Sin embargo, con CSS lo único que podemos controlar actualmente es esto último de pasar el puntero. Se hace usando el pseudoelemento :hover y ya hemos visto por aquí algunos ejemplos sencillos y otros un poco más sofisticados (1) (2).

Pero como decía, no hay nada en CSS que sirva para el clic. Nada que sea directo claro, porque indirectamente sí que tenemos al menos un sistema. Lo vemos.

Crear un spoiler con CSS


La clave es usar la etiqueta HTML input del tipo checkbox que es la que se usa para botones radio en formularios y en la que sí se puede controlar mediante CSS cuando está clicada (realmente, seleccionada) gracias a la pseudoclase CSS :checked.

Para poder manejar cómodamente con CSS todo esto, la cosa comienza con incluir en el HTML un input, seguida su etiqueta label que hará las veces de botón y justo a continuación, dentro de una caja div, el elemento que será mostrado/ocultado con el clic en el anterior.

Con lo único que hay que tener cuidado es con que cada par input-label tengan la misma ID y sobre todo, que si usamos en la misma página otros spoilers de este tipo, la ID vaya siendo distinta.

<input type="checkbox" id="spoiler1"></input>
<label for="spoiler1">SPOILER</label>
<div class="spoiler">CONTENIDO OCULTO</div>

OTRO TIPO DE CONTENIDO
<input type="checkbox" id="spoiler2"></input>
<label for="spoiler2" >SPOILER</label>
<div class="spoiler">CONTENIDO OCULTO</div>
OTRO TIPO DE CONTENIDO


Ya metidos en el CSS, para los distintos selectores usaremos un filtro para atributos con el fin de que el estilo se aplique sólo a los input cuyo id empiecen por "spoiler" [id^="spoiler"] y que no afecte a otros que pudiera tener la página para otros fines.

Pero la clave de todo está en poder detectar con :checked, cuando un input está seleccionado. Cuando eso ocurre, a sus hermanos adyacentes que encontramos con +, le aplicamos otro estilo y listo. En este caso lo mostraremos inicialmente con opacity: 0 y con el clic lo pasaremos a opaco total para hacerlo visible.

Este sería el código básico para conseguir todo esto:

/* Ocultar botón radio */
input[id^="spoiler"]{
display: none;
}
/* Estilo botón clicable */
input[id^="spoiler"] + label {
display: block;
width: 200px;
margin: 0 auto;
padding: 5px 20px;
background: #e1a;
cursor: pointer;
}
/* Estilo botón cuando su INPUT está seleccionado */
input[id^="spoiler"]:checked + label {
color: #333;
background: #ccc;
}
/* Estilo caja SPOILER (inicialmente oculto) */
input[id^="spoiler"] ~ .spoiler {
width: 90%;
height: 0;
overflow: hidden;
opacity: 0;
margin: 10px auto 0;
}
/* Estilo caja SPOILER cuando su INPUT está seleccionado */
input[id^="spoiler"]:checked + label + .spoiler{
height: auto;
opacity: 1;
}


Como veis, en primer lugar ocultamos el input para que el botón radio no se vea y lo siguiente, menos relevante, es dar estilo a la etiqueta label que servirá de botón.

Con la tercera regla empieza el truco, aunque de momento sólo nos sirve para cambiar el aspecto del botón o label cuando su input precedente está seleccionado, en el ejemplo con un cambio de color.

Digo que aquí empieza el truco porque aunque esto no oculta ni revela nada, ya se puede ver cómo se controla eso. Podéis ver un input[id^="spoiler"]:checked + label que traducido quiere decir "selecciona los INPUT con una ID cuyos primeros caracteres sean SPOILER y si están seleccionados (CHECKED), a la etiqueta LABEL que hay justo a continuacion dale las siguientes propiedades..."

De la misma manera, las dos últimas reglas nos sirven para dar estilo a la caja marcada con clase .spoiler. La penúltima para que inicialmente no se vea y la última para que se haga visible cuando su correspondiente input está pulsado.


Realmente a veces no sé si mis explicaciones sirven para aclarar o para confundir más, pero si es lo segundo, en este enlace tenéis un desarrollo en CodePen para que podáis experimentar y que además incluye algo de estilo extra para dejar todo el conjunto más mono... tal que así:

Esta es una manera de ocultar cierta información hasta que el usuario hace clic en un botón para visualizarla. Con un segundo clic el spoiler se pliega de nuevo y vuelve a no ser visible.

Y sin ningún problema permite añadir varios botones y contenidos de este tipo simplemente cambiando el valor de la ID de cada par input-label asociados.

Lo que ha sufrido Brasil en este pasado mundial de fútbol...

¿Vemos otro post al azar por si le encuentras utilidad o quizás prefieres ser más metódico y suscribirte a nuestras entradas por correo? También puedes imprimir este artículo y por supuesto compartirlo en redes sociales si fue de tu agrado.

Compartir
Copy URL

Y muchos más artículos interesantes si nos sigues en...

follow us in feedly

41 comentarios :

  1. Curioso, yo también estuve haciendo pruebas sobre este tema, lo único que me chirría es el tema de la semántica. Incluso usándolo dentro de un formulario. Manías mias supongo.

    ResponderEliminar
  2. Hola Oloman esta buena la idea para crear spoiler con imput y ocultar algunos elementos, usando solo CSS.
    Me ha gustado la frase que acompaña tu segundo ejemplo.
    Saludos.

    ResponderEliminar
  3. Saludos Oloman... Viendo esto se me viene a la cabeza muchas ideas que me gustaría implementar en mi Blog... una de ellas es : como se haría para que los spoliers no se vean Verticalmente si no Horizontalmente?... que Atributo debería de cambiarle o Agregarle.?... desde ya Muchas Gracias por estar Nutriéndonos con Tus conocimientos del CSS ... un Abrazo !!!!!!!

    ResponderEliminar
    Respuestas
    1. Los que puse son horizontales, pero es que no imagino como es eso de ponerlos en vertical si es lo que quieres decir. De todas formas, si accedes al CodePen que enlacé, tú mismo puedes cambiar valores e ir viendo como queda, hasta que des con tu propio estilo.

      Eliminar
  4. Hola holoman, amigo necesito que me ayudes con mi blog.

    tengo un problema con mis imagenes, y es que yo quiero que las imagenes en el index se muestren con zoom, por ejemplo la foto tuya que sale en los comentarios supongamos que es de una entrada y quieres que dentro de la entrada de vea completa y en el index se haga zoom a tu cara solamente y que aunque le pongas una dimension con width alto o height alto no se distorcione.

    aca hice un ejemplo con photoshop, hay dos ejemplos uno con la imagen distorcionada y uno como lo quiero.

    http://3.bp.blogspot.com/-38NuX7DFBa4/U9Zv3ao-RXI/AAAAAAAAAmQ/USGMGSScGyY/s1600/ejemplo.jpg

    ResponderEliminar
    Respuestas
    1. Tienes un sistema de sumarios muy popular Kelvin, pero ese que dices es uno de sus problemas, que distorsiona las imágenes. Prueba a cambiarlo por este otro que es una evolución que construí hace un tiempo.

      Eliminar
    2. un millon de gracias amigo, solucione el problema y tambien me ayudo a solucionar un problema de imagenes a escala que tenia.

      Eliminar
    3. Hola oloman, disculpa las molestias amigo, pero aun tengo un problema y es que las imagenes se enfocan demasiado y en la mayoria no se puede observar el contenido de las imagenes, me gustaria reducir el enfoque, he intentado de mil formas y no puedo.

      Eliminar
    4. Sí, tengo una solución ideal que descubrí después de escribir el artículo al que te remití. Incluye la última línea que pongo a continuación:
      .miniaturas {
      width: 125px;
      height: 125px;
      background: no-repeat scroll 50% 40% #eeeeee;
      background-size: cover;
      }

      Eliminar
  5. Hola Oloman. Su blog es excelente! Felicidades gran trabajo.

    Me gustaría hacer ese efecto de "Desplegar" en el sidebar (columna izquierda). Pero antes tengo que resolver unos problemitas que me hago con width (ancho) del blog.
    Mi objetivo es que el blog quede con unos anchos de:
    columna izquierda: width: 20%
    columna del centro width: 80%
    Pero aún no puedo, ¿podría ayudarme?
    Los codigos que tengo son:

    /* Columns
    ----------------------------------------------- */
    .main-outer {
    background: #f2f2f2;
    margin-top: 5px;
    }

    .main-inner .fauxcolumn-left-outer {
    position: fixed;
    top: 0px;
    border-right:1px dashed white;
    border-bottom: 2px solid gray;
    background: black;
    }

    .main-inner .column-left-inner{
    position: fixed;
    top:20px;
    }

    .column-center-outer {
    margin-left: 50px;
    width: 80%;
    top: 0px;
    }

    #sidebar-left-1 {
    width: 258px;
    background: black;
    }

    body {
    min-width: 0%;
    }

    .content-outer, .content-fauxcolumn-outer, .region-inner {
    min-width: 100%;
    max-width: 100%;
    _width: 100%;
    }

    .main-inner .columns {
    padding-left: 20%;
    padding-right: 0%;
    }

    .main-inner .fauxcolumn-center-outer {

    left: 20%;
    right: 0%;
    /* IE6 does not respect left and right together */
    _width: expression(this.parentNode.offsetWidth -
    parseInt("$(main.column.left.width)") -
    parseInt("$(main.column.right.width)") + 'px');
    }

    .main-inner .fauxcolumn-left-outer {
    width: 20%;
    }

    .main-inner .fauxcolumn-right-outer {
    width: 0%;
    }

    .main-inner .column-left-outer {
    width: 20%;
    right: 12%;
    }

    .main-inner .column-right-outer {
    width: 0%;
    margin-right: 0%;
    }

    #layout {
    min-width: 0;
    }

    #layout .content-outer {
    min-width: 0;
    width: 800px;
    }

    #layout .region-inner {
    min-width: 0;
    width: auto;
    }

    /* Fin
    ----------------------------------------------- */

    Gracias

    ResponderEliminar
    Respuestas
    1. Eso tiene pinta de ser una plantilla de las del "nuevo diseñador", que para mí son una pesadilla. Sin embargo tienen la ventaja de que precisamente el ancho lo puedes regular desde dicho diseñador ¿has probado desde ahí?

      Eliminar
    2. Si, es del "nuevo diseñador". Bueno intentaré regular el ancho desde el diseñador.
      Saludos.

      Eliminar
  6. ¿Se puede modificar el css mediante javascript y cookies?

    ResponderEliminar
  7. Así, como pregunta absoluta, la respuesta es sí. Y si te refieres a este cacharrito en concreto, también.

    JavaScript tiene una instrucción que es .style con la que podrás -después de cargarlo- cambiar el estilo de cualquier objeto, aunque lo más práctico sería crear clases nuevas para un segundo estilo y luego cambiar esa clase con removeClass y addClass.

    Como las cookies también se pueden gestionar con JavaScript sólo sería cuestión de controlarlas y según el contenido de la cookie, poner una clase u otra.

    ResponderEliminar
  8. Saludos Oloman... por aca poniendote un pequeño pereke... puse el spoiler en una entrada y le puse un nombre al spoiler.. pero al abrir sigue con el mismo nombre... como cambio esa parte ahi?.. ejemplo:

    me gustaria que fuera asi: Clik Para Mostrar Contenido.. el user da clik y deberia quedar : Clik Para ocultar Contenido despues de mostrar el contenido.. ... xd espero hayas entendido lo que escribi... jejejejeje un Abrazo y Gracias ...
    mi blog. y diculpa la molestia y el span:
    http://joralgom1.blogspot.com/

    ResponderEliminar
    Respuestas
    1. No te sabría decir exactamente porque sin JavaScript habría que complicar este código, sobre todo si hay muchos "spoilers" por página, pero en un principio se me ocurre que se podría hacer añadiendo un :before a cada LABEL y que desde ahí se rellenara el texto con un CONTENT. Luego, para el mismo selector pero con el CHECKED se cambiaría el contenido del CONTENT.

      Eliminar
  9. Repito el comentario que lo tenía escrito y se me borró :(

    Lo primero, MUY útil el artículo.

    ¿Sería posible ampliar la funcionalidad de dicho código abriendo una web en una nueva ventana al pulsar sobre spoiler? Lo he probado con onclick y href pero "casca" la aplicación.

    Aprovecho para añadirte en Google+ ya que ha sido un gran hallazgo este blog!!

    Saludos.

    ResponderEliminar
    Respuestas
    1. Hola. Se podría generar una especie de "doble enlace", de manera que se abriera ese spoiler para mostrar la información oculta y que al mismo tiempo se abriera una ventana con un enlace real, pero no con este sistema basado en INPUT. Para eso ya tendrías que usar JavaScript y no sólo CSS.

      Eliminar
  10. Hola Oloman :)

    ¿Tu sabes como crear este efecto en todas las entradas de la página de inicio?, me explicaré... Tengo muchas entradas y quiero que todas se muestren en la página de inicio, pero, para que la página no sea tan larga quiero tener cada entrada con un botón de despliegue/pliegue. Ya no quiero tener que mostrar solo unas cuantas entradas en la página inicio, ni tampoco quiero seguir usando el típico "Read More", quisiera tener algo novedoso y original como el pliegue/despliegue de entradas!!

    ¿Que dices? :)
    Muchas gracias bro :D

    ResponderEliminar
    Respuestas
    1. Aunque no es necesario que sean con botón, podría ser que solo con dar clic se puedan desplegar/plegar cada entrada. Gracias :)

      Eliminar
    2. Hola Joan. Si buscas en mi blog con la palabra "desplegable", verás que te salen varios sistemas con lo que poder hacer lo que quieres. Quizás el que esté más cerca de lo que me explicas sería Más en menos espacio. Secciones desplegables., aunque tendrías que adaptarlo para las entradas.

      Eliminar
    3. Hola Oloman. No quisiera cambiarle el estilo a mi blog o ponerlo mas pesado con gadgets nuevos, solo quería agregar un link desplegable al titulo de las entradas sin necesidad de moverlas ni cambiarles el estilo, es decir, que el blog continuara igual pero ya no se vería el contenido de las entradas solo se vería el titulo y al darle clic se expandiría y mostraría el contenido en vez de llevarlo a la url de la entrada.

      Este es mi blog: blog.circulowh.com.co

      Talvez es mas complejo de lo que pensé, pero te agradezco mucho! ;)

      Eliminar
    4. Pues sí Joan, es más complejo de lo que pensaste. Para hacer eso que dices sin llevarlo a la URL de la entrada tendrías que cargar varias entradas COMPLETAS por página, pues así sería la única forma de hacerlas visibles al pinchar... y eso no es fácil, no.

      Si no quieres hacerlo más pesado lo mejor es que no lo toques. Cada cosa que se añade, por narices pesa algo.

      Eliminar
  11. Hola,

    Tengo un problema con tu código. El problema es que en el navegador Safari no funciona y yo uso Mac, por lo que el problema es constante ya que no abre el desplegable.

    Saludos!

    ResponderEliminar
    Respuestas
    1. Hola IndyPropMaker

      ¿Quieres probar a usar estos dos selectores en lugar de los dos últimos que puse (input[id^="spoiler"] + label + .spoiler / input[id^="spoiler"]:checked + label + .spoiler)?

      input[id^="spoiler"]:checked ~ .spoiler

      input[id^="spoiler"] ~ .spoiler

      Básicamente se trata de cambiar el "+ label +" por un símbolo "~".

      Por favor dime si funciona para actualizar el post (no tengo MAC).

      Eliminar
  12. Muchas gracias por contestar tan rápido. Ya muestra la capa al clickar, pero ahora el problema está en que pulsando el primer input muestra las dos capas ocultas. Pulsando el último inpuct lo hace bien, sólo muestra la capa de abajo.

    Saludos!

    ResponderEliminar
    Respuestas
    1. Definitivamente estoy torpe. Debe ser así, sólo cambiando el penúltimo selector. Este:

      /* Estilo caja SPOILER (inicialmente oculto) */
      input[id^="spoiler"] ~ .spoiler {
      width: 90%;
      height: 0;
      overflow: hidden;
      opacity: 0;
      margin: 10px auto 0;
      }


      A ver qué tal ahora.

      Eliminar
  13. Ahora va a la perfección. Responde muy bien. Creo que ya lo has clavado :)

    Muchas gracias!

    ResponderEliminar
    Respuestas
    1. Gracias porque no podía probar en MAC. Ya lo cambio en el post ;)

      Eliminar
  14. Buenos dias, he colocado dos botones (uno lado del otro) y todo bien. El problema es que cuando coloco un tercero debajo del primero no me aparece la mano sobre el boton para poder abrir el contenido. Puedes ayudarme?. Como siempre a agradecido por tu ayuda.

    ResponderEliminar
  15. Oloman disculpa ya lo he solucionado

    ResponderEliminar
    Respuestas
    1. Espero que seas el que comento como Unknown y luego como Pepa ;)

      Eliminar
  16. Esta genial, buen aporte!
    Una sola pregunta muy concreta...

    Si tengo spoiler1 y spoiler2 y tengo spoiler1 visible porque lo cliquié...
    ¿Cómo hago para que al clickear spoiler2 se me cierre el spoiler1 que previamente yo había clikeado y se me estaba mostrando?
    Esto para evitar tener por ejemplo un listado de preguntas y que la pagina se te vaya laaargo.. gracias!

    ResponderEliminar
    Respuestas
    1. Hola. Con este sistema, el único apaño que podrías hacer sería cambiar el tipo de botón de "checkbox" a "radio" y a cada uno añadirle el mismo name.

      De esta manera el primero sería así:
      <input type="radio" name="radio" id="spoiler1">
      y el segundo igual pero con id="spailer2".

      El inconveniente en este caso es que siempre se quedaría uno abierto.

      Eliminar
  17. Oloman necesitaria que al hacer clik en un botom y abrirse el contenido, éste apareciese encima del siguiente boton que tengo debajo. El caso es que me sale por debajo y queda mal.
    Muchas graiuas como siempre

    ResponderEliminar
    Respuestas
    1. Hola Ferran. Tendría que ver qué código utilizaste y cómo lo incluiste en tu sitio.

      Eliminar
  18. Hola, muchas gracias por compartir tus conocimientos. Una pregunta, como puedo hacer lo de tu post, pero que ademas cuando presione el boton, se abra un enlace en otra ventana o pestaña. Asi como una publicidad? Gracias....

    ResponderEliminar
    Respuestas
    1. Con este sistema no se puede Iron Man. El problema es que sólo utiliza CSS y por tanto no hay posibilidad de insertar un enlace. Para hacer algo así tendrías que recurrir a JavaScript.

      Eliminar
  19. hola excelente, soy inquieto en estas cosas que ustedes dominan, lo admiro Oloman, puedes darme el codigo completo de un spoiler con imagen integrada, gracias

    ResponderEliminar
    Respuestas
    1. ¿Una imagen integrada? ¿Qué quieres decir exactamente?

      Eliminar