获得一个粘性标题来“向上推”,就像在 Instagram 的 iPhone 应用程序中使用 CSS 和 jQuery

IT技术 javascript html css Instagram
2021-03-13 10:49:33

Instagram 应用程序有一个很好的粘性标题,可以将当前的标题推到新的位置。我找到了一个很棒的教程,介绍了如何为 Android 原生地执行此操作,但我希望使用 JavaScript 和 CSS 来执行此操作。

我能够让我的标题切换到一个新的标题,但我似乎无法找到一种方法来模仿 Instagram 的做法。任何帮助是极大的赞赏。

*编辑:在评论中指出的使用航点作为 Cj 滚动时,我能够让标题粘在页面顶部。链接到航点)。我遇到的主要问题是获得 Instagram 在其 iPhone 移动应用程序中使用的“俯卧撑”效果。我会链接到一个例子,但我以前从未见过它被使用过。*

* * 编辑 2:使用@Chris 提供的部分代码笔,我能够将标题固定下来。然后我添加了一个 .slideUp 效果。我现在的问题是让 .slideUp 效果只在到达下一个标题时发生。现在效果在滚动时激活。

这是代码:

(function() {
function stickyTitles(stickies) {
    this.load = function() {
        stickies.each(function(){
            var thisSticky = jQuery(this);
            jQuery.data(thisSticky[0], 'pos', thisSticky.offset().top);
        });
    }
    this.scroll = function() {      
        stickies.each(function(){           
            var thisSticky = jQuery(this),          
                pos = jQuery.data(thisSticky[0], 'pos');
            if (pos <= jQuery(window).scrollTop()) {
                thisSticky.addClass("fixed");
                // added this 
                 $(".followMeBar:parent").slideUp();

            } else {
                thisSticky.removeClass("fixed");
            }
        });         
    }
}
jQuery(document).ready(function(){
    var newStickies = new stickyTitles(jQuery(".followMeBar"));
    newStickies.load();
    jQuery(window).on("scroll", function() {
        newStickies.scroll();

    }); 
});

})();

6个回答

对此没有快速或简单的答案,但通过一些创造性的哄骗,我们可以模拟相同的功能。

我们需要的是一系列我们可以识别、循环然后设置的元素,这样当我们点击它们在页面上的位置时,前一个项目被推上,新项目固定。我们将需要使用 jQuery 的offset().top方法检索元素的初始位置并将其存储在data标签中,以便我们稍后引用它。然后将在我们滚动时计算其余部分。

这应该可以解决问题:

var stickyHeaders = (function() {

  var $window = $(window),
      $stickies;

  var load = function(stickies) {

    if (typeof stickies === "object" && stickies instanceof jQuery && stickies.length > 0) {

      $stickies = stickies.each(function() {

        var $thisSticky = $(this).wrap('<div class="followWrap" />');
  
        $thisSticky
            .data('originalPosition', $thisSticky.offset().top)
            .data('originalHeight', $thisSticky.outerHeight())
              .parent()
              .height($thisSticky.outerHeight()); 			  
      });

      $window.off("scroll.stickies").on("scroll.stickies", function() {
		  _whenScrolling();		
      });
    }
  };

  var _whenScrolling = function() {

    $stickies.each(function(i) {			

      var $thisSticky = $(this),
          $stickyPosition = $thisSticky.data('originalPosition');

      if ($stickyPosition <= $window.scrollTop()) {        
        
        var $nextSticky = $stickies.eq(i + 1),
            $nextStickyPosition = $nextSticky.data('originalPosition') - $thisSticky.data('originalHeight');

        $thisSticky.addClass("fixed");

        if ($nextSticky.length > 0 && $thisSticky.offset().top >= $nextStickyPosition) {

          $thisSticky.addClass("absolute").css("top", $nextStickyPosition);
        }

      } else {
        
        var $prevSticky = $stickies.eq(i - 1);

        $thisSticky.removeClass("fixed");

        if ($prevSticky.length > 0 && $window.scrollTop() <= $thisSticky.data('originalPosition') - $thisSticky.data('originalHeight')) {

          $prevSticky.removeClass("absolute").removeAttr("style");
        }
      }
    });
  };

  return {
    load: load
  };
})();

