5
\$\begingroup\$

I have made some jQuery Fallback Support for the CSS Property "background-attachment: local" and I am mainly a CSS developer. I do some jQuery, but I thought I would check to see if I am doing this in the more efficient way, as I may have multiple versions of this on one page.

CODEPEN DEMO

HTML

<div class="container">
  <div class="data-holder">
    <div id="shadowtop"></div>
    <div id="shadowbottom"></div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
    <div class="block">hello</div>
  </div>
</div>

CSS

@import "http://fonts.googleapis.com/css?family=Open+Sans:400,600,700";
* {
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}
body {
    background: none repeat scroll 0 0 #fff;
    font-family: "Open Sans";
    line-height: 26px;
    margin: 20px;
}

.container {
  position: relative;
  margin-top: 30px;
}

.data-holder {
  border-top: 1px solid #eee;
  border-bottom: 1px solid #eee;
  width: 200px;
  height: 300px;
  overflow: auto;
}

#shadowtop,
#shadowbottom {
  position: absolute;
  left: 0;
  height: 12px;
  width: 180px;
  z-index: 9999;
  display: none;
  background-size: 100% 12px;

}
#shadowtop {
  top: 0;
  background:   radial-gradient(farthest-side at 50% 0, rgba(0,0,0,.15), rgba(0,0,0,0)) 0 100%;
}
#shadowbottom {
  bottom: 0;
  background:   radial-gradient(farthest-side at 50% 100%, rgba(0,0,0,.15), rgba(0,0,0,0)) 0 100%;
}

.block {
  background: #fff;
  border-bottom: 1px solid #f4f4f4;
  padding: 10px;
}
.block:last-child {
  border-bottom: 0 none;
}

jQuery

$(document).ready(function(){
  $('.data-holder').scroll(function(){
    var scrollValue = $(this).scrollTop();
    var elementHeight = $(this).height();
    if(scrollValue == 0){
      $("#shadowtop").fadeOut(200);
      console.log("at top");  //should remove
    } else if (scrollValue == ($(this).get(0).scrollHeight - $(this).height())){
      $("#shadowbottom").fadeOut(200);
      console.log("at bottom"); //should remove
    } else {
      console.log("in middle"); //should remove
      $("#shadowtop").fadeIn(200);
      $("#shadowbottom").fadeIn(200);
    }
  });
  var scrollValue = $('.data-holder').scrollTop();
  if(scrollValue < ($('.data-holder').get(0).scrollHeight - $('.data-holder').height())){
     $("#shadowbottom").show();
  }
});
\$\endgroup\$
2
+50
\$\begingroup\$

This code annoyed me for a while, the part outside of the initialization does not belong and it seemed silly to add it to the listener. Plus, the code outside of the listener will mess up when you have multiple data-holder elements.

Then I realized that I could take a different approach, do this in 2 steps:

  1. Determine whether I should hide or show the top
  2. Determine whether I should hide or show the bottom

Then, I do not need the piece of code outside of the listener, and it becomes cleaner. Also, the 200 has to be a constant, also I would take only the #shadowbottom and #shadowtop belonging to the .data-holder.

So, in all, I would counter propose:

$(document).ready(function(){
  var fadeSpeed = 200;
  $('.data-holder').scroll(function(){
    var scrollValue = $(this).scrollTop(),
        elementHeight = $(this).height(),
        $top = $(this).children('#shadowtop'),
        $bottom = $(this).children('#shadowbottom'),
        atTop = (scrollValue == 0),
        atBottom = (scrollValue == ( this.scrollHeight - elementHeight));
    (atTop)   ? $top.fadeOut( fadeSpeed )    : $top.fadeIn( fadeSpeed );
    (atBottom)? $bottom.fadeOut( fadeSpeed ) : $bottom.fadeIn( fadeSpeed );
  }).scroll();
});

I was mildly worried that with each scroll event the top / bottom might flicker because of the repeated fadeIn() calls, but I can tell from your CodePen that does not happen, so there is nothing to worry about there.

Finally, I did not look at your CSS as you actually are a CSS developer and also I did not test my code, but I am confident you get where I am going with this.

\$\endgroup\$
1
  • \$\begingroup\$ Very nice answer. Thank you. codepen.io/2ne/pen/gELai works here with 2 elements and it is a lot easier to see how your code is done. More universal \$\endgroup\$
    – 2ne
    Jan 24 '14 at 20:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.