Jquery sticky sidebar ή πως να κάνετε το sidebar να μένει πάντα ορατό (above the fold)

Υπάρχουν περιπτώσεις που θέλετε ένα sidebar, block, καλάθι αγορών ή απλά οι διαφημίσεις σας να μένουν πάντα ορατά καθώς ο χρήστης scrollaρει στην οθόνη.

Ο κώδικας HTML

<!DOCTYPE html>
<html>
  <head>
    <title>jQuery stickysidebar plugin</title>
  <link href='http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:extralight,light,regular,bold' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" href="../style/default.css" media="screen" />
    <link rel="stylesheet" href="style/sticky.css" media="screen" />
  </head>
  <body>
    <div id="wrap">
      <header>
        <h1>jQuery Sticky Sidebar</h1>
        <div id="main">
          <h2>Product catalogue</h2>
          <ul id="products">
            <li>
              <h3>Product</h3>
              <img src="style/images/product.png" width="126" height="126" alt="product image" />
            </li>
            <li>
              <h3>Product</h3>
              <img src="style/images/product.png" width="126" height="126" alt="product image" />
            </li>
            <li class="end">
              <h3>Product</h3>
              <img src="style/images/product.png" width="126" height="126" alt="product image" />
            </li>
            <li>
              <h3>Product</h3>
              <img src="style/images/product.png" width="126" height="126" alt="product image" />
            </li>
            <li>
              <h3>Product</h3>
              <img src="style/images/product.png" width="126" height="126" alt="product image" />
            </li>
            <li class="end">
              <h3>Product</h3>
              <img src="style/images/product.png" width="126" height="126" alt="product image" />
            </li>
          </ul>
        </div>
        <div id="side">
          <div id="basket">
            <h3>Your basket</h3>
            <p>Total: <strong>&pound;455.00</strong></p>
            <span id="items">4</span>
          </div>
        </div>
    </div>
    <div id="stop-before"></div>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
    <script src="js/jquery.easing.1.3.js"></script>
    <script src="js/stickysidebar.jquery.js"></script>
    <script>
      $(function () {
        $("#basket").stickySidebar({
            timer: 400
          , easing: "easeInOutQuad"
          , stopBefore: '#stop-before'
        });
      });
    </script>
  </body>
</html>

Ο κώδικας javascript

(function($){

  var settings = {
        speed: 350 //animation duration
      , easing: "linear" //use easing plugin for more options
      , padding: 10
      , constrain: false
      , stopBefore: null
    }
    , $window = $(window)
    , stickyboxes = []
    , methods = {

          init:function(opts){
            settings = $.extend(settings,opts);
            return this.each(function () {
              var $this = $(this);
              setPosition($this);
              stickyboxes[stickyboxes.length] = $this;
              moveIntoView();
            });
          }

        , remove:function(){
            return this.each(function () {
              var sticky = this;
              $.each(stickyboxes, function (i, $sb) {
                if($sb.get(0) === sticky){
                reset(null, $sb);
                stickyboxes.splice(i, 1);
                return false;
                }
              });
            });
          }

        , destroy: function () {
            $.each(stickyboxes, function (i, $sb) {
              reset(null, $sb);
            });
            stickyboxes=[];
            $window.unbind("scroll", moveIntoView);
            $window.unbind("resize", reset);
            return this;
          }

      };


  var moveIntoView = function () {
    $.each(stickyboxes, function (i, $sb) {
      var $this = $sb
        , data = $this.data("stickySB");
      if (data) {
        var sTop = $window.scrollTop() - data.offs.top
          , currOffs = $this.offset()
          , origTop = data.orig.offset.top - data.offs.top
          , animTo = origTop;
        //scrolled down out of view
        if (origTop < sTop) {
					//make sure to stop inside parent
          console.log((sTop + settings.padding), data.offs.bottom);
          if ((sTop + settings.padding) > data.offs.bottom) {
            animTo = data.offs.bottom;
          }
          else {
            animTo = sTop + settings.padding;
          }
        }
        $this
          .stop()
          .animate(
              {top: animTo}
            , settings.speed
            , settings.easing
        );
      }
    });
  }

  var setPosition = function ($sb) {
    if ($sb) {
      var $this = $sb
        , $parent = $this.parent()
        , parentOffs = $parent.offset()
        , currOff = $this.offset()
        , data = $this.data("stickySB");
      if (!data) {
        data = {
            offs: {} // our parents offset
          , orig: { // cache for original css
                top: $this.css("top")
              , left: $this.css("left")
              , position: $this.css("position")
              , marginTop: $this.css("marginTop")
              , marginLeft: $this.css("marginLeft")
              , offset: $this.offset()
            }
        }
      }
      //go up the tree until we find an elem to position from
      while (parentOffs && "top" in parentOffs
        && $parent.css("position") == "static") {
        $parent = $parent.parent();
        parentOffs = $parent.offset();
      }
      if (parentOffs) { // found a postioned ancestor
        var padBtm = parseInt($parent.css("paddingBottom"), 10);
        padBtm = isNaN(padBtm) ? 0 : padBtm;
        data.offs = parentOffs;

        if (settings.stopBefore != null) {
          data.offs.bottom = $(settings.stopBefore).offset().top - $this.outerHeight() - data.offs.top - settings.padding;
        }
        else if (settings.constrain) {
          data.offs.bottom = Math.abs(($parent.innerHeight() - padBtm) - $this.outerHeight());
        }
        else {
          data.offs.bottom = $(document).height();
        }
      }
      else data.offs = { // went to far set to doc
          top: 0
        , left: 0
        , bottom: $(document).height()
      };
      $this.css({
          position: "absolute"
        , top: Math.floor(currOff.top - data.offs.top) + "px"
        , left: Math.floor(currOff.left - data.offs.left) + "px"
        , margin: 0
        , width: $this.width()
      }).data("stickySB", data);
    }
  }

  var reset = function (ev, $toReset) {
    var stickies = stickyboxes;
    if ($toReset) { // just resetting selected items
      stickies = [$toReset];
    }
    $.each(stickies, function(i, $sb) {
      var data = $sb.data("stickySB");
      if (data) {
        $sb.css({
            position: data.orig.position
          , marginTop: data.orig.marginTop
          , marginLeft: data.orig.marginLeft
          , left: data.orig.left
          , top: data.orig.top
        });
        if (!$toReset) { // just resetting
          setPosition($sb);
          moveIntoView();
        }
      }
    });
  }

  $window.bind("scroll", moveIntoView);
  $window.bind("resize", reset);

  $.fn.stickySidebar = function (method) {

    if (methods[method]) {
      return methods[method].apply(
          this
        , Array.prototype.slice.call(arguments, 1)
      );
    } else if (!method || typeof method == "object") {
      return methods.init.apply(this, arguments);
    }

  }

})(jQuery);

