javascript - span - CSS revela de la animación de la esquina
span style font (5)
Estoy tratando de lograr un efecto de animación de la siguiente manera:
Cuando se muestra un banner, la esquina inferior derecha del siguiente banner debe estar visible. Al hacer clic en esta esquina, debería ocultar el banner actual y revelar el siguiente.
Mi marca actual es la siguiente:
<div class="banners">
<div class="image active" style="background-color: red;">
<div class="corner"></div>
</div>
<div class="image" style="background-color: blue;">
<div class="corner"></div>
</div>
</div>
CSS de la siguiente manera: Observe que usé clip-path
para crear la esquina:
.banners {
width: 800px;
height: 600px;
}
.image {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.image.active {
z-index: 1;
clip-path: polygon(100% 0, 100% 65%, 60% 100%, 0 100%, 0 0);
}
.corner {
width: 50%;
height: 50%;
position: absolute;
right: 0;
bottom: 0;
}
JS:
$(document).ready(function () {
$(''.corner'').click(function() {
$(''.image.active'').removeClass(''active'');
$(this).parent().addClass(''active'');
});
});
Aquí hay un JSFiddle de todo el código anterior: https://jsfiddle.net/cqqxjjgu/
Un problema inmediato con esto es que debido a que estoy usando z-index
para especificar que el banner ''activo'' actual debería tener prioridad, cuando se elimina la clase active
, solo se muestra el siguiente banner inmediatamente, por lo que idealmente el z-index
debería ser cambiado una vez que la animación ha terminado.
¿Alguien tiene alguna idea de cómo puedo lograr esto? Idealmente, necesito una solución de navegador cruzado (no muy preocupado por IE <10).
Esta es una respuesta sin el uso de clip-path
, porque la compatibilidad del navegador con elementos DOM distintos a svg
es baja.
Ahora veo que Vadim tuvo la misma idea que yo con el contenedor girado (no había vuelto a revisar aquí hasta que terminé), pero por lo que puedo decir, todavía hay suficientes diferencias entre nuestras respuestas para justificar la publicación de mi solución:
$(document).ready(function() {
$(".slider").on("click",".next",function() {
if ($(this).prev().length) {$(this).prev().removeClass("curr");} else {$(this).siblings().last().removeClass("curr");} //deactivate current slide
if ($(this).next().length) {$(this).next().addClass("next");} else {$(this).siblings().first().addClass("next");} //prepare slide that follows next slide
$(this).removeClass("next").addClass("curr"); //activate next slide
});
});
.slider, .slider .img {
width: 55vw;
height: calc(55vw / 16*9);
background: #000 center/contain no-repeat;
}
.slider {position:relative; margin:0 auto; overflow:hidden;}
.slider .slide {
position: absolute;
z-index: 0;
width: 250%;
height: 0;
transform: translateX(-50%) rotate(-20deg);
transform-origin: 50% 0;
transition:z-index 0s 0.7s, height 0.7s;
overflow: hidden;
}
.slider .slide.next {z-index:1; height:155%; opacity:0.5; transition:z-index 0s 1.1s, height 0s 0.7s; cursor:pointer;}
.slider .slide.curr {z-index:2; height:135%; opacity:1.0; transition:z-index 0s 1.1s, height 0.4s 0.7s, opacity 0.7s;}
.slider .slide .img {margin-left:50%; transform:rotate(20deg); transform-origin:0 0;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="slider">
<div class="slide curr"><div class="img" style="background-image:url(https://placeimg.com/640/480/animals);"></div></div>
<div class="slide next"><div class="img" style="background-image:url(https://placeimg.com/640/480/people);"></div></div>
<div class="slide"><div class="img" style="background-image:url(https://placeimg.com/640/480/nature);"></div></div>
<div class="slide"><div class="img" style="background-image:url(https://placeimg.com/640/480/tech);"></div></div>
<div class="slide"><div class="img" style="background-image:url(https://placeimg.com/640/480/arch);"></div></div>
</div>
jsfiddle: https://jsfiddle.net/tq2hw7b9/5/
- En lugar de
clip-path
declip-path
solo cambio laheight
de los contenedores de diapositivas, utilizando latransition
para los efectos de animación.
PROBLEMAS DE IE
Desafortunadamente, como es habitual, los procesos de IE transform:rotate()
diferente a otros navegadores. Visualmente, las rotaciones ocurren, pero el navegador aún parece reservar el espacio original de los elementos, por lo que no se puede hacer clic en la esquina expuesta de la siguiente diapositiva porque la diapositiva actual la "cubre". Usar el prefijo -ms-
o -webkit-
no hace una diferencia.
El siguiente fragmento de código funciona en IE:
$(document).ready(function() {
$(".slider .corner").on("click",function() {
var $next = $(this).siblings(".next");
if ($next.prev().length) {$next.prev().removeClass("curr");} else {$next.siblings(".slide").last().removeClass("curr");} //deactivate current slide
if ($next.next(".slide").length) {$next.next().addClass("next");} else {$next.siblings().first().addClass("next");} //prepare slide that follows next slide
$next.removeClass("next").addClass("curr"); //activate next slide
});
});
.slider, .slider .img {
width: 55vw;
height: calc(55vw / 16*9);
background: #000 center/contain no-repeat;
}
.slider {position:relative; margin:0 auto; overflow:hidden;}
.slider .corner {
position: absolute;
z-index: 3;
bottom: 0;
right: 0;
width: 100%;
height: 21%;
transform: rotate(-20deg);
transform-origin: 100% 0;
cursor: pointer;
}
.slider .slide {
position: absolute;
z-index: 0;
width: 250%;
height: 0;
transform: translateX(-50%) rotate(-20deg);
transform-origin: 50% 0;
transition:z-index 0s 0.7s, height 0.7s;
overflow: hidden;
}
.slider .slide.next {z-index:1; height:155%; opacity:0.5; transition:z-index 0s 1.1s, height 0s 0.7s;}
.slider .slide.curr {z-index:2; height:135%; opacity:1.0; transition:z-index 0s 1.1s, height 0.4s 0.7s, opacity 0.7s;}
.slider .slide .img {margin-left:50%; transform:rotate(20deg); transform-origin:0 0;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="slider">
<div class="slide curr"><div class="img" style="background-image:url(https://placeimg.com/640/480/animals);"></div></div>
<div class="slide next"><div class="img" style="background-image:url(https://placeimg.com/640/480/people);"></div></div>
<div class="slide"><div class="img" style="background-image:url(https://placeimg.com/640/480/nature);"></div></div>
<div class="slide"><div class="img" style="background-image:url(https://placeimg.com/640/480/tech);"></div></div>
<div class="slide"><div class="img" style="background-image:url(https://placeimg.com/640/480/arch);"></div></div>
<div class="corner"></div>
</div>
jsfiddle: https://jsfiddle.net/8ggqndj1/
- Agregué un
<div class="corner">
extra que cubre todas las diapositivas. - El controlador de clics en JS ahora está vinculado a este
.corner
, y al comienzo del controlador se almacena una referencia a la siguiente diapositiva en una variable, que se usa en el resto del código. - En CSS también hay una nueva regla para el
.corner
.
DIAPOSITIVO-ARRAY EN JS
Eche un vistazo al fragmento de código a continuación, para ver una lista de diapositivas en JS (si alguien lo necesita):
$(document).ready(function() {
var slides = [
2, //index for next slide
"https://placeimg.com/640/480/animals",
"https://placeimg.com/640/480/people",
"https://placeimg.com/640/480/nature",
"https://placeimg.com/640/480/tech",
"https://placeimg.com/640/480/arch"
];
//INITIALIZE SLIDESHOW--------------------
$(".slider").css("background-image","url("+slides[2]+")"); //set next slide
$(".slider .current .img").css("background-image","url("+slides[1]+")"); //set current slide, and set slide-height to slideshow-height
//SLIDESHOW CLICK-HANDLER--------------------
$(".slider .current").on("click",function(e){e.stopPropagation();});
$(".slider").on("click",function() {
$(this).children(".current").animate({height:0},700,function(){
$(this).children(".img").css("background-image","url("+slides[slides[0]]+")"); //set the current slide to the next slide
$(this).css("height","155%"); //cover entire slide
if (slides[0]==slides.length-1) {slides[0]=1;} else {++slides[0];} //increase/loop index for next slide
$(this).parent().css("background-image","url("+slides[slides[0]]+")"); //set the next slide to the next slide after that
$(this).animate({height:"135%"},400); //reveal corner for next slide
});
});
});
.slider, .slider .img {
width: 55vw;
height: calc(55vw / 16*9);
background: #000 center/contain no-repeat;
}
.slider {margin:0 auto; cursor:pointer; overflow:hidden;}
.slider .current {
width: 250%;
height: 135%;
transform: translateX(-50%) rotate(-20deg);
transform-origin: 50% 0;
overflow: hidden;
cursor: default;
}
.slider .current .img {margin-left:50%; transform:rotate(20deg); transform-origin:0 0;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="slider"><div class="current"><div class="img"></div></div></div>
jsfiddle: https://jsfiddle.net/qghv9bnh/13/
- Puede que tenga algunas preferencias para algunos, aunque creo que mi primera solución es mucho más limpia, más rápida y flexible para agregar diapositivas adicionales (ciertamente cuando se usa un CMS como WordPress o Joomla):
- Las imágenes solo se cargan cuando realmente usa el control deslizante, por lo que los usuarios ahorran ancho de banda para cada diapositiva en la que no hacen clic.
- El HTML es muy conciso y nunca crecerá sin importar cuántas diapositivas tenga, por lo que su HTML se verá más limpio (pero si usa PHP para incluirlas, se verá igual de limpio, incluso más limpio).
Realmente no puedo pensar en otra cosa, como dije, prefiero la primera. Pero sin embargo, puede ser útil para alguien.
Esta muestra funciona en Firefox, Chrome, IE.
Para cambiar la regla de cambio de transition
$(document).ready(function () {
$(''.angle'').click(function() {
var $parent = $(this).parent();
$parent.removeClass("current");
if ($parent.next().length){
$parent.next().addClass("current");
} else {
$parent.prevAll().last().addClass("current");
}
});
});
body{
height:100%;
width:100%;
}
.slideShow {
width: 100%;
height: 100%;
}
.image {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
overflow:hidden;
z-index:1;
transition:z-index 2s step-end, 1s opacity 1s ease-in-out;
text-align:center;
opacity:0;
background-size:100% 100%;
background-attachment:fixed;
}
.image.current{
opacity:1;
z-index:2;
transition:z-index 2s step-end, 0s opacity 0s;
}
.angle {
width: 200%;
height: 200%;
position: absolute;
top: -100%;
left: -100%;
clip-path: polygon(100% 0, 0 70%, 0 100%, 100% 100%, 100% 0, 100% 0);
z-index:3;
margin-left:150%;
margin-top:150%;
transition:2s top ease-in-out, 2s left ease-in-out, 0s margin 2s;
background-size:100% 100%;
background-attachment:fixed;
}
.image.current .angle{
top:0;
left:0;
margin-top:0;
margin-left:0;
transition:0s top ease-in-out 1s, 0s left ease-in-out 1s, 2s margin ease-in-out 1s;
}
.main{
color:#FFF;
display:inline-block;
vertical-align:middle;
font-family:arial;
text-transform:uppercase;
font-size:24px;
}
.middle{
vertical-align:middle;
width:0;
height:100%;
display:inline-block;
}
.image1, .image3 .angle{
background-image: url(http://i3.imgbus.com/doimg/4c5o0m8m6o5n4e0.png);
}
.image1 .angle, .image2{
background-image:url(http://i4.imgbus.com/doimg/1c7obm6m1o3nbb0.png);
}
.image2 .angle, .image3{
background-image:url(http://i3.imgbus.com/doimg/ccbo5m2m8o8n759.jpg);
}
<div class="slideShow">
<div class="image image1 current">
<div class="main">
</div>
<div class="middle"></div>
<div class="angle" style="background-color: cyan;"></div>
</div>
<div class="image image2" style="background-color: cyan;">
<div class="main">
</div>
<div class="middle"></div>
<div class="angle" style="background-color: magenta;"></div>
</div>
<div class="image image3" style="background-color: magenta;">
<div class="main">
</div>
<div class="middle"></div>
<div class="angle"></div>
</div>
</div>
También puedes usar los softwares SildeShow Maker como Amazing Slider .
Fácil descarga, fácil uso: enlace de descarga
Esto debería funcionar para cualquier navegador con soporte de transición: https://jsfiddle.net/freer4/cqqxjjgu/1/
Esencialmente, cree una diapositiva de portada muy grande, con el mismo color de fondo que la siguiente diapositiva, y colóquela sobre la diapositiva actual. Luego desaparece para revelar la siguiente diapositiva.
Así que un pequeño ajuste en el html:
<div class="banners">
<div class="image active" style="background-color: black;">
<div class="content">
Slide 1
</div>
<div class="spanner"></div>
<div class="corner" style="background-color: cyan;"></div>
</div>
<div class="image" style="background-color: cyan;">
<div class="content">
Slide 2
</div>
<div class="spanner"></div>
<div class="corner" style="background-color: magenta;"></div>
</div>
<div class="image" style="background-color: magenta;">
<div class="content">
Slide 3
</div>
<div class="spanner"></div>
<div class="corner" style="background-color: black;"></div>
</div>
</div>
Cambie jQuery para seleccionar la siguiente diapositiva o la primera si no hay más:
$(document).ready(function () {
$(''.corner'').click(function() {
var $parent = $(this).parent();
$parent.removeClass("active");
if ($parent.next().length){
$parent.next().addClass("active");
} else {
$parent.prevAll().last().addClass("active");
}
});
});
Y configura algunas transiciones complejas para ajustar el tiempo de:
.image {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
overflow:hidden;
z-index:1;
transition:z-index 2s step-end, 1s opacity 1s ease-in-out;
text-align:center;
opacity:0;
}
.image.active{
opacity:1;
z-index:2;
transition:z-index 2s step-end, 0s opacity 0s;
}
.corner {
width: 200%;
height: 200%;
position: absolute;
top: -100%;
left: -100%;
clip-path: polygon(100% 0, 0 70%, 0 100%, 100% 100%, 100% 0, 100% 0);
z-index:3;
margin-left:150%;
margin-top:150%;
transition:2s top ease-in-out, 2s left ease-in-out, 0s margin 2s;
}
.image.active .corner{
top:0;
left:0;
margin-top:0;
margin-left:0;
transition:0s top ease-in-out 1s, 0s left ease-in-out 1s, 2s margin ease-in-out 1s;
}
Aparte: este ejemplo es completamente flexible (no le importa el tamaño):
.banners {
width: 100%;
height: 100%;
}
O con imágenes: https://jsfiddle.net/freer4/ens7caaL/
Esto funcionará en todas partes, incluso en IE / Edge. Se basa en las transition
CSS y en la sustitución de clases de CSS a través de JavaScript.
Estoy usando un rectángulo girado para recortar imágenes. Demostración del principio principal (contiene muchos valores codificados previamente, calculados previamente):
*,
*:before,
*:after {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
div {
width: 300px;
height: 200px;
border: 1px solid red;
position: relative;
}
div:after {
content: "";
position: absolute;
left: -86.6px;
top: 50px;
width: 359.8px;
height: 240px;
transform-origin: 0 0;
transform: rotate(-30deg);
border: 1px solid blue;
}
<div></div>
Demostración principal (hay muchos valores codificados). Para comprender mejor cómo funciona, puede agregar un border
a .slide-cropper
:
$(document).ready(function() {
$(".banners").on("click", ".slide-cropper.next .slide-content", function() {
var $container = $(this).closest(".slide");
$(".slide-cropper").removeClass("prev")
.removeClass("current")
.removeClass("next");
$(this).closest(".slide-cropper").addClass("current");
var $prevContainer;
if ($container.prev().length) {
$prevContainer = $container.prev();
} else {
$prevContainer = $container.siblings(":last");
}
$prevContainer.find(".slide-cropper").addClass("prev");
var $nextContainer;
if ($container.next().length) {
$nextContainer = $container.next();
} else {
$nextContainer = $container.siblings(":first");
}
$nextContainer.find(".slide-cropper").addClass("next");
});
});
*,
*:before,
*:after {
box-sizing: border-box;
}
/* all body styles are just for demo */
/* just centering the slider */
body {
margin: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.banners {
width: 300px;
height: 200px;
position: relative;
}
.slide {
width: 100%;
height: 100%;
}
.slide .slide-cropper {
position: absolute;
left: -86.6px;
top: 50px;
width: 359.8px;
height: 323.2px;
transform-origin: 0 0;
transform: rotate(-30deg);
overflow: hidden;
transition: height 2s linear;
}
.slide-content {
position: absolute;
background-size: 100% 100%;
left: 100px;
top: 0;
width: 300px;
height: 200px;
transform: rotate(30deg);
transform-origin: 0 0;
z-index: 0;
/* just styles for text */
/* using flexbox to center text */
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 3em;
}
.slide1 .slide-content {
background-image: url("https://i.stack.imgur.com/tt875.jpg");
}
.slide2 .slide-content {
background-image: url("https://i.stack.imgur.com/hzbmw.jpg");
}
.slide3 .slide-content {
background-image: url("https://i.stack.imgur.com/4UxLW.jpg");
}
.slide-cropper.prev {
height: 0;
z-index: 3;
}
.slide-cropper.current {
height: 240px;
transition-delay: 2s;
z-index: 2;
}
.slide-cropper.next {
z-index: 1;
}
/* Fix for IE */
.slide-cropper.current {
pointer-events: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="banners">
<div class="slide slide1">
<div class="slide-cropper current">
<div class="slide-content">
Slide 1
</div>
</div>
</div>
<div class="slide slide2">
<div class="slide-cropper next">
<div class="slide-content">
Slide 2
</div>
</div>
</div>
<div class="slide slide3">
<div class="slide-cropper">
<div class="slide-content">
Slide 3
</div>
</div>
</div>
</div>
Para entender cómo funciona, moví todos los cálculos a las variables CSS. AKA Propiedades personalizadas de CSS . Funcionan en muchos navegadores, pero no en combinación con la función de calc
CSS. Este ejemplo funciona perfectamente solo en Chrome, pero ayudará a comprenderlo y modificarlo (solo reemplace las variables CSS con valores codificados). También puede mover estos cálculos al preprocesador CSS o al código JavaScript.
$(document).ready(function() {
$(".banners").on("click", ".slide-cropper.next .slide-content", function() {
var $container = $(this).closest(".slide");
$(".slide-cropper").removeClass("prev")
.removeClass("current")
.removeClass("next");
$(this).closest(".slide-cropper").addClass("current");
var $prevContainer;
if ($container.prev().length) {
$prevContainer = $container.prev();
} else {
$prevContainer = $container.siblings(":last");
}
$prevContainer.find(".slide-cropper").addClass("prev");
var $nextContainer;
if ($container.next().length) {
$nextContainer = $container.next();
} else {
$nextContainer = $container.siblings(":first");
}
$nextContainer.find(".slide-cropper").addClass("next");
});
});
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
--width: 300px;
--height: 200px;
/* rotate for image cropping */
--rotate-angle: 30deg;
/* sin 30 degrees for image cropping */
--sin-rotate-angle: 0.5;
/* cos 30 degrees for image cropping */
--cos-rotate-angle: 0.8660254037844386;
/* clipper ratio for width, can be from 0 to 1 */
--clipper-ratio: 0.45;
--animation-timeout: 2s;
}
/* all body styles are just for demo */
/* just centering the slider */
body {
margin: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.banners {
width: var(--width);
height: var(--height);
position: relative;
}
.slide {
width: 100%;
height: 100%;
}
.slide .slide-cropper {
position: absolute;
left: calc(-1 * var(--height) * var(--sin-rotate-angle) * var(--cos-rotate-angle));
top: calc(var(--height) * var(--sin-rotate-angle) * var(--sin-rotate-angle));
width: calc(var(--height) * var(--sin-rotate-angle) + var(--width) * var(--cos-rotate-angle));
height: calc(var(--height) * var(--cos-rotate-angle) + var(--width) * var(--sin-rotate-angle));
transform-origin: 0 0;
transform: rotate(calc(-1 * var(--rotate-angle)));
overflow: hidden;
transition: height var(--animation-timeout) linear;
}
.slide-content {
position: absolute;
background-size: 100% 100%;
left: calc(var(--height) / 2);
width: var(--width);
height: var(--height);
transform: rotate(var(--rotate-angle));
transform-origin: 0 0;
z-index: 0;
/* just styles for text */
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 3em;
}
.slide1 .slide-content {
background-image: url("https://i.stack.imgur.com/tt875.jpg");
}
.slide2 .slide-content {
background-image: url("https://i.stack.imgur.com/hzbmw.jpg");
}
.slide3 .slide-content {
background-image: url("https://i.stack.imgur.com/4UxLW.jpg");
}
.slide-cropper.prev {
height: 0;
z-index: 3;
}
.slide-cropper.current {
height: calc(var(--height) * var(--cos-rotate-angle) + var(--clipper-ratio) * var(--width) * var(--sin-rotate-angle));
transition-delay: var(--animation-timeout);
z-index: 2;
}
.slide-cropper.next {
z-index: 1;
}
/* Fix for IE */
.slide-cropper.current {
pointer-events: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="banners">
<div class="slide slide1">
<div class="slide-cropper current">
<div class="slide-content">
Slide 1
</div>
</div>
</div>
<div class="slide slide2">
<div class="slide-cropper next">
<div class="slide-content">
Slide 2
</div>
</div>
</div>
<div class="slide slide3">
<div class="slide-cropper">
<div class="slide-content">
Slide 3
</div>
</div>
</div>
</div>
Para cambiar esto a pantalla completa, debe configurar --width: 100vw
y --height: 100vh
. (Por supuesto, entonces tendrás que reemplazar las variables CSS con valores codificados para que funcionen en todos los navegadores). Manifestación:
$(document).ready(function() {
$(".banners").on("click", ".slide-cropper.next .slide-content", function() {
var $container = $(this).closest(".slide");
$(".slide-cropper").removeClass("prev")
.removeClass("current")
.removeClass("next");
$(this).closest(".slide-cropper").addClass("current");
var $prevContainer;
if ($container.prev().length) {
$prevContainer = $container.prev();
} else {
$prevContainer = $container.siblings(":last");
}
$prevContainer.find(".slide-cropper").addClass("prev");
var $nextContainer;
if ($container.next().length) {
$nextContainer = $container.next();
} else {
$nextContainer = $container.siblings(":first");
}
$nextContainer.find(".slide-cropper").addClass("next");
});
});
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
--width: 100vw;
--height: 100vh;
/* rotate for image cropping */
--rotate-angle: 30deg;
/* sin 30 degrees for image cropping */
--sin-rotate-angle: 0.5;
/* cos 30 degrees for image cropping */
--cos-rotate-angle: 0.8660254037844386;
/* clipper ratio for width, can be from 0 to 1 */
--clipper-ratio: 0.45;
--animation-timeout: 2s;
}
/* all body styles are just for demo */
/* just centering the slider */
body {
margin: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.banners {
width: var(--width);
height: var(--height);
position: relative;
}
.slide {
width: 100%;
height: 100%;
}
.slide .slide-cropper {
position: absolute;
left: calc(-1 * var(--height) * var(--sin-rotate-angle) * var(--cos-rotate-angle));
top: calc(var(--height) * var(--sin-rotate-angle) * var(--sin-rotate-angle));
width: calc(var(--height) * var(--sin-rotate-angle) + var(--width) * var(--cos-rotate-angle));
height: calc(var(--height) * var(--cos-rotate-angle) + var(--width) * var(--sin-rotate-angle));
transform-origin: 0 0;
transform: rotate(calc(-1 * var(--rotate-angle)));
overflow: hidden;
transition: height var(--animation-timeout) linear;
}
.slide-content {
position: absolute;
background-size: 100% 100%;
left: calc(var(--height) / 2);
width: var(--width);
height: var(--height);
transform: rotate(var(--rotate-angle));
transform-origin: 0 0;
z-index: 0;
/* just styles for text */
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 3em;
}
.slide1 .slide-content {
background-image: url("https://i.stack.imgur.com/tt875.jpg");
}
.slide2 .slide-content {
background-image: url("https://i.stack.imgur.com/hzbmw.jpg");
}
.slide3 .slide-content {
background-image: url("https://i.stack.imgur.com/4UxLW.jpg");
}
.slide-cropper.prev {
height: 0;
z-index: 3;
}
.slide-cropper.current {
height: calc(var(--height) * var(--cos-rotate-angle) + var(--clipper-ratio) * var(--width) * var(--sin-rotate-angle));
transition-delay: var(--animation-timeout);
z-index: 2;
}
.slide-cropper.next {
z-index: 1;
}
/* Fix for IE */
.slide-cropper.current {
pointer-events: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="banners">
<div class="slide slide1">
<div class="slide-cropper current">
<div class="slide-content">
Slide 1
</div>
</div>
</div>
<div class="slide slide2">
<div class="slide-cropper next">
<div class="slide-content">
Slide 2
</div>
</div>
</div>
<div class="slide slide3">
<div class="slide-cropper">
<div class="slide-content">
Slide 3
</div>
</div>
</div>
</div>
También muestra con variables CSS que funcionan en Firefox (Firefox no es amigable con la combinación de variables CSS y transform: rotate
, así que simplemente reemplacé transform: rotate
con valores codificados):
$(document).ready(function() {
$(".banners").on("click", ".slide-cropper.next .slide-content", function() {
var $container = $(this).closest(".slide");
$(".slide-cropper").removeClass("prev")
.removeClass("current")
.removeClass("next");
$(this).closest(".slide-cropper").addClass("current");
var $prevContainer;
if ($container.prev().length) {
$prevContainer = $container.prev();
} else {
$prevContainer = $container.siblings(":last");
}
$prevContainer.find(".slide-cropper").addClass("prev");
var $nextContainer;
if ($container.next().length) {
$nextContainer = $container.next();
} else {
$nextContainer = $container.siblings(":first");
}
$nextContainer.find(".slide-cropper").addClass("next");
});
});
*,
*:before,
*:after {
box-sizing: border-box;
}
html {
--width: 100vw;
--height: 100vh;
/* sin 30 degrees for image cropping */
--sin-rotate-angle: 0.5;
/* cos 30 degrees for image cropping */
--cos-rotate-angle: 0.8660254037844386;
/* clipper ratio for width, can be from 0 to 1 */
--clipper-ratio: 0.45;
--animation-timeout: 2s;
}
/* all body styles are just for demo */
/* just centering the slider */
body {
margin: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.banners {
width: var(--width);
height: var(--height);
position: relative;
}
.slide {
width: 100%;
height: 100%;
}
.slide .slide-cropper {
position: absolute;
left: calc(-1 * var(--height) * var(--sin-rotate-angle) * var(--cos-rotate-angle));
top: calc(var(--height) * var(--sin-rotate-angle) * var(--sin-rotate-angle));
width: calc(var(--height) * var(--sin-rotate-angle) + var(--width) * var(--cos-rotate-angle));
height: calc(var(--height) * var(--cos-rotate-angle) + var(--width) * var(--sin-rotate-angle));
transform-origin: 0 0;
transform: rotate(-30deg);
overflow: hidden;
transition: height var(--animation-timeout) linear;
}
.slide-content {
position: absolute;
background-size: 100% 100%;
left: calc(var(--height) / 2);
width: var(--width);
height: var(--height);
transform: rotate(30deg);
transform-origin: 0 0;
z-index: 0;
/* just styles for text */
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 3em;
}
.slide1 .slide-content {
background-image: url("https://i.stack.imgur.com/tt875.jpg");
}
.slide2 .slide-content {
background-image: url("https://i.stack.imgur.com/hzbmw.jpg");
}
.slide3 .slide-content {
background-image: url("https://i.stack.imgur.com/4UxLW.jpg");
}
.slide-cropper.prev {
height: 0;
z-index: 3;
}
.slide-cropper.current {
height: calc(var(--height) * var(--cos-rotate-angle) + var(--clipper-ratio) * var(--width) * var(--sin-rotate-angle));
transition-delay: var(--animation-timeout);
z-index: 2;
}
.slide-cropper.next {
z-index: 1;
}
/* Fix for IE */
.slide-cropper.current {
pointer-events: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="banners">
<div class="slide slide1">
<div class="slide-cropper current">
<div class="slide-content">
Slide 1
</div>
</div>
</div>
<div class="slide slide2">
<div class="slide-cropper next">
<div class="slide-content">
Slide 2
</div>
</div>
</div>
<div class="slide slide3">
<div class="slide-cropper">
<div class="slide-content">
Slide 3
</div>
</div>
</div>
</div>
Un ejemplo simple que logra este efecto sin javascript:
https://jsfiddle.net/freer4/j2159b1e/2/
html, body{
height:100%;
width:100%;
margin:0;
padding:0;
}
.banners {
position:relative;
background:#000;
width: 100%;
height: 100%;
overflow:hidden;
}
.banners input{
display:none;
}
.slide1{
background-image: url(https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT5T6nwVYWsbzLcLF-JNxnGXFFFwkZMBcCMbaqeTevuldkxHg0N);
}
.slide2{
background-image:url(http://www.rd.com/wp-content/uploads/sites/2/2016/02/06-train-cat-shake-hands.jpg);
}
.slide3{
background-image:url(https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTKr6YlGNsqgJzvgBBkq1648_HsuDizVn_ZXC6iQp9kjXFzLvs1BA);
}
.image {
display:block;
height:100%;
width:100%;
position: absolute;
overflow:hidden;
z-index:1;
text-align:center;
background-position:0 0;
background-size:cover;
transition:z-index 1s step-end;
clip-path: polygon(100% 0, 100% 100%, 100% 100%, 0 100%, 0 0);
animation-duration: 2s;
animation-name: clipout;
}
input:checked + .image{
z-index:3;
transition:z-index 1s step-end;
clip-path: polygon(100% 0, 100% 50%, 50% 100%, 0 100%, 0 0);
animation-duration: 2.2s;
animation-name: clipin;
cursor:default;
}
.image:nth-child(2),
input:checked + * + * + .image{
z-index:2;
cursor:pointer;
}
.content{
color:#FFF;
display:inline-block;
vertical-align:middle;
font-family:arial;
text-transform:uppercase;
font-size:24px;
opacity:0;
transition:0s opacity 1s;
}
input:checked + .image .content{
opacity:1;
transition:0.8s opacity 0.8s;
}
.spanner{
vertical-align:middle;
width:0;
height:100%;
display:inline-block;
}
@keyframes clipout {
from { clip-path: polygon(100% 0, 100% 50%, 50% 100%, 0 100%, 0 0); }
50% { clip-path: polygon(100% 0, 100% -100%, -100% 100%, 0 100%, 0 0); }
51% { clip-path: polygon(100% 0, 100% 100%, 100% 100%, 0 100%, 0 0); }
to { clip-path: polygon(100% 0, 100% 100%, 100% 100%, 0 100%, 0 0); }
}
@keyframes clipin{
from { clip-path: polygon(100% 0, 100% 100%, 100% 100%, 0 100%, 0 0); }
50% { clip-path: polygon(100% 0, 100% 100%, 100% 100%, 0 100%, 0 0); }
to { clip-path: polygon(100% 0, 100% 50%, 50% 100%, 0 100%, 0 0); }
}
<div class="banners">
<input type="radio" id="slide1" name="slides" checked="checked" />
<label class="image slide1" for="slide1">
<div class="content">
Slide 1
</div>
<div class="spanner"></div>
</label>
<input type="radio" id="slide2" name="slides" />
<label class="image slide2" for="slide2">
<div class="content">
Slide 2
</div>
<div class="spanner"></div>
</label>
<input type="radio" id="slide3" name="slides" />
<label class="image slide3" for="slide3">
<div class="content">
Slide 3
</div>
<div class="spanner"></div>
</label>
</div>
Básicamente, solo use los fotogramas clave para animar la ruta del clip. Adapte los índices z y algunos selectores de hermanos.