jQuery居中div在父div可见区域内

4
我有一个 <div>,我想要在其父级 <div> 的可见区域内垂直居中。这是一个演示图像,点击这里。白色圆圈代表子 <div>,灰色矩形代表父 <div>,白色矩形代表浏览器的视口。
我的问题是如何编写公式来定位子 <div>,使其在浏览器滚动或调整大小时适用于任何大小的子或父 <div>
var scrollListener = function(){
    var child = $('.child'),        // child element
    w=$(window).height,             // window height
    s=$(window).scrollTop(),        // window scrollTop position
    t=child.parent().offset().top,  // parent position in window
    h=child.parent().height(),      // parent height
    p=(w+s-t),                      // initial position
    v=0;                            // final value for child position

    if( t<s ){
       // top of parent is beyond viewport
       if( p<h ){
          // bottom of parent is also beyond viewport
          v = (w/2)+s-t;
       }else{
          // ??? - not working
          // bottom of parent is within viewport
          v = ((h-p)/2)+s-t;
       }
    }else{
       v = p/2;
    }
    child.css("top",v);
};

$(window).on("scroll resize",scrollListener);

Fiddle


2
什么是问题/难题? - depperm
你在哪里调用scrollListener? - Jonas Wilms
position: relative.childmargin: auto将中心对齐黑色方框。 这就是您想要的吗? - RST
@RST 可以将子元素居中于父元素内,但是居中位置可能会超出视口。我想要将子元素居中于可见的父元素区域。这里有一个更新后的 JSFiddle:https://jsfiddle.net/uzbyy7dw/2/。 - Aaron
抱歉,我不明白你想做什么。也许其他人会知道。 - RST
显示剩余3条评论
1个回答

1
我找到了解决方案,可以在这里找到一个可行的示例 https://jsfiddle.net/uzbyy7dw/6/
几乎所有原始计算都被放弃了。 我的新方法是确定父 <div> 的顶部边缘是否在浏览器的视口之外,然后根据父元素底部边缘是否在视口之外计算子 <div> 的垂直中心位置。
请注意,子 <div> 在父 <div> 中具有绝对位置。

(function($){
var scrollListener = function(){
    $('.child').each(function(){
    var child = $(this),            // child div element
    w=$(window).height(),           // window height
    s=$(window).scrollTop(),        // window scrollTop position
    t=child.parent().offset().top,  // parent top edge
    h=child.parent().height(),      // parent height
    r=(w+s-t),                      // parent's initial visible area
    // parent's bottom edge in relation to the viewport
    // calculated by the parent's height minus it's initial visible area
    b=h-r,                          
    v=0;                            // final value for child position
    if( t<s ){
       /*
       The amount scrolled is greater than the parent's offset
       thus, the parent's top edge is outside the viewport
       */
       if( 0 < b ){
            /*
            When the parent's bottom edge is greater than 0 then
            it's bottom edge is below the bottom of the viewport
            
            Since both the top and bottom edge exceed the viewport 
            some middle section of the parent is spanning the
            full height of the viewport.  The child's position will be
            in the middle of viewport, but offset by the amount
            scrolled minus the parent's top offset
            */
            v = (w/2)+s-t;
       }else{
            /*
            The parent's top edge is outside the viewport, but the
            bottom edge is within the viewport
            
            Calculate the middle position by taking the amount scrolled
            minus the parent's offset and the parent's height, which
            will get the remaining visible area of the parent div, then
            divide by two to get the middle
            */
            v = (s-t+h)/2;
       }
    }else{
        /*
        The parent's top edge is greater than the amount scrolled
        thus, the parent top edge has not exceeded the viewport
        */
     if( 0 < b ){
           /*
            When the parent's bottom edge is greater than 0 then
            it is below the bottom of the viewport
            
            Since the parent's top edge has not exceeded the viewport
            and bottom edge HAS exceed the viewport, use the parent's
            initial position determined by adding the window's height
            and the amount scrolled then subtract the parent's offset.
            
            Divide this position by two to get the middle of the
            parent's visible area, unless the parent's top edge is
            below the viewport's bottom edge then the parent is out of
            view and the child will be too
            */
            v = r/2;
        }else{
           /*
            Both the top and bottom edges of the parent div are within
            the viewport.  Vertically center the child div within the
            parent by dividing the parent's height by 2 to get its
            middle
            */
            v = h/2;
      }
    }
    
    child.css("top",v);
    });
};

$(window).on("scroll resize",scrollListener);
scrollListener();
})(jQuery);
html,body { background:white; height:100%; }
body{ margin-top:140%; }
.middle-line {
  position:fixed;
  top:50%;
  width:100%;
  z-index:100;
  border-top:1px solid #2495ec;
}
.parent1, .parent2 {
  float:left;
  width:30%;
  margin-left:10px;
  position:relative;
}

.parent1 {
  background:#ccc;
  height:120%;
  margin-top:-50px;
  }
.parent2 {
  background:#aaa;
  height:50%;
}
.child {
  background:#000;
  color:#fff;
  line-height:50px;
  text-align:center;
  position:absolute;
  height:50px;
  width:50px;
  left:50%;
  transform:translate(-50%,-50%);
}
.other-stuff{
  height:800px;
  clear:both;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="parent1">
<div class="child"></div>
</div>
<div class="parent2">
<div class="child"></div>
</div>
<div class="other-stuff"></div>
<div class="middle-line"></div>


1
我找到了解决方案 - 那么这个解决方案是什么?回答自己的问题没问题,但我不会去比较文件来找出问题所在、你做了哪些更改以及为什么要这样做。 - Stephen P
@StephenP -- 问题完全在于计算方式。我已经更新了我的答案,并添加了更多的js注释细节。 - Aaron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接