1

I got two columns of images, done with column-count:2. When I press one of the images, jQuery duplicates that image at the exact same position with position:absolute. Then a class .dupAnim gets added, which makes that image full width and transition it to top:0;left:0 of the page.


So my problem:
When I click an image, the transition from the original state to top:0; left:0; width:100% isn't working. But when I click the close button, it's perfectly transitioning back.

It seems like the in transition isn't working, but the out transition is working. Below you can find a snippet. Does anyone know what the problem is?

$(".item").each(function(){
  var imageSrc = $(this).children('img').attr('src');
  $(this).css('background-image', 'url(' + imageSrc + ')');
  $(this).find('.clipped').css('background-image', 'url(' + imageSrc + ')');
  
  var imgHeight = $(this).find('img').height();
  $(this).css('height', imgHeight + 'px');
});

$(".item").click(function(){
  
  $(this).clone().appendTo(".duplicated").addClass("dupe");
  var width = $(this).width();
  var height = $(this).height();
  var top = $(this).offset().top;
  var left = $(this).offset().left;
    
  var dupe = ".dupe";
  
  $(dupe).css({
    'width': width + 'px',
    'height': height + 'px',
    'top': top + 'px',
    'left': left + 'px',
    'position': 'fixed'
  });
  
  $(dupe).addClass("dupAnim");
  
  $(".portfolio-close").fadeIn();
  
});

$(".portfolio-close").click(function(){
  $(".duplicated").find(".dupAnim").removeClass("dupAnim");
  setTimeout(function(){
    $(".duplicated").children().remove();
  }, 500);
  $(this).fadeOut();
});
* {
  font-family: 'Source Sans Pro', sans-serif;
  margin: 0;
  padding: 0;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.wrapper {
  padding: 5% 10%;
}
.wrapper .page-title {
  font-size: 4em;
  font-weight: 900;
  margin-bottom: 20px;
}
.wrapper #portfolio-items {
  -webkit-column-count: 2;
  -webkit-column-gap: 0px;
  -moz-column-count: 2;
  -moz-column-gap: 0px;
  column-count: 2;
  column-gap: 10px;
}
.wrapper #portfolio-items .item {
  -webkit-column-break-inside: avoid;
  -webkit-backface-visibility: hidden;
  border-radius: 8px;
  overflow: hidden;
  margin: 0 0 10px 0;
  cursor: pointer;
  width: 100%;
  background: #fff;
  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50% 50%;
  transition: .5s ease-in-out;
}
.wrapper #portfolio-items .item .clipped {
  padding: 0 30px 10px 20px;
  display: flex;
  align-items: flex-end;
  height: 100%;
  line-height: 1.2;
  overflow: hidden;
  color: #fff;
  font-size: 1.7em;
  background: #fff;
  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50% 50%;
  -webkit-text-fill-color: transparent;
  -webkit-background-clip: text;
  -webkit-filter: invert(100%) hue-rotate(0deg);
  /* change hue-rotate to play with tint */
  transition: .5s ease-in-out;
}
.wrapper #portfolio-items .item .clipped .item-title {
  overflow: hidden;
}
.wrapper #portfolio-items .item img {
  width: 100%;
  visibility: hidden;
}
.wrapper #portfolio-items .duplicated .dupe {
  position: fixed;
  transition: .5s ease-in-out;
}
.wrapper #portfolio-items .duplicated .dupe.dupAnim {
  top: 0 !important;
  left: 0 !important;
  width: 100% !important;
  height: 100px !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  transition: .5s ease-in-out;
}
.wrapper #portfolio-items .portfolio-close {
  position: fixed;
  z-index: 21;
  cursor: pointer;
  top: 0;
  right: 0;
  background: #515151;
  width: 50px;
  height: 50px;
  font-size: 30px;
  color: white;
  padding: 10px 0 0 13px;
  line-height: 1;
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="wrapper">
  
  <div id="portfolio-items">
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Yoga</h1>
      </div>
      <img src="https://www.w3schools.com/howto/img_fjords.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Elephant</h1>
      </div>
      <img src="https://s3-us-west-1.amazonaws.com/powr/defaults/image-slider2.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Bird</h1>
      </div>
      <img src="http://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">View</h1>
      </div>
      <img src="https://upload.wikimedia.org/wikipedia/commons/6/64/Ailurus_fulgens_RoterPanda_LesserPanda-2.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Dog</h1>
      </div>
      <img src="https://www.codeproject.com/KB/GDI-plus/ImageProcessing2/flip.jpg">
    </div>
    
  <div class="duplicated"></div>
    
  <div class="portfolio-close">✕</div>
    
  </div>
