Efecto “Before / After” Responsive

HTML5 incorpora nuevos tipos de input. Uno de ellos, range, es el protagonista de esta demo. Con él podemos seleccionar y modificar valores dentro de un rango. En este artículo vamos a usar HTML HTML5, CSS, CSS3 y algo de Javascript.

Lo que haremos será poner una imagen de fondo, encima la otra imagen y encima del todo el input con el que modificaremos el ancho de la segunda imagen dejando que se muestre la primera. Vamos a ello…

Ver Demo

HTML

El HTML es muy simple y sin apenas contenido, ya que todas las imágenes se muestran como fondos usando CSS. El total de elementos son un div, un figure, otro div y un input.

<div id="contenedor">
  <figure>
    <div id="separador"></div>
  </figure>
  <input type="range" value="50" min="0" max="100" id="deslizador" />
</div>

contenedor
Como su nombre indica, este elemento div contiene todo lo demás y es donde pondremos las medidas generales del proyecto.

figure
Esta nueva etiqueta de HTML5 sirve para indicar que el elemento contiene una imagen, una foto o una ilustración… Nuestra etiqueta figure llevará de fondo la primera de las dos imágenes.

separador
Este elemento div lleva de fondo la segunda imagen y cambiando su ancho conseguiremos que se muestre una imagen o la otra.

input
Con su type=”range” será con lo que cambiaremos realmente el ancho del elemento anterior. Le añadiremos algunos atributos como value para darle un valor incial, min para el valor mínimo, y max para el valor máximo. También un id para luego “encontrarlo” desde Javascript.

Este es el código y el aspecto que tendrá el input por defecto (diferente en cada navegador).

<input type="range" value="50" min="0" max="100" id="deslizador"/>

Para apreciar su funcionamiento mueve el deslizador y observa este número: 50

CSS

Los estilos CSS son un poco más extensos:

#contenedor
En este elemento usaremos la unidad de medida vw que se refiere al viewport (la medida de la ventana) para darle dimensiones al proyecto. Las medidas en pixels corresponden al tamaño original de la imagen. Las imágenes con relaciones de aspecto diferentes requerirán diferentes valores de altura, más adelante veremos como calcularlos.

#contenedor { 
    height: 73.5vw;
    margin: 1vw auto;
    max-height: 750px;
    max-width: 1000px;
    overflow: hidden;
    width: 98vw;
}

figure
En este elemento añadimos la primera imagen de fondo. Establecemos el tamaño de fuente y el margen en 0 para eliminar todo el espacio del elemento.

figure { 
    background-image: url(//josetxu.com/html5/beforeafter-responsive/cocodrilo-01b.jpg); 
    background-size: cover;
    font-size: 0;
    height: 100%;
    margin: 0; 
    position: relative;
    width: 100%; 
}

#separador
Este elemento contiene la segunda imagen de fondo, le añadimos un borde derecho para marcar la diferencia entre las dos imagenes, un ligero sombreado y un ancho del 50% (inicialmente). También definimos aquí la animación del inicio con animation (que es opcional).

#separador {
    background-image: url(//josetxu.com/html5/beforeafter-responsive/cocodrilo-01a.jpg);
    background-size: cover;
    bottom: 0;
    border-right: 5px solid rgba(255,255,255,0.7);
    box-shadow: 10px 0 15px -13px #000;
    height: 100%;
    max-width: 98.6%;
    min-width: 0.6%;
    overflow: visible;
    position: absolute;
    width: 50%; 
    animation: figure 2s 1 normal ease-in-out 0.1s; 
    -webkit-animation: figure 2s 1 normal ease-in-out 0.1s; 
}

input
Básicamente lo que hacemos con el input es desactivar el estilo predeterminado de cada navegador y añadirle nuestros propios estilos, que serán; alto y ancho 100% y todo transparente. También lo posicionamos correctamente con margen negativo justo encima de la imagen, ya que inicialmente aparecerá a continuación (debajo) del elemento figure.

/*barra input */
input#deslizador {
    -moz-appearance: none;
    -webkit-appearance: none;
    border: none; 
    background: transparent;
    cursor: col-resize;
    height: 100vw;
    left: 0;
    margin: 0;
    outline: none; 
    padding: 0;
    position: relative;
    top: -100vw;
    width: 100%;
}

