0

I want to have a div positioned in the bottom of another div. This i can solve with just

bottom: 0px;
postion: fixed;

But, if the containing div is larger than the window, i want to freeze the inner div to the bottom of the window.

If it's easier the first condition can be scrapped and the inner div can just be positioned under the content, the important part is that the content must always be visible.

berinder
  • 85
  • 9

2 Answers2

1

The best solution would be to detect with JavaScript if the footer is visible inside the viewport. If not, you should change it's styles to stick to the bottom of the window instead of that of the containing div.

You could use this function to see if it's in the viewport:

function elementInViewport(el) {
  var top = el.offsetTop;
  var left = el.offsetLeft;
  var width = el.offsetWidth;
  var height = el.offsetHeight;

  while(el.offsetParent) {
    el = el.offsetParent;
    top += el.offsetTop;
    left += el.offsetLeft;
  }

  return (
    top >= window.pageYOffset &&
    left >= window.pageXOffset &&
    (top + height) <= (window.pageYOffset + window.innerHeight) &&
    (left + width) <= (window.pageXOffset + window.innerWidth)
  );
}

(taken from How to tell if a DOM element is visible in the current viewport?)

Now, every time you scroll or resize the page you can do a check that runs that function. Based on that, you can decide to set a class or change a CSS property that will do what you're looking for.

Since you didn't include any code (in the future, please do) I'm going to assume your code looks something like this:

<div class="wrapper">
    (contents)

    <div class="footer">footer</div>
</div>

To stick the .footer to the bottom of .wrapper, it has to have a 'positon: absolute' and the wrapper will need a position: relative. However, if you change it's position property to fixed and the wrapper to static (the default for all elements), the footer is going to stick to the bottom of the window instead.

View this example http://jsfiddle.net/GMYEh/

Now, using the script above you can tell which of the two it should be. You have to use a fake element at the same position of the footer, instead of the footer itself. That way, if you move the footer to the bottom of the window, you can still measure whether or not the bottom of the wrapper is in the viewport. (If you measure the footer itself and move it you'll get stuck).

The script that does this (in jQuery):

// add a fake footer after the wrapper
$('.wrapper').after($('<div class="fakefooter" />'));

$(document).on('resize scroll', function(e){
    //measure if the fake footer is in viewport
    if(elementInViewport($('.fakefooter')[0])) {
        // If so, it should be in the bottom of the wrapper. 
        $('.wrapper').css('position', 'relative');
        $('.footer').css('position', 'absolute');
    } else {
        // else it should be in the bottom of the window
        $('.wrapper').css('position', 'static');
        $('.footer').css('position', 'fixed');
    } 
});

Working example: http://jsfiddle.net/GMYEh/4/

Community
  • 1
  • 1
Stephan Muller
  • 24,574
  • 14
  • 80
  • 119
0

Try this:

HTML:

<div id="wrapper">
    <div id="innerContent"></div>
</div>

CSS:

.fixedContent {
    position: fixed;
    bottom: 0;
}

and the javascript:

var wrapper = document.getElementById('wrapper');
var content = document.getElementById('innerContent');
function position() {
    if (wrapper.offsetHeight + wrapper.offsetTop - content.offsetHeight - window.scrollY > window.innerHeight) {
        content.className += ' fixedContent';
    } else {
        content.className = content.className.replace('fixedContent', '');
    }
}

window.onload = position;
window.onresize = position;

If you're open to jQuery you can make the javascript more simple and compatible

var $wrapper = $('#wrapper');
var $content = $('#innerContent');
$(window).on('load resize', function() {
    $content.toggleClass('fixedContent', $wrapper.outerHeight(true)  $content.offset().top - $content.outerHeight(true) - $(document).scrollTop() > $(window).height());
});

EDIT: I modified the conditions a bit adding the vertical scroll value and top offset.

matewka
  • 9,337
  • 2
  • 26
  • 40