</div>

2
  • When element is added to dom or changed from "display: none", it appears in finished state of transition. This means that you have to add at least 17ms delay between adding an element and applying a transitioned class. Commented Nov 18, 2017 at 13:11
  • @RauliRajande When I add a timeout for adding the class, the transition isn't clean still :/ Tried that out aswell. Commented Nov 18, 2017 at 13:13

4 Answers 4

3

I think you want to add the fadeIn and the addition of the dupe class as callbacks to the container being faded in. This ensures that the callback it not executed until after the first effect is complete.

Also, I've added: $(".portfolio-close").hide(); at the beginning of the code to ensure that the container always starts off hidden because after clicking one item, it will be visible and you need it hidden for each click so that when it's class changes, the transition will work.

I reorganized the creation of the duplicate a little (to remove unnecessary variables and clean up the code a bit) and I added the all parameter to your transition properties:

$(".item").each(function(){
  var imageSrc = $(this).children('img').attr('src');
  $(this).css('background-image', 'url(' + imageSrc + ')');
  $(this).find('.clipped').css('background-image', 'url(' + imageSrc + ')');
  
  var imgHeight = $(this).find('img').height();
  $(this).css('height', imgHeight + 'px');
});

$(".item").click(function(){
  
  var $clone = $(this).clone();
  
  // Make sure the container is hidden before the effects begin:
  $(".portfolio-close").hide();  

  $clone.appendTo(".duplicated");
  $clone.hide();  
  
  // Passing a function as the second argument to JQuery's show(),
  // hide(), fadeIn(), fadeOut(), etc. ensures that the function
  // is run AFTER the first effect is complete.
  $(".portfolio-close").fadeIn(50, function(){
    $clone.fadeIn();
    $clone.addClass("dupe");
  });    

  // No need to create varaibles for values you are only
  // going to access just once. Just get the values directly:
  $clone.css({
    'width': $(this).width() + 'px',
    'height': $(this).height() + 'px',
    'top': $(this).offset().top + 'px',
    'left': $(this).offset().left + 'px',
    'position': 'fixed'
  });

  $clone.addClass("dupAnim");   
});

$(".portfolio-close").click(function(){
  $(".duplicated").find(".dupAnim").removeClass("dupAnim");
  setTimeout(function(){
    $(".duplicated").children().remove();
  }, 500);
  $(this).fadeOut();
});
* {
  font-family: 'Source Sans Pro', sans-serif;
  margin: 0;
  padding: 0;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.wrapper {
  padding: 5% 10%;
}
.wrapper .page-title {
  font-size: 4em;
  font-weight: 900;
  margin-bottom: 20px;
}
.wrapper #portfolio-items {
  -webkit-column-count: 2;
  -webkit-column-gap: 0px;
  -moz-column-count: 2;
  -moz-column-gap: 0px;
  column-count: 2;
  column-gap: 10px;
}
.wrapper #portfolio-items .item {
  -webkit-column-break-inside: avoid;
  -webkit-backface-visibility: hidden;
  border-radius: 8px;
  overflow: hidden;
  margin: 0 0 10px 0;
  cursor: pointer;
  width: 100%;
  background: #fff;
  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50% 50%;
  transition:all .5s ease-in-out;
}
.wrapper #portfolio-items .item .clipped {
  padding: 0 30px 10px 20px;
  display: flex;
  align-items: flex-end;
  height: 100%;
  line-height: 1.2;
  overflow: hidden;
  color: #fff;
  font-size: 1.7em;
  background: #fff;
  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50% 50%;
  -webkit-text-fill-color: transparent;
  -webkit-background-clip: text;
  -webkit-filter: invert(100%) hue-rotate(0deg);
  /* change hue-rotate to play with tint */
  transition:all .5s ease-in-out;
}
.wrapper #portfolio-items .item .clipped .item-title {
  overflow: hidden;
}
.wrapper #portfolio-items .item img {
  width: 100%;
  visibility: hidden;
}
.wrapper #portfolio-items .duplicated .dupe {
  position: fixed;
  transition:all .5s ease-in-out;
}
.wrapper #portfolio-items .duplicated .dupe.dupAnim {
  top: 0 !important;
  left: 0 !important;
  width: 100% !important;
  height: 100px !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  transition:all .5s ease-in-out;
}
.wrapper #portfolio-items .portfolio-close {
  position: fixed;
  z-index: 21;
  cursor: pointer;
  top: 0;
  right: 0;
  background: #515151;
  width: 50px;
  height: 50px;
  font-size: 30px;
  color: white;
  padding: 10px 0 0 13px;
  line-height: 1;
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="wrapper">
  
  <div id="portfolio-items">
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Yoga</h1>
      </div>
      <img src="https://www.w3schools.com/howto/img_fjords.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Elephant</h1>
      </div>
      <img src="https://s3-us-west-1.amazonaws.com/powr/defaults/image-slider2.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Bird</h1>
      </div>
      <img src="http://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">View</h1>
      </div>
      <img src="https://upload.wikimedia.org/wikipedia/commons/6/64/Ailurus_fulgens_RoterPanda_LesserPanda-2.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Dog</h1>
      </div>
      <img src="https://www.codeproject.com/KB/GDI-plus/ImageProcessing2/flip.jpg">
    </div>
    
  <div class="duplicated"></div>
    
  <div class="portfolio-close">✕</div>
    
  </div>
