Search code examples
javascriptjquerypositionfixed

How to Make a Fixed Element Stay Relative to the Current Top Scroll Position?


Original Question:

I have a function which opens an overlaying, fixed-positioned element when prompted, and I am trying to figure out how to be able to open this at the current top position, instead of jumping to the top of the page (top: 0) every time the .no-scroll class is active.

Here is the progress I've made, thus far:

var o = 0;
$("img.click").click(function() {
  var s = $("html, body");
  o = $(window).scrollTop(), s.css("position", "fixed"), s.css("background-position", "0 -" + o + "px");
  var i = $(this).attr("src");
  s.find("#img-open").attr("src", i), s.addClass("no-scroll"), $("#img-view").addClass("target");
});

And I've additionally applied a .no-scroll class to the html, and body tags:

html {
  height: initial;
}

body {
  height: auto;
}

body.no-scroll,
html.no-scroll {
  overflow: hidden;
  -webkit-overflow-scrolling: touch;
}

Update (Applied Answer to Snippet + Additional Notes):

Thanks to this answer, I was able to adjust a few additional things:

  1. No need for a no-scroll class on the html tag. Therefore, it was removed.
  2. I added preventDefault() to the touchmove touch event, which keeps the body background content from scrolling on mobile browsers like iOS Safari, (as of 2018).

$(document).ready(function() {
  $("a.lbimg > img.lb-click").click(function() {
    $("#lb-view").addClass("target");
    var o = document.documentElement.scrollTop || document.body.scrollTop;
    $('body').addClass('no-scroll');
    document.documentElement.scrollTop = document.body.scrollTop = o;
    $('body').bind('touchmove', function(e) {
      e.preventDefault();
    });
  });
  $(".lbimg-wrap, #lb-controls").on("click", function(s) {
    $("#lb-view").removeClass("target");
    $('body').removeClass('no-scroll');
    $('body').unbind('touchmove');
  });
});
body {
  height: auto;
}

body,
html {
  width: 100%;
  background-size: cover;
  background-repeat: no-repeat;
}

body {
  background: #808080;
  margin: 0;
  padding: 0;
  border: 0;
}

body.no-scroll {
  overflow: hidden;
}

p.content {
  color: white;
}

img {
  padding: 5px;
  border: 1px solid;
  box-sizing: border-box;
  z-index: 1;
}

.img-wrap {
  display: block;
}

.img-wrap img {
  line-height: 0;
  display: block;
}

a.lbimg {
  cursor: pointer;
  display: block;
  line-height: 0;
}

a.lbimg img {
  margin: 0 auto;
  padding: 0;
  border: 0;
}

.lb-click {
  width: 25%;
  height: auto;
}

.customlightbox {
  top: 0;
  bottom: 0;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  position: fixed;
  left: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.7);
  opacity: 0;
  z-index: -1;
}

.lbimg-wrap {
  width: 100%;
  height: 100%;
  padding: 47px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  position: relative;
  text-align: center;
}

.customlightbox img {
  border-color: white;
  width: auto;
  margin: auto;
  max-width: 100%;
  max-height: 100%;
  opacity: 0;
  position: relative;
  top: 50%;
  -webkit-transform: translateY(-50%);
  -ms-transform: translateY(-50%);
  transform: translateY(-50%);
}

#lb-controls {
  cursor: pointer;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  position: fixed;
  height: 50px;
  width: 50px;
  top: -50px;
  right: -3px;
  border-left: 1px solid;
  border-bottom: 1px solid;
  border-color: white;
  z-index: 3;
}

#lb-close {
  display: block;
  position: absolute;
  overflow: hidden;
  height: 30px;
  width: 30px;
  right: 10px;
  top: 10px;
  -webkit-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  transform: rotate(45deg);
}

#lb-close:before,
#lb-close:after {
  content: '';
  display: block;
  position: absolute;
  background: white;
  -webkit-border-radius: 2px;
  -moz-border-radius: 2px;
  border-radius: 2px;
}

#lb-close:before {
  width: 2px;
  height: 0;
  top: 0;
  left: 14px;
}

#lb-close:after {
  width: 0;
  height: 2px;
  top: 14px;
  left: 0;
}

.customlightbox.target {
  display: inline-block;
  z-index: 2;
}

.customlightbox.target,
.customlightbox.target img {
  opacity: 1;
}

.customlightbox.target~#lb-controls {
  top: -3px;
}

.customlightbox.target~#lb-controls #lb-close:after {
  width: 30px;
}

.customlightbox.target~#lb-controls #lb-close:before {
  height: 30px;
}