Το CSS

#wrap { width: 800px; margin: 0 auto; }
#main { width: 500px; height: 1500px; margin: 0 25px 0 0; float: left; }
#side {
  width: 275px;
  float: left;
  position: relative;
}
#basket {
  border: solid 1px silver;
  -moz-border-radius: 12px;
  -webkit-border-radius: 12px;
  border-radius: 12px;
  padding: 10px;
  background: white;
  position: relative;
}
#basket h3 {
  margin: 0 0 15px 0;
}
#basket p { margin: 32px 0 0 0; text-align: right; font-size: 1.2em; }
#items { 
  position: absolute; 
  top: 0px; 
  right: 6px;
  font-size: 1.4em;
  font-weight: bold;
  padding: 14px 38px 8px 6px;
  background: url(images/cart.png) right top no-repeat;
}
#products { margin: 0; padding: 0; list-style: none;}
#products li {
  width: 126px;
  margin: 0 25px 25px 0;
  float: left;
  padding: 10px;
  border: solid 2px #ddd;
  -moz-border-radius: 12px;
  -webkit-border-radius: 12px;
  border-radius: 12px;
  text-align: center;
}
.end { margin-right: 0 !important }

/* =Multi page demo
--------------------------------------------------------------------------*/
#right { width: 200px; float: left; }
#left { 
		width: 178px; 
		height: 800px; 
		float: left; 
		border: solid 1px red; 
		position: relative;
		padding: 10px;
}
#middle { width: 400px; float: left; height: 2000px; }
#navbox { 
  list-style: none;
  margin: 0;
  padding: 10px 10px 0 10px;
  border: solid 1px silver;
  height: 200px;
}
#navbox li {
  margin: 0 0 10px 0;
}

#realtest { 
	position: absolute; 
	left: 20px; 
	top: 450px; 
	height: 300px; 
	width: 300px; 
	border: solid 2px black;
}
#floatedbox {
  width: 150px;
  height: 150px;
  background-color: white; 
  position: absolute; 
  top: 10px; 
  left: 20px; 
  border: solid 1px silver;
  padding: 10px;
}
#stop-before {
  position: absolute;
  top: 800px;
  width: 100%;
  height: 600px;
  background: red;
  opacity: 0.4;
}

Πρόκειται για το script που κάλυψε καλύτερα τις απαιτήσεις μας από κάθε σχετικό javascript.

  • Δε χρειάζεται να γνωρίζετε το ύψος του block, sidebar που θα γίνει sticky
  • Δεν απαιτείται να γνωρίζετε το ύψος του κυρίως περιεχομένου δίπλα στο οποίο scrollarei το block
  • Έιναι "έξυπνο" καθώς μπορεί να οριστεί το div στο οποίο σταματάει το scrolling. Δε θα θέλατε να πέφτει το siebar πάνω στο footer σας..
  • Χρησιμοποιεί το Jquery library
  • Περιλαμβάνει τα easing effects για smooth scrolling
  • Ορίζετε την ταχύτητα του effect
  • Ρυθμίζεται το πάνω padding, πόσο θα απέχει από το πάνω μέρος του document.

Κατεβάστε το script από το GitHub