</div>

Sign up to request clarification or add additional context in comments.

5 Comments

I noticed the lack of all, too, but W3C seems to think it's still valid CSS without it, and indeed it still works fine.
@ChuckLeButt Yes, but better to include it for clarity.
It was just an observation, not a criticism. I would include it myself.
@ChuckLeButt Understood. Just my reply. That's all.
@ScottMarcus Thanks alot for your answer. That makes sense. Instead of adding $clone.fadeIn(); $clone.addClass("dupe"); as a callback function of fadeIn() of the close button, I just set a timeout, so the close button can fade in nicer. Additionally I changed the $clone.fadeIn() to $clone.show(), because the duplicated element was weirdly fading in on codepen. Working like a charm now. Thank you!
0

The transitions are working fine, it's just that your duplicates are not starting from the same shape/size as the original.

Comments

0

Update you jQuery and add a SetTimeout() when adding the dupAnim class, then wrap() the duplicate img with a new container.

$(".item").click(function(){
  // changed the container
  $(this).clone().appendTo(".duplicated").wrap('<span class="img-container dupe">');
  var width = $(this).width();
  var height = $(this).height();
  var top = $(this).offset().top;
  var left = $(this).offset().left; 
  var dupe = ".dupe";
   $(dupe).css({
    'width': width + 'px',
    'height': height + 'px',
    'top': top + 'px',
    'left': left + 'px',
    'position': 'fixed',
  });
 // settime out
  setTimeout(function(){    
        $(dupe).addClass("dupAnim");
  },100) ; 

 $(".portfolio-close").fadeIn();

});

$(".portfolio-close").click(function(){
  $(".duplicated").find(".dupAnim").removeClass("dupAnim");
  setTimeout(function(){
    $(".duplicated").children().remove();
  }, 500);
  $(this).fadeOut();
});

1 Comment

No need for setTimeout. fadeIn() takes a callback as its second argument for just this purpose.
0

Your transition: .5s ease-in-out for .dupe will invoke the transition when you modify the initial style (eg, modify the width: 100% of the image to width + 'px' which computed through js) with the next code:

```

$(dupe).css({
'width': width + 'px',
'height': height + 'px',
'top': top + 'px',
'left': left + 'px',
'position': 'fixed',

}) ```

Then if you immediately addClass('dupAnim'), it will override the former style modify(eg, set width to 100% !important) so, you will not see the transition of the width.

So you can add a extra className for unset the transition before set the style computed through js, and then remove the className.

Add the more thing is that you need add a setTimeout when modify the className to invoke the reflow of the browser.

$(".item").each(function(){
  var imageSrc = $(this).children('img').attr('src');
  $(this).css('background-image', 'url(' + imageSrc + ')');
  $(this).find('.clipped').css('background-image', 'url(' + imageSrc + ')');
  
  var imgHeight = $(this).find('img').height();
  $(this).css('height', imgHeight + 'px');
});

