0

This is a tricky problem to describe...I have a fixed height <div> on my page with a bunch of content items inside. Each item is a square <div>, floated left, so they fill in the area left to right and top to bottom. If there are too many items to fit in the view, then the content area will scroll (overflow-y: auto).

Forgive the ASCII art:

---------------------
| [ 1 ] [ 2 ] [ 3 ] |
| [ 4 ] [ 5 ] [ 6 ] |
| [ 7 ] [ 8 ] [ 9 ] |
---------------------

The thing is, the items inside don't fit perfectly in the area without the bottom row getting clipped. So what I want to do is somehow automatically scroll the view down when the user hovers over an item that's clipped off the bottom of the content area.

I can't figure out how I would go about determining whether a particular item is clipped or not.

Is this totally wacky? Or is there a logical method for doing this?

daGUY
  • 27,055
  • 29
  • 75
  • 119
  • I have an idea using anchors and targets. Lemme put together a fiddle – Geuis Aug 17 '12 at 22:06
  • Certainly you can, but I'd think about the ramifications of doing this. It might be detrimental to the user experience. Picture hundreds of these divs. If you scroll to just the bottom of the straddling-the-fold divs, the user still must manually scroll to reach even-lower divs below that. If you scroll a bit past the bottom of the straddling-the-fold divs so that the even-lower divs show, now the user's mouse may be hovering over the even-lower divs which would trigger the scroll yet again. This is not insurmountable; I just want you to think about whether you really want to do this. – Zach Shipley Aug 17 '12 at 22:22
  • @ZachShipley The reason why I want to do this is because the individual `div`s, when hovered over, "expand" to double their height to display additional information. Thus, if the particular `div` is at the bottom of the content area and you hover over it, you have to manually scroll down to see the expanded portion. – daGUY Aug 18 '12 at 00:41

2 Answers2

0

This is a very basic example.

http://jsfiddle.net/8Kb7N/

Essentially, each of your square divs would have an associate anchor inside with a unique name.

You want to set a hover event for each item that sets the window.location to the name of its anchor. This should let it navigate inside the area.

Geuis
  • 41,122
  • 56
  • 157
  • 219
  • Ooh...that's clever. But then won't that result in the view scrolling when any item is hovered over? I really only want it to scroll if the particular item being hovered is clipped at the bottom. – daGUY Aug 18 '12 at 00:39
  • Get the width/height of the containing div. Get the width & height of each inner div. Use this to calculate the number of rows and number of items in each row. From this, you can select the last n number of divs and only apply the anchor technique to them. – Geuis Aug 18 '12 at 05:08
0

After first experimenting with @Geuis' method, I realized I was solving the wrong problem, because the last row of items isn't necessarily the same row that's getting clipped.

For example, say I have 12 items in a 3x4 grid: 3 items per row, 4 rows in total. Then say my container is only tall enough to show the first two rows and the top half of the third row. The last row is the fourth row, but the row that's getting clipped is the third row, assuming I'm scrolled to the top. Or, what if I scroll to the bottom of the container? Now the second row is getting clipped, and off the top rather than the bottom.

So I realized that rather than looking at the rows, I need to look at the particular item that's being hovered over and determine if that single item is being shown in full or not. If it is, do nothing; if it's not, scroll up or down depending on which end of the item is clipped.

Here's what I came up with. On hover:

var containerHeight = $container.height(),
    itemHeight = $(this).height(),
    itemOffset = Math.floor($(this).position().top),
    itemVisible = containerHeight - itemOffset,
    itemClip = itemHeight - itemVisible;

if (itemClip > 0){
    $container.scrollTo('+=' + itemClip, 600);
} else if (itemOffset < 0){
    $container.scrollTo('-=' + Math.abs(itemOffset), 600);
}

($container is defined elsewhere in my script as the containing div)

Line by line:

  1. Get the height of the container that holds all the items
  2. Get the height of the item being hovered
  3. Get the distance from the top of the container to the top of the hovered item
  4. Subtract the distance (line 3) from the height of the container (line 1)
  5. Take the difference from line 4 and subtract it from the height of the item being hovered (line 2)

Now, this tells you two things:

  • If the result of line 3 is negative, the item is being clipped by that many pixels past the top of the container
  • If the result of line 5 is positive, the item is being clipped by that many pixels past the bottom of the container

Knowing this, you can then scroll the container in the correct direction and by the correct distance to reveal the whole item.

The actual scrolling itself requires the jQuery ScrollTo plugin in order to scroll up or down x number of pixels from the current scroll position (not from the top of the container, which is what jQuery's built-in .scrollTop() function does).

(ScrollTo does not take a negative number as a value, so in order to scroll up, you need to get the absolute value of itemOffset - hence Math.abs(itemOffset)).

daGUY
  • 27,055
  • 29
  • 75
  • 119