.lb-animate {
  -webkit-transition: 0.5s ease-in-out;
  -o-transition: 0.5s ease-in-out;
  transition: 0.5s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>

  <p class="content">
    Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
    to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
    to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
    to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
    to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
    to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll.
  </p>

  <div class="img-wrap">
    <a class="lbimg">
      <img class="lb-click" src="https://78.media.tumblr.com/8b1b8cbb2b963ab64eb2341f608638bf/tumblr_p4wbo7ZLJS1qccr26o1_1280.jpg">
    </a>
    <div class="customlightbox lb-animate" id="lb-view">
      <div class="lbimg-wrap">
        <img class="lb-animate" id="lbimg-open" src="https://78.media.tumblr.com/8b1b8cbb2b963ab64eb2341f608638bf/tumblr_p4wbo7ZLJS1qccr26o1_1280.jpg">
      </div>
    </div>
    <div id="lb-controls" class="lb-animate">
      <a id="lb-close" class="lb-animate"></a>
    </div>
  </div>

  <p class="content">
    Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
    to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
    to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
    to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
    to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
    to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll.
  </p>

</body>


Solution

  • You were almost there:

    $(document).ready(function() {
    
      $("a.lbimg > img.lb-click").click(function() {
        $("#lb-view").addClass("target");
        var o = document.documentElement.scrollTop || document.body.scrollTop;
        $('html, body').addClass('no-scroll');
        document.documentElement.scrollTop = document.body.scrollTop = o;
      });
    
      $(".lbimg-wrap, #lb-controls").on("click", function(s) {
          $("#lb-view").removeClass("target");
          $('html, body').removeClass('no-scroll');
      });
      
    });
    html {
      height: initial;
    }
    
    body {
      height: auto;
    }
    
    body,
    html {
      width: 100%;
      background-size: cover;
      background-repeat: no-repeat;
    }
    
    body {
      background: #808080;
      margin: 0;
      padding: 0;
      border: 0;
    }
    
    body.no-scroll,
    html.no-scroll {
      overflow: hidden;
    }
    
    p.content {
      color: white;
    }
    
    img {
      padding: 5px;
      border: 1px solid;
      box-sizing: border-box;
      z-index: 1;
    }
    
    .img-wrap {
      display: block;
    }
    
    .img-wrap img {
      line-height: 0;
      display: block;
    }
    
    a.lbimg {
      cursor: pointer;
      display: block;
      line-height: 0;
    }
    
    a.lbimg img {
      margin: 0 auto;
      padding: 0;
      border: 0;
    }
    
    .lb-click {
      width: 25%;
      height: auto;
    }
    
    .customlightbox {
      top: 0;
      bottom: 0;
      -webkit-box-sizing: border-box;
      box-sizing: border-box;
      position: fixed;
      left: 0;
      right: 0;
      background: rgba(0, 0, 0, 0.7);
      opacity: 0;
      z-index: -1;
    }
    
    .lbimg-wrap {
      width: 100%;
      height: 100%;
      padding: 47px;
      -webkit-box-sizing: border-box;
      box-sizing: border-box;
      position: relative;
      text-align: center;
    }
    
    .customlightbox img {
      border-color: rgba(255, 255, 255, .5);
      width: auto;
      margin: auto;
      max-width: 100%;
      max-height: 100%;
      opacity: 0;
      position: relative;
      top: 50%;
      -webkit-transform: translateY(-50%);
      -ms-transform: translateY(-50%);
      transform: translateY(-50%);
    }
    
    #lb-controls {
      cursor: pointer;
      -webkit-box-sizing: border-box;
      box-sizing: border-box;
      position: fixed;
      height: 50px;
      width: 50px;
      top: -50px;
      right: -3px;
      border-left: 1px solid;
      border-bottom: 1px solid;
      opacity: .7;
      border-color: rgba(255, 255, 255, .7) !important;
      z-index: 3;
    }
    
    #lb-close {
      display: block;
      position: absolute;
      overflow: hidden;
      height: 30px;
      width: 30px;
      right: 10px;
      top: 10px;
      -webkit-transform: rotate(45deg);
      -ms-transform: rotate(45deg);
      transform: rotate(45deg);
    }
    
    #lb-close:before,
    #lb-close:after {
      content: '';
      display: block;
      position: absolute;
      background: white;
      -webkit-border-radius: 2px;
      -moz-border-radius: 2px;
      border-radius: 2px;
    }
    
    #lb-close:before {
      width: 2px;
      height: 0;
      top: 0;
      left: 14px;
    }
    
    #lb-close:after {
      width: 0;
      height: 2px;
      top: 14px;
      left: 0;
    }
    
    .customlightbox.target {
      opacity: 1;
      display: inline-block;
      z-index: 2;
    }
    
    .customlightbox.target img {
      opacity: 1;
    }
    
    .customlightbox.target~#lb-controls {
      top: -3px;
    }
    
    .customlightbox.target~#lb-controls #lb-close:after {
      width: 30px;
    }
    
    .customlightbox.target~#lb-controls #lb-close:before {
      height: 30px;
    }
    
    .lb-animate {
      -webkit-transition: 0.5s ease-in-out;
      -o-transition: 0.5s ease-in-out;
      transition: 0.5s ease-in-out;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <body>
    
      <p class="content">
        Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
        to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
        to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
        to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
        to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
        to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll.
      </p>
    
      <div class="img-wrap">
        <a class="lbimg">
          <img class="lb-click" src="https://78.media.tumblr.com/8b1b8cbb2b963ab64eb2341f608638bf/tumblr_p4wbo7ZLJS1qccr26o1_1280.jpg">
        </a>
        <div class="customlightbox lb-animate" id="lb-view">
          <div class="lbimg-wrap">
            <img class="lb-animate" id="lbimg-open" src="https://78.media.tumblr.com/8b1b8cbb2b963ab64eb2341f608638bf/tumblr_p4wbo7ZLJS1qccr26o1_1280.jpg">
          </div>
        </div>
        <div id="lb-controls" class="lb-animate">
          <a id="lb-close" class="lb-animate"></a>
        </div>
      </div>
    
      <p class="content">
        Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
        to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
        to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
        to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
        to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content
        to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll. Content to scroll.
      </p>
    
    </body>