$(".item").click(function(){
  
  $(this).clone().appendTo(".duplicated").addClass("dupe");
  var width = $(this).width();
  var height = $(this).height();
  var top = $(this).offset().top;
  var left = $(this).offset().left;
    
  var dupe = ".dupe";
  
  $(dupe).addClass('no-transition').css({
    'width': width + 'px',
    'height': height + 'px',
    'top': top + 'px',
    'left': left + 'px',
    'position': 'fixed',
  });
  setTimeout(function() {
 $(dupe).removeClass('no-transition');
  }, 10);
 
  setTimeout(function() {
  $(dupe).addClass("dupAnim") 
    $(".portfolio-close").fadeIn(500);
  }, 30);
  
  
});

$(".portfolio-close").click(function(){
  $(".duplicated").find(".dupAnim").removeClass("dupAnim");
  setTimeout(function(){
  $(".duplicated").children().remove();
  }, 500);
  $(this).fadeOut();
});
* {
  font-family: 'Source Sans Pro', sans-serif;
  margin: 0;
  padding: 0;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.wrapper {
  padding: 5% 10%;
}
.wrapper .page-title {
  font-size: 4em;
  font-weight: 900;
  margin-bottom: 20px;
}
.wrapper #portfolio-items {
  -webkit-column-count: 2;
  -webkit-column-gap: 0px;
  -moz-column-count: 2;
  -moz-column-gap: 0px;
  column-count: 2;
  column-gap: 10px;
}
.wrapper #portfolio-items .item {
  -webkit-column-break-inside: avoid;
  -webkit-backface-visibility: hidden;
  border-radius: 8px;
  overflow: hidden;
  margin: 0 0 10px 0;
  cursor: pointer;
  width: 100%;
  background: #fff;
  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50% 50%;
  transition: .5s ease-in-out;
}
.wrapper #portfolio-items .item .clipped {
  padding: 0 30px 10px 20px;
  display: flex;
  align-items: flex-end;
  height: 100%;
  line-height: 1.2;
  overflow: hidden;
  color: #fff;
  font-size: 1.7em;
  background: #fff;
  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50% 50%;
  -webkit-text-fill-color: transparent;
  -webkit-background-clip: text;
  -webkit-filter: invert(100%) hue-rotate(0deg);
  /* change hue-rotate to play with tint */
  transition: .5s ease-in-out;
}
.wrapper #portfolio-items .item .clipped .item-title {
  overflow: hidden;
}
.wrapper #portfolio-items .item img {
  width: 100%;
  visibility: hidden;
}
.wrapper #portfolio-items .duplicated .dupe {
  position: fixed;
}
.no-transition {
  transition: unset !important;
}
.wrapper #portfolio-items .duplicated .dupe.dupAnim {
  top: 0 !important;
  left: 0 !important;
  width: 100% !important;
  height: 100px !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  transition: .5s ease-in-out;
}
.wrapper #portfolio-items .portfolio-close {
  position: fixed;
  z-index: 21;
  cursor: pointer;
  top: 0;
  right: 0;
  background: #515151;
  width: 50px;
  height: 50px;
  font-size: 30px;
  color: white;
  padding: 10px 0 0 13px;
  line-height: 1;
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="wrapper">
  
  <div id="portfolio-items">
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Yoga</h1>
      </div>
      <img src="https://www.w3schools.com/howto/img_fjords.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Elephant</h1>
      </div>
      <img src="https://s3-us-west-1.amazonaws.com/powr/defaults/image-slider2.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Bird</h1>
      </div>
      <img src="http://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">View</h1>
      </div>
      <img src="https://upload.wikimedia.org/wikipedia/commons/6/64/Ailurus_fulgens_RoterPanda_LesserPanda-2.jpg">
    </div>
    
    <div class="item">
      <div class="clipped">
        <h1 class="item-title">Dog</h1>
      </div>
      <img src="https://www.codeproject.com/KB/GDI-plus/ImageProcessing2/flip.jpg">
    </div>
    
  <div class="duplicated"></div>
    
  <div class="portfolio-close">✕</div>
    
  </div>
</div>

5 Comments

Or you could just place that code inside a callback to fadeIn.
Yes, I tried that out aswell, but here's the problem that the width of the duplicated object doesn't transition tho
@TobiasGlaus See my answer below.
I would suggest to avoid fadeIn and other js animations, as they make your page slower. This is perfectly doable in css.
@TobiasGlaus Still need something to modify. Updated the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.