0

I've started creating a rollover image effect for a Rails application I'm working on. I'm using the twitter-bootstrap-rails gem to keep the application looking good across devices. The problem I'm having with my current implementation is that when the browser is resized the image no longer resizes to width of the browser and the rollover effect breaks out of the borders of the image. The problem I think stems from the .photo class but I'm unsure of how to fix it or if there is a better way to implement my desired result?

HTML

<% @photos.each do |photo| %>
<div class="photo row">
  <div class="span8 photo"><%= image_tag photo.image_url(:large).to_s %></div>
  <div class="span4 hover">
    <div class="bg"></div>
    <div class="description">
      <h4><%= link_to photo.title, photo_path(photo) %></h4>
      <hr>
      <p><%= raw photo.tag_list.map { |t| link_to t, tag_path(t)}.join(' ') %></p>
    </div>
  </div>
</div>
<% end %>

CSS:

 .photo {
    position: relative;
    width: 770px;
  }

  .photo .hover {
    position: absolute;;
    height: 90.4%;
    left: 3.09%;
    top: 4.8%;
    width: 93.82%;
    display: none;
  }

  .photo .hover .bg {
    z-index: 1;
    position: absolute;
    height: 100%;
    width: 100%;
    background: #FFF;
    -webkit-opacity: 0.8;
    -moz-opacity: 0.8;
    filter:alpha(opacity=80);
    opacity: 0.8;
  }

  .photo .hover .description {
    position: relative;
    text-align: center;
    top: 40%;
    z-index: 2;
  }

JS

jQuery(document).ready(function($) {


  $(".photo").mouseenter(function () {
      $(this).find('.hover').fadeIn(300);
  }).mouseleave(function (){ 
    $(this).find('.hover').stop(true, true).fadeOut(300);
  });

}); /* End Dom Ready */

2 Answers2

0

I'm no front end whiz, but the problem you're having could be caused by event listeners being cleared by bootstrap's JS whenever the resizing happens. For some reason, DOM elements act as if they were destroyed and recreated under certain kinds of transformations, which means your callbacks would go away.

The way of fixing this used to be to use .live(), but that's apparently deprecated. Looks like .on() is what you want here. There are some caveats, however!

Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers.

source

This means you need to make sure to attach the event to a container that is guaranteed to not be manipulated in such a way that it's event listeners are cleared, but ideally that is as close in the DOM hierarchy as possible. Simply surrounding the image with a div could do that, if there's not already one in place.

heartpunk
  • 2,235
  • 1
  • 21
  • 26
  • Interesting! I didn't think of that... I shall do some research into both as well. I'm eager to see your update. –  Dec 30 '12 at 11:15
  • Ah, a bit further in the documentation, it says: '$(document).on(events, selector, data, handler); // jQuery 1.7+' is the way to do it now. Something along those lines has a good chance of solving your problem. Let me know if it doesn't. – heartpunk Dec 30 '12 at 11:20
  • I haven't had a chance to implement your response. Why wont it solve the problem? Should I hold off until you update your response? Thanks for taking the time to help me out. –  Dec 30 '12 at 11:46
  • I've updated my response already. The key is that it *might* solve your problem, depending on what DOM elements event listeners are being cleared. – heartpunk Dec 30 '12 at 11:49
  • Looks like you might want a div right outside of your existing div.photo, since I suspect that element is the one being resized by bootstrap. Alternately, you can list event listeners in chrome's dev tools, resize, and then list again, to find which elements' listeners are being cleared (or if any are at all). – heartpunk Dec 30 '12 at 11:51
  • Thanks I'll let you know you know how I go. –  Dec 30 '12 at 11:55
0

Bootstrap uses media queries to resize the span8. So we need to rearrange the html to include the hover elements within the span8 and then use percentages for the dimensions to retain the aspect ratio relative to the photo.

HTML

<% @photos.each do |photo| %>
<div class="row">
  <div class="span8 photo">
    <%= image_tag photo.image_url.to_s %>
    <div class="hover">
      <div class="bg"></div>
      <div class="description">
        <h4><%= link_to photo.title, photo_path(photo) %></h4>
        <hr>
        <p><%= raw photo.tag_list.map { |t| link_to t, tag_path(t)}.join(' ') %></p>
      </div>
    </div>
  </div> 
</div>
<% end %>

CSS

.photo {
  position: relative;
}

.photo .hover {
  position: absolute;
  height: 90%;
  width: 94%;
  top: 0;
  left: 0;
  padding: 3%;
  display: none;
}

.photo .hover .bg {
  z-index: 1;
  position: relative;
  height: 100%;
  width: 100%;
  background: #FFF;
  -webkit-opacity: 0.8;
  -moz-opacity: 0.8;
  filter:alpha(opacity=80);
  opacity: 0.8;
}

.photo .hover .description {
  position: absolute;
  text-align: center;
  top: 40%;
  width: 94%;
  height: 90%;
  z-index: 2;
}
Paul Mason
  • 1,818
  • 2
  • 20
  • 32