The Linux Page

Bottom bar animation depending on scroll position

Today I got a little challenge trying to get a bar at the bottom of the SMS From Me public pages.

I was thinking to use CSS to animate size. Already here there is a trick to know about. You cannot use the height (or width) parameter. However, you can use the max-height (max-width) to make the transition work as expected.

So my CSS transition included the following important parameters:

.bottom-bar
{
  padding: 0;
  margin: 0;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  max-height: 0px; /* at the start, it is hidden */
  transition: max-height 1s;
}

.bottom-bar.in-view
{
  max-height: 120px;
}

The "px" after the "0" in the first max-height is important for older Chrome browsers, otherwise they drop the transition.

The max-height in the "in-view" CSS is set to 120px. If you have a specific size for your bar, easy. If you expect each browser to use the correct height depending on content, then you need a little extra to change the height properly.

First, let's take a look at the HTML. As we can see the .bottom-bar section has no padding and no margin. This is important. If you need/want such, you'll look at having a sub-div inside that element. That sub-div is also important to determine the correct size in the ".in-view" CSS.

<footer>
  <div>
    <p>Copyright, Dates, Menus, Who Created this...
       your footer goes here</p>
  </div>
</footer>
<div class="bottom-bar"><!-- hidden on load (max-height: 0px) -->
  <div class="bar-content">
    Some text goes here (ad, anchors, etc.)
  </div>
</div>

The CSS, by default, says "max-height: 0px;", so to get the size of the bottom bar, we get the size of the "bar-content" as shown below. Note that's why we need a margin and padding of 0 in the ".bottom-bar" CSS definition.

jQuery("head").append("<style>.bottom-bar.in-view{max-height:"
                    + jQuery(".bar-content").height()
                    + "}</style>");

This JavaScript code uses jQuery. It adds a <style> tag to the <head> tag. The content replaces the default height of "max-height" defined in your CSS file with the exact height of the "bar-content" <div> element. Note that also you do not absolutely need a definition in your main CSS file, I suggest you have it, just in case.

Without that code, the easing of the animation may not look quite right if you put a height that's too large.

Now, when you add such a bottom bar, it covers the footer unless you also add "empty" space at the bottom of your footer (you could also allow for the closing of the bar, but in my case I do not have such a feature.) The following line of code does that.

jQuery("<div class='space'>&nbsp;</div>").appendTo("footer");

You may have to tweak the content of that space to better match your bottom bar. In my case I just have some text so putting &nbsp; and in CSS having the same font height is enough. The CSS should also duplicate padding as required.

That is pretty good to setup everything. A bit sad we have to do these things in JavaScript, but note that the appendTo("footer") does not need to be done in JS if you know that your bottom bar is always there. In my case, it is there only if the user is not logged in so I needed dynamism. That being said, I probably could have used a class and hide that tag by default and if I know the footer gets extended then add a class to show that extension.

Finally, to handle the showing/hiding of the bottom bar as the user scrolls the window, I use the scroll() function of jQuery. It is pretty simple:

function f()
{
  var scroll_top = parseFloat(jQuery(window.top).scrollTop());

  if(scroll_top > screen_height + 20) /* +20 is arbitrary */
  {
    jQuery(".bottom-bar").addClass("in-view");
  }
  else
  {
    jQuery(".bottom-bar").removeClass("in-view");
  }
}

This is the content of the scroll() handler. I set it up like this:

jQuery("footer").scroll(f);

where f() is the function defined earlier.

Now, the first time you load, if no scrolling happens, the function will never be called. This means on a Reload things may not work as expected (i.e. you are scrolled down enough for the bar to appear, but it does not happen.) To fix the potential problem, I call the function once on initialization. That way the "in-view" class may be added:

f();

Finally, you may have noticed a screen_height variable in the function f(). That variable is set with the height of the window as in:

var screen_height = parseFloat(jQuery(window.top).outerHeight());

The reason why I do not do that in my function f() is because smartphones can hide their location bar at the top. When that happens, the screen height grows by quite a few pixels. That means the test in f() can flip flop and you can notice it on the screen.

For Desktop computers, this can be a problem only if the user changes the size of his window (either by resizing the window, going fullscreen with F11, or showing/hiding various toolbars...) I do not think that the bottom bar of my website is so important that I should handle all those cases, especially because many of my users are on their smartphone when they come and visit SMS From Me. So... having one static variable value is enough for me.

That was quite a feat, not what I first expected having to use when I started this little project.