$(function() {
  stickyHeaders.load($(".followMeBar"));
});
.followMeBar {
  background: #999;
  padding: 10px 20px;
  position: relative;
  z-index: 1;
  color: #fff;
}
.followMeBar.fixed {
  position: fixed;
  top: 0;
  width: 100%;
  box-sizing: border-box;
  z-index: 0;
}
.followMeBar.fixed.absolute {
  position: absolute;
}
/* For aesthetics only */

body {
  margin: 0;
  font-family: Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="followMeBar">A</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">B</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">C</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">D</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">E</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">F</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">G</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">H</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">I</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">J</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">K</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">L</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">M</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">N</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">O</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">P</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">Q</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">R</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">S</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">T</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">U</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">V</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">W</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">X</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">Y</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">Z</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>

这是仅 CSS 版本:

在你说“什么?!当只有 CSS 版本时,我刚刚经历了所有这些?!” 它只适用于几个浏览器。例如在 Firefox 中试试这个:

.sticky {
  position: -webkit-sticky;
  position: -moz-sticky;
  position: -o-sticky;
  position: -ms-sticky;
  position: sticky;
  top: 0;
  left: 0;
  right: 0;
  display: block;
  z-index: 1;
  background: #999;
  color: #fff;
  padding: 10px 20px;
}

/* For aesthetics only */
body {
  margin: 0;
  font-family: Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif;
}
<div data-lorem="p">
  <span class="sticky">a</span>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
</div>
<div data-lorem="p">
  <span class="sticky">b</span>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
</div>
<div data-lorem="p">
  <span class="sticky">c</span>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
</div>
<div data-lorem="p">
  <span class="sticky">d</span>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
</div>
<div data-lorem="p">
  <span class="sticky">e</span>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
</div>
<div data-lorem="p">
  <span class="sticky">f</span>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
</div>
<div data-lorem="p">
  <span class="sticky">g</span>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
</div>
<div data-lorem="p">
  <span class="sticky">h</span>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
</div>

http://caniuse.com/#feat=css-sticky

我已经调整了 Chris 的 codepen 以在可滚动的 div codepen.io/jakeyadda/pen/kaFhI 中工作
2021-04-25 10:49:33
@ChrisSpittles - 非常感谢!我只需要添加一些逻辑来检查粘性的位置是否已经确定,否则如果您当时向下滚动页面,它将错误地重新定位。其他人需要的完整代码:codepen.io/anon/pen/blJrC
2021-05-05 10:49:33
克里斯,喜欢这个代码!对于任何人谁是想知道我能得到一个滚动中此代码工作<div>通过改变offset().top引用position().top和滚动事件连接到<div>代替window您可能需要稍微调整 CSS,但效果很好!
2021-05-06 10:49:33
这不是一个非常优雅的解决方案,但我将 50px 硬编码到固定顶部定位,然后将元素何时应成为固定元素(第 24 行)的检查调整为 50 像素,对绝对定位环绕的检查调整为 50 像素(第 28 行)并且绝对定位的环绕应该失去其绝对定位 50 像素(第 38 行)。保存在这里:codepen.io/seraphzz/pen/GpeCi
2021-05-10 10:49:33
@jetlej 您必须重构示例以允许添加如下元素:codepen.io/chrissp26/pen/vfgwb
2021-05-18 10:49:33

首先,感谢@Chris Spittle 的出色回答。

我创建了一个修改版本,不需要包装每个粘性元素,因为它只是改变它们的相对位置而不是使用固定定位。

var stickyHeaders = (function() {

    var $stickies;

    var load = function(stickies, target) {

        if (typeof stickies === "object" && stickies instanceof jQuery && stickies.length > 0) {

            $stickies = stickies.each(function() {

                var $thisSticky = $(this);

                $thisSticky
                    .data('originalPosition', $thisSticky.offset().top)
                    .data('originalHeight', $thisSticky.outerHeight());               
            });

            target.off("scroll.stickies").on("scroll.stickies", function(event) {
                 _whenScrolling(event);     
            });
        }
    };

    var _whenScrolling = function(event) {

        var $scrollTop = $(event.currentTarget).scrollTop();

        $stickies.each(function(i) {            

            var $thisSticky = $(this),
                $stickyPosition = $thisSticky.data('originalPosition'),
                $newPosition,
                $nextSticky;

            if ($stickyPosition <= $scrollTop) {

                $newPosition = Math.max(0, $scrollTop - $stickyPosition);
                $nextSticky = $stickies.eq(i + 1);

                if($nextSticky.length > 0) {

                    $newPosition = Math.min($newPosition, ($nextSticky.data('originalPosition') -  $stickyPosition) - $thisSticky.data('originalHeight'));
                }

            } else {

                $newPosition = 0;
            }

            $thisSticky.css('transform', 'translateY(' + $newPosition + 'px)');

            //could just as easily use top instead of transform
            //$thisSticky.css('top', $newPosition + 'px');
        });
    };

    return {
        load: load
    };
})();

$(function() {
    stickyHeaders.load($(".followMeBar"), $(window));
});

css简化为:

.followMeBar {
    background: #999;
    padding: 10px 20px;
    position: relative;
    z-index: 1;
    color: #fff;
}

/* For aesthetics only */

body {
    margin: 0;
    font-family: Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif;
}

http://plnkr.co/edit/wk3h40LfBdN1UFtDLZgY?p=preview

这是另一个示例,展示了在使用固定标头时如何获得偏移量:

http://plnkr.co/edit/8YBqdCIKruVKYRXbZnCp?p=preview

@akshay OP 没有要求使用引导程序解决方案
2021-05-13 10:49:33
这在与引导程序一起使用时会出现问题,请参阅jsfiddle.net/pzquzLxh/2
2021-05-15 10:49:33
伟大的!更简单,也应该更快。但是有一个问题:我们如何防止我们在移动设备上看到的弹性滚动问题?只需在手机上加载示例页面embed.plnkr.co/wk3h40LfBdN1UFtDLZgY/preview看看我的意思
2021-05-17 10:49:33

我尝试了上面提供的解决方案,但没有一个可以完美运行而没有错误(主要是滚动和浏览器兼容性方面的错误)。刚刚找到了这个https://github.com/sarahdayan/feedify,它对我很有用。

确保将其包裹起来 div

注意第 6 个标题,因为它没有被包裹 div

h1, h2{
position: sticky;
top: 0;
}

div{
height: 500px;
}
<div>
<h1>lorem ipsum doloro sit <br> amet 1</h1>
</div>

<div>
<h1>lorem ipsum doloro sit 2</h1>
</div>

<div>
<h2>lorem ipsum doloro sit 3</h2>
</div>

<div>
<h1>lorem ipsum doloro sit <br> amet 4</h1>
</div>

<div>
<h2>lorem ipsum doloro sit <br> amet 5</h2>
</div>

<h2>lorem ipsum doloro sit <br> amet 6</h2>

<div></div>

<div>
<h1>lorem ipsum doloro sit  7</h1>
</div>

<div>
<h1>lorem ipsum doloro sit <br> amet 8</h1>
</div>

<div>
<h1>lorem ipsum doloro sit <br> amet 9</h1>
</div>

我很难让 Chris 的答案准确地为我工作,因为所有的便签都在一个相对定位的 div 内(在它上面有一个标题,在相对 div 之外)——这个问题的答案只是存储 .offset() var 中相对容器 div 的 .top 并从脚本中的 .css('top', value ) 中减去它与 chris 的版​​本一样,最高值是从文档顶部推出,效果很好。当您添加相对 div 时,top 现在从它的顶部推动,因此相对 div 上方的任何空间都包含在值中,这是您不想要的。希望这对其他人有帮助。詹姆士

此外,当我在页面向下滚动时刷新页面时遇到问题。这似乎会干扰 jquery 获取正确的 offset.top 值,因此当它重新加载时,粘性会以奇怪的方式偏移。(如果我想出解决方案,我会在这里发布)
2021-05-03 10:49:33
好的,很明显,问题只是在 chrome(webkit 浏览器)中 - 我通过将整个内容包装在 $(window).load() 中来处理它,因为答案在这篇文章中:stackoverflow.com/questions/2173040/...
2021-05-19 10:49:33