Algunos pseudo-elementos del input actúan como su barra de desplazamiento, su botón, su fondo, etc… Algunas de estas partes del elemento deben especificarse por separado para cada navegador.

/*barra input mozilla*/
input#deslizador::-moz-range-track { 
    background: transparent; 
}
/*barra input ie*/
input#deslizador::-ms-track {
    border: none; 
    background-color: transparent;
    height: 100vw; 
    left: 0; 
    outline: none; 
    position: relative;
    top: -100vw; 
    width: 100%;
    margin: 0;
    padding: 0;
    cursor: col-resize;
    color:transparent;
}
input#deslizador::-ms-fill-lower {
    background-color:transparent;
}
 
/*boton input chrome*/
input#deslizador::-webkit-slider-thumb {
    -webkit-appearance:none;
    height: 100vw;
    width: 0.5%;
    opacity: 0;
}
/*boton input mozilla*/
input#deslizador::-moz-range-thumb {
    -moz-appearance: none;
    height: 100vw;
    width: 0.5%;
    opacity: 0;
}   
/*boton input ie*/
input#deslizador::-ms-thumb {
    height: 100vw;
    width: 0.5%; 
    opacity:0;
}
input#deslizador::-ms-tooltip {
    display:none;
}

#separador::before
Utilizamos el pseudoelemento before del elemento separador para añadir las flechas centrales como imagen de fondo.

/*flechas*/
#separador::before {
    background: url(//josetxu.com/html5/beforeafter-responsive/flechas.png) no-repeat scroll 0 0 transparent;
    background-size:cover;
    content: " ";
    float: right;
    height: 64px;
    margin-right: -34px;
    position: relative;
    top: 46%;
    width: 64px;
}

@keyframes (opcional)
Con esta regla de CSS3 creamos una animación inicial que, junto a animation (también de CSS3), muestra al usuario el funcionamiento de la página al primer vistazo.

/*animacion*/
@keyframes figure {
  0% {width: 0%; }
  50% {width: 80%; }
  100% {width: 50%; }
}
/*animacion chrome*/
@-webkit-keyframes figure {
  0% {width: 0%; }
  50% {width: 80%; }
  100% {width: 50%; }
}

Javascript

En Javascript creamos la función beforeAfter que modificará el tamaño del elemento separador que contiene nuestra segunda imagen. Para ello seleccionamos el elemento con el método getElementById y ordenamos que su ancho sea igual al valor de la posición del input, valor que podemos modificar a nuestro antojo con un clic del ratón como hemos visto más arriba. Añadiremos el símbolo % a continuación para obtener una medida en porcentajes.

function beforeAfter() {
  document.getElementById('separador').style.width = document.getElementById('deslizador').value + "%";
}

No hay que olvidar llamar a la funcion beforeAfter en el evento oninput de nuestro input, y para un funcionamiento óptimo en Internet Explorer también añadimos la llamada a la función en el evento onchange.

<input type="range" value="50" min="0" max="100" id="deslizador" oninput="beforeAfter()" onchange="beforeAfter()" />

Tamaño de imágenes

Recuerda que si las imagenes cambian de tamaño hay que modificar las medidas del elemento contenedor cambiando los valores de la regla #contenedor en nuestro código CSS.
La fórmula es una simple regla de tres y es la siguiente:

Si te has quedado igual que estabas antes…

  • a es el ancho de tu imagen
  • b es el alto de tu imagen
  • c es el ancho del viewport (en principio no se debería tocar)
  • x es el alto del viewport

Aplicando la regla de tres:

c multiplicado por b y dividido por a nos dá como resultado x que es la medida que nos faltaba por averiguar, ya que las medidas de la imagen las pones tú y el ancho del viewport no lo deberías tocar. En el caso de que decidas cambiar el ancho del viewport el alto del mismo se ajustará automáticamente al aplicar la regla de tres.

(Estoy trabajando en una versión mejorada que automatizará este proceso).

Demo

Os dejo por aquí la demo para comprobar el funcionamiento, la demo está adaptada de una idea original de Dudley Storey. En Codepen podéis ver la demo a tamaño completo.

