2

I'm putting together a simple jQuery script that lets me offset an item based on how far outside of the viewport it is. In other words, collision of an object (div) with the viewport. What I've put together so far works perfectly using position: fixed, but is off by 34 pixels if using position: absolute;, which I think is due to the browser vertical scrollbar * 2. Whether this is the case or not, I don't know how to compensate for it.

Perhaps someone has an idea how I can fix this different reading?

I put together a jsfiddle that can be viewed here: https://jsfiddle.net/pegues/m1zg5p4c/1/

In the jsfiddle, you can see in the view pane 'Off-screen X: -133`. This should be -150 for the value. If you change the css for .box at line 13 to fixed, you will see the red box position correctly and flush to the bottom and right of the screen, and the Off-screen X value will be -150.

Maybe there is some principle with how fixed vs absolute works that I'm missing or forgotten about?

elemCollision($('.box'));

function elemCollision(el) {

  // Viewport Width and Height
  var viewportW = window.innerWidth;
  var viewportH = window.innerHeight;

  // Element Width and Height
  var width = el.innerWidth();
  var height = el.innerHeight();

  // Element Position: top, right, bottom, left
  var top = el.offset().top;
  var left = el.offset().left;
  var right = (viewportW - left) + viewportW;
  var bottom = (viewportH - top) + viewportH;

  // Amount Element is Off Screen
  var offScreenX = (viewportW - left) - width;
  var offScreenY = (viewportH - top) - height;

  // Position Element 100% on Screen
  var placementX = (viewportW - left) - Math.abs(offScreenX);
  var placementY = (viewportH - top) - Math.abs(offScreenY);

  // Assign New X and Y Placement Values
  $('.box').css({ bottom: placementY, right: placementX });

  $('body').append(
    '<div style="padding: 10px; font-size: 0.80em; line-height: 1.25em;">-----' + '<br/>' +
        'Placement Top: ' + top + '<br/>' +
    'Placement Right: ' + right + '<br/>' +
    'Placement Bottom: ' + bottom + '<br/>' +
    'Placement Left: ' + left + '<br/>' +
    'Box Width: ' + width + '<br/>' +
    'Box Height: ' + height + '<br/>' +
    'Viewport Width: ' + viewportW + '<br/>' +
    'Viewport Height: ' + viewportH + '<br/>' +
    'Off-screen X: ' + offScreenX + '<br/>' +
    'Off-screen Y: ' + offScreenY + '<br/>' +
    'New Placement X: ' + placementX + '<br/>' +
    'New Placement Y: ' + placementY + '<br/>' +
    '-----</div>'
  );
}
Pegues
  • 1,693
  • 2
  • 21
  • 38

2 Answers2

2

You are correct that it is the scrollbar (even though it looks invisible). If you run this function (source):

function getScrollBarWidth () {
    var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
        widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
    $outer.remove();
    return 100 - widthWithScroll;
};

You will see the scrollbar's width (here is the jsfiddle where I added the function). If you keep positition:absolute on the box and add overflow-y:hidden; to the body, you can see that running the function now will give you a null exception, as the scrollbar doesn't have any width affecting the body (it even doesn't really exist).

So to answer your question, since Absolute positioning is relative to the parent (body), and body had the scrollbar affecting the width, you were not getting the result you expected.

Community
  • 1
  • 1
Nick G
  • 1,953
  • 12
  • 16
  • My value for `Off-screen X` is different than what you're saying, but the width of the scrollbar should make up the difference for what it should be. – Nick G Nov 16 '16 at 19:50
  • Thank you Nick. Your solution gives me both an explanation and something to work with in being able able to achieve the outcome I need. – Pegues Nov 16 '16 at 19:51
  • @Pegues glad to help you! – Nick G Nov 16 '16 at 19:52
1

Modify your window's width and height from innerWidth to just width and same with height.

// Viewport Width and Height
  var viewportW = window.width;
  var viewportH = window.height;

and your bottom and left css to 0px

Keith.Abramo
  • 6,952
  • 2
  • 32
  • 46
  • Thank you for your solution. It seems to work, but one answer was better in that they also provided some explanation. Thank you. I'll certainly give you an up vote. – Pegues Nov 16 '16 at 19:50