首页 > 解决方案 > 有没有更好的方法来扩展 div 的高度以包含其所有子元素?

问题描述

我有一个网页显示多个区域,这些区域的高度在来自数据库的内容放置在各自的区域并呈现网页之前不知道。在这个网页中,有一个父 div 使用三个 css url 显示背景图像,一个用于顶帽、一个中间重复图像和一个底帽,其想法是无论父 div 的整体高度如何,这些图像将填充父 div 的整个区域。这些图像不应被拉伸,否则它们看起来不正确。

所有三个图像都显示了,但中间的图像没有重复到足以填充父 div 的所有子元素后面的区域。但是,使用Chrome的inspect元素面板并专注于父div,我可以看到div的clientHeight属性为0,但是,如果我手动增加父div的高度样式,我可以手动设置这个高度,使背景完全填充以我想要的方式离开该地区。

同样,我不想将父级的高度样式设置为特定值,因为子 div 包含不同数量的文本,具体取决于页面应该显示的信息。

不幸的是,这个演示没有表现出这个初始的 clientHeight 问题。

即使我无法重现初始高度问题,我仍然希望就如何确保正确设置父 div 的高度以及背景正确延伸到所有子 div 后面的评论。

我的想法是这必须在 javascript 中完成,在页面呈现之后,所以我编写了下面的函数,在这里,我使用黄色背景色而不是背景图像来显示高度父分区

//
// Update the context_text_long class div's
// height to include the sum of the heights
// of all child divs when each div has a
// clientHeight.
//

//
// To prevent closure issues, create these
// global variables to used by the following
// function.
//

var $content_text_long,
    content_text_long,
    content_text_long_height,
    divs, divs_count, divs_index,
    total_height, counter;

//
// Use the jQuery ready function so that the code runs after the
// page is loaded and rendered...
//

$( function() {
     var handle;

     content_text_long =
       ( $content_text_long = $( '.content-text-long' ) )
       .get( 0 );

     initial_height =
     total_height   = $content_text_long.height();

     divs           = content_text_long.querySelectorAll( 'div' );

     divs_count     = divs.length; 
     divs_index     = 0;
     counter        = 0;

     //
     // The window.setInterval loops with a
     // fifth of a second delay until each
     // div has a clientHeight and it has
     // been added to the content_text_long
     // height.
     //

// alert( 'before' );
// debugger;

     handle =
       window.setInterval(
        function() {

          //
          // total_height is the cumulative
          // clientHeight of all of the divs
          // and the content_text_long div's
          // clientHeight, which it is
          // initially set, but if the
          // content_text_long div's
          // clientHeight is initially 0,
          // then get clientHeight until it
          // has a non-zero value.
          //

          var value = ( ( !total_height )
                        ? ( total_height = $content_text_long
                                           .height() )
                        : total_height );

          //
          // The divs, including the
          // content_text_long div, don't
          // seem to get their clientHeight
          // immediately after the page has
          // loaded and is ready, so use the
          // counter test to stop trying
          // to get their clientHeight
          // values in case they never load
          // and create an endless loop.
          // This mainly happens if there
          // actually no data for the area,
          // but with good data this should
          // not happen in production.
          //

          if( counter++ > 100 )

            if( confirm('keep trying?') ) {

              // OK

              counter = 0;

            }
            else {

              // Cancel

              value = false;
              clearInterval( handle );

            } // End of if(confirm(...)) ...
              //        else ...

          // End of if(counter++ > 100) ...

          //
          // Only process the divs when they
          // have clientHeights.
          //
          // When a div doesn't yet have a
          // clientHeight, don't enter this
          // while loop, instead exit this
          // interval loop and try the same
          // div the next time this function
          // executes.
          //

          while( value &&
                 ( value = divs[ divs_index ].clientHeight ) ) {

            //
            // This loop, allows all of the
            // consecutive divs that have
            // clientHeight per interval to
            // be summed up and added to
            // with the content_text_long
            // div's clientHeight, and that
            // assigned to the
            // content_text_long class div's
            // height style.
            //
            // This way the overall interval
            // delay duration is minimized.
            //

            total_height += value;
            content_text_long.style.height =
              total_height + 'px';

            //
            // Advance to the next div and
            // check that the index is
            // beyond the range of divs ...
            // Stop the interval looping
            // when done.
            //

            if( ++divs_index >= divs_count ) {

              clearInterval( handle );
              alert( 'done' );
              break;

            }

          } // End of while( ... ) ...

        },
        200 );

   } );
.content-text-long {
  background-color: yellow;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="content-text-long">
  <div class="profile">
      Read-Only value of an indeterminate length
    </div>

<!--
  //
  // In the real code the value displayed in
  // textarea, below, is checked and this
  // element structure is not injected by the
  // server-side code when the value is
  // empty.
  //
-->

  <div class="title">
    <textarea>
      Read-Only value of an indeterminate length
    </textarea>
  </div><!-- close artist-title class div -->

<!--
  //
  // The value displayed by the inner div is
  // checked and this element structure isn't
  // injected when empty.
  //
-->

  <div class="members">
    <h2>Members</h2>
    <div>
      Read-Only Value of an indeterminate length
    </div>
  </div><!-- close members Members div -->

<!--
  //
  // More element structures similar to those
  // shown above follow in the real code.
  //
-->

</div><!-- Close content-text-long class div -->

上面代码的问题在于,如果 clientHeight 设置正确并且不为 0,那么代码会将父 div 的高度加倍,但我稍后会解决这个问题。

我对比我目前使用的更好的解决方案更感兴趣。

如果有帮助,这里是一个 codepen 调试演示的链接。谢谢

标签: javascripthtmljquerycss

解决方案


这并不复杂:

/* css/external.css */
*{
  box-sizing:border-box;
}
html,body,#main{
  width:100%; height:100%; margin:0;
}
#main{
  display:flex; flex-direction:column;
}
#main>div{
  flex:1;
}
#top{
  background:center/cover url('https://www.texturex.com/wp-content/uploads/2018/03/sky-cloud-texture-white-fluffy-cloud-beautiful-blue-cloudscape-nature-weather-wallpaper-background-800x255.jpg');
}
#middle{
  background:url('https://vignette.wikia.nocookie.net/tekken/images/6/6c/200px-Mystical_Forest_-_Tekken_6.jpg/revision/latest/scale-to-width-down/250?cb=20140823070707&path-prefix=en'); padding:10px;
}
#middle>div{
  color:#fff; text-shadow:-1px 0 #000,0 1px #000,1px 0 #ccc,0 -1px #000;
}
#bottom{
  background:center/contain url('https://thumbs.dreamstime.com/t/fire-web-background-border-12532410.jpg');
}
<!DOCTYPE html>
<html lang='en'>
  <head>
    <meta charset='UTF-8' /><meta name='viewport' content='width=device-width, height=device-height, initial-scale:1, user-scalable=no' />
    <title>Title Here</title>
    <link type='text/css' rel='stylesheet' href='css/external.css' />
    <script src='js/external.js'></script>
  </head>
<body>
  <div id='main'>
    <div id='top'></div>
    <div id='middle'>
      <div>content</div>
      <div>content</div>
      <div>content</div>
      <div>content</div>
      <div>content</div>
    </div>
    <div id='bottom'></div>
  </div>
</body>
</html>

继续并在此处打开该完整页面链接,然后点击浏览器中的“还原” (双框)按钮并使用它。


推荐阅读