CSS reveal from corner animation

后端 未结 5 502
小蘑菇
小蘑菇 2020-12-13 14:34

I am trying to achieve an animation effect as follows:

When a banner is shown, the bottom right corner of the next banner should be visible. When you click on this c

5条回答
  •  天命终不由人
    2020-12-13 15:14

    This is an answer without the use of clip-path, because browser compatibility on DOM elements other than svg is low.

    I see now that Vadim had the same idea as me with the rotated container (hadn't checked back here until I had finished), but from what I can tell there are still enough differences between our answers to justify posting my solution:

    $(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;}
    
    
    
    codepen: https://codepen.io/anon/pen/JJQRvM
    jsfiddle: https://jsfiddle.net/tq2hw7b9/5/

    • Instead of clip-path I just change the height of the slide containers, using transition for the animation effects.

    IE TROUBLES

    Unfortunately, as usual, IE processes transform:rotate() differently from other browsers. Visually the rotations happen, but the browser still seems to reserve the original space of the elements, so therefor the exposed corner of the next slide is not clickable because the current slide is 'covering' it. Using the -ms- or -webkit- prefix doesn't make a difference.

    The following code snippet DOES work in 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;}
    
    
    
    codepen: https://codepen.io/anon/pen/GEbrzQ
    jsfiddle: https://jsfiddle.net/8ggqndj1/

    • I added an extra
      that covers all the slides.
    • The click-handler in JS is now bound to this .corner, and at the start of the handler a reference to the next slide is stored into a variable, which is used in the rest of the code.
    • In CSS there is also a new rule for the .corner.

    SLIDE-ARRAY IN JS

    Have a look at the code snippet below, for a list of slides in JS (if someone needs it):

    $(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;}
    
    
    
    codepen: https://codepen.io/anon/pen/EXBgew
    jsfiddle: https://jsfiddle.net/qghv9bnh/13/

    • It may hold some preferences for some, although I think my first solution is a lot cleaner, faster, and flexible for adding extra slides (certainly when you use a CMS like WordPress or Joomla):
      1. The images are only loaded when you actually use the slider, so users save bandwidth for every slide they don't click on.
      2. The HTML is very concise and will never grow no matter how many slides you have, so your HTML will look cleaner (but if you use PHP to include them it will look just as clean, even cleaner).

    Can't really think of anything else, as I said, I prefer the first one. But none the less, it may come in handy for someone.

提交回复
热议问题