Ver Efecto Before/After Responsive de Josetxu (@josetxu) en CodePen.

… y el código completo para hacer pruebas:

<!DOCTYPE html>
<html lang="es">
  <head>
  <meta charset="UTF-8">
  <title>Before/After Responsive</title>
    <script type="text/javascript">
	function beforeAfter() {
	  document.getElementById('separador').style.width = document.getElementById('deslizador').value + "%";
	}
    </script>
    <style type="text/css">
	#contenedor {
	  height: 73.5vw;
	  margin: 1vw auto;
	  max-height: 750px;
	  max-width: 1000px;
	  overflow: hidden;
	  width: 98vw;
	}
	#contenedor figure {
	  background-image: url(https://josetxu.com/html5/beforeafter-responsive/cocodrilo-01b.jpg);
	  background-size: cover;
	  font-size: 0;
	  height: 100%;
	  margin: 0;
	  position: relative;
	  width: 100%;
	}
	#separador {
	  background-image: url(https://josetxu.com/html5/beforeafter-responsive/cocodrilo-01a.jpg);
	  background-size: cover;
	  bottom: 0;
	  border-right: 5px solid rgba(255,255,255,0.7);
	  box-shadow: 10px 0 15px -13px #000;
	  height: 100%;
	  max-width: 98.6%;
	  min-width: 0.6%;
	  overflow: visible;
	  position: absolute;
	  width: 50%;
	  animation: figure 2s 1 normal ease-in-out 0.1s;
	  -webkit-animation: figure 2s 1 normal ease-in-out 0.1s;
	}
	/*barra input */
	input#deslizador {
	  -moz-appearance: none;
	  -webkit-appearance: none;
	  border: none;
	  background: transparent;
	  cursor: col-resize;
	  height: 100vw;
	  left: 0;
	  margin: 0;
	  outline: none;
	  padding: 0;
	  position: relative;
	  top: -100vw;
	  width: 100%;
	}
	/*barra input mozilla*/
	input#deslizador::-moz-range-track {
	  background: transparent;
	}
	/*barra input ie*/
	input#deslizador::-ms-track {
	  border: none;
	  background-color: transparent;
	  height: 100vw;
	  left: 0;
	  outline: none;
	  position: relative;
	  top: -100vw;
	  width: 100%;
	  margin: 0;
	  padding: 0;
	  cursor: col-resize;
	  color:transparent;
	}
	input#deslizador::-ms-fill-lower {
	  background-color:transparent;
	}
	 
	/*boton input chrome*/
	input#deslizador::-webkit-slider-thumb {
	  -webkit-appearance:none;
	  height: 100vw;
	  width: 0.5%;
	  opacity: 0;
	}
	/*boton input mozilla*/
	input#deslizador::-moz-range-thumb {
	  -moz-appearance: none;
	  height: 100vw;
	  width: 0.5%;
	  opacity: 0;
	}  
	/*boton input ie*/
	input#deslizador::-ms-thumb {
	  height: 100vw;
	  width: 0.5%;
	  opacity:0;
	}
	input#deslizador::-ms-tooltip {
	  display:none;
	}
	/*flechas*/
	#separador::before {
	  background: url(https://josetxu.com/html5/beforeafter-responsive/flechas.png) no-repeat scroll 0 0 transparent;
	  background-size:cover;
	  content: " ";
	  float: right;
	  height: 64px;
	  margin-right: -34px;
	  position: relative;
	  top: 46%;
	  width: 64px;
	}
	/*animacion*/
	@keyframes figure {
	  0% {width: 0%; }
	  50% {width: 80%; }
	  100% {width: 50%; }
	}
	/*animacion chrome*/
	@-webkit-keyframes figure {
	  0% {width: 0%; }
	  50% {width: 80%; }
	  100% {width: 50%; }
	}
    </style>
  </head>
<body>
  <div id="contenedor">
    <figure>
      <div id="separador"></div>
    </figure>
    <input type="range" value="50" min="0" max="100" id="deslizador" oninput="beforeAfter()" onchange="beforeAfter()" />
  </div>
</body>
</html>
Datos de CANIUSE.COM