Tuesday, February 27, 2018

How control vertical spacing of div children?

Leave a Comment

Task:

Keep a vertical list of thumb nails. Thumb nails must scale with window dimensions. Thumb nails are contained in a div the dimensions of which are given using vw, vh. On every resize, a Javascript function recomputes width and height of all thumb nails so that a fixed number of them appears in the visible area of the div and is as big as possible. To keep the thumb nails' vertical spacing constant, the height of the visible thumb nails is added up, increased by a factor and assigned to the div's height.

Problem:

When making the window very narrow, vertical space between the thumb nails is getting bigger and bigger. The values calculated for hFit and hTotal (see Javascript code below) seem to be incorrect and lead to unwanted overlay or too big vertical spacing of the thumb nails.

Details:

The entire layout is as follows:

An outmost div (.content-area) controls vertical alignment of the entire control (centered). A child of .content-area (.content-control) controls the layout of the actual list (.content-data) plus a close button (.close-btn-area) that will appear left of that list.

Code:

CSS:

.content-area {     position: absolute;     left: 2vw;     top: 5vh;     width: 30vw;     height: 90vh;     display: flex;     flex-direction: column;     align-items: start;     justify-content: center;     list-style: none;     opacity: 0.0; }  .content-control {     position: relative;     margin: 0 0 0 0;     display: flex;     flex-direction: row;     align-items: start;     justify-content: flex-start;     overflow: hidden; }  .content-data {     position: relative;     margin: 0 0 0 0;     padding: 0 0 0 0;     width: auto;     display: flex;     flex-direction: column;     align-items: center;     justify-content: center;     overflow: hidden; }  #thumbs-content {     margin: 1vmin 1vmin 1vmin 1vmin;     height: 78vh;     font-family: 'Alegreya Sans SC', Verdana, sans-serif;     font-variant: small-caps;     overflow: hidden;     color:#404040; }  .thumb-size {     margin: 1vmin 0;     width: 16vw;     height: 12vh;     display: flex;     justify-content: center;     align-items: center;         }  .close-btn-area {     margin: 1vmin 1vmin 1vmin 1vmin;     width: 4vh;     height: 4vh;     display: flex;     align-items: start;     justify-content: flex-start;     cursor: pointer;     -webkit-user-select: none;     -khtml-user-select: none;     -moz-user-select: none;     -o-user-select: none;     -ms-user-select: none;     user-select: none; }  .close-btn {     width:    4vh;     height: 4vh;     border: 0; } 

HTML:

<div class="content-area" id="thumbs-area">     <div class="content-control" id="thumbs-control">          <div class="close-btn-area" id="close-thumbs">              <a><img class="close-btn" id="close-btn-thumbs" src="close-btn-inverted-128x128.png">          </div>          <div class="content-data" id="thumbs-data">             <article id="thumbs-content">                 <div class="thumb-size"><img class="thumb" id="thumb1" src="img1.jpg"></div>                 <div class="thumb-size"><img class="thumb" id="thumb2" src="img2.jpg"></div>                 <div class="thumb-size"><img class="thumb" id="thumb3" src="img3.jpg"></div>                 <div class="thumb-size"><img class="thumb" id="thumb4" src="img4.jpg"></div>                 <div class="thumb-size"><img class="thumb" id="thumb5" src="img5.jpg"></div>                 <div class="thumb-size"><img class="thumb" id="thumb6" src="img6.jpg"></div>                 <div class="thumb-size"><img class="thumb" id="thumb7" src="img7.jpg"></div>                 <div class="thumb-size"><img class="thumb" id="thumb8" src="im8.jpg"></div>                 <div class="thumb-size"><img class="thumb" id="thumb9" src="im9.jpg"></div>                 <div class="thumb-size"><img class="thumb" id="thumb10" src="img10jpg"></div>                 <div class="thumb-size"><img class="thumb" id="thumb11" src="img11.jpg"></div>             </article>         </div>     </div> </div> 

JavaScript:

const nVisibleThumbs = 6; var nTopThumb = 0; var nThumbCount = 11; // simplified; will be computed in the actual code var nThumbScale = 0.9;  function RecalcThumbsLayout ()  {     var elem = $('#thumbs-content');     var w = elem.width ();     var h = Math.round (elem.height () * nThumbScale);     var hFit = 0;     var wFit = 0;     var hTotal = 0;      for (i = 1; i <= nThumbCount; i = i + 1)      {         var idStr = "#thumb" + i;         var ar = Math.min (1.5, $(idStr).prop ('naturalWidth') / $(idStr).prop ('naturalHeight'));         var ph = Math.round (h / nVisibleThumbs * 0.9);         var pw = Math.round (Math.min (ph * ar, w * 0.9));         ph = Math.floor (pw / ar); // considers portrait format images         $(idStr).css ("width", pw);         $(idStr).css ("height", ph);         hTotal += ph;         if ((i > nTopThumb) && (i <= nTopThumb + nVisibleThumbs))             hFit += ph;         if (wFit < pw)             wFit = pw;     }     wFit *= 1.25; // compensate for scaling above     hFit *= 1.25; // compensate for scaling above     $('#thumbs-data').css ('width', wFit + 'px');      $('#thumbs-data').css ('height', hFit + 'px');      elem.css ('height', hTotal + 'px'); } 

Demonstration:

To see the unwanted effect, you can go here: http://www.brockart.de/S, click on "Schmuck" and then horizontally resize the browser window.

Questions:

  1. What do I need to change in the Javascript to make this work?
  2. Is there a more elegant way to do this with css / html only?

3 Answers

Answers 1

You might get it without JS and with a simpler HTML and CSS (flexboxes and excessive containers look unnecessary).

Since

Keep a vertical list of thumb nails. ... a fixed number of them appears in the visible area of the div

Horizontal resize should not affect the thumbnails size to maintain the images aspect ratio.

So all we need is to calculate and set image height depending on the desired number of visible thumbnails.

Run the snippet below in fullscreen and resize the window:

.content {    width: 30vw;    height: 90vh;  }    .thumbs {    height: 78vh;    overflow: auto;    text-align:center;  }    .thumbs img {    display: block;    box-sizing: border-box;        /*    since we need to fit 6 images,    set img height = 1/6 of the container height    */        height: 16.667%;      margin: 0 auto;    border: solid 1vh transparent;  }    .close-btn {    display: inline-block;    font: 400 2rem/1 sans-serif;  }
<div class="content">    <a class="close-btn">&times;</a>    <div class="thumbs">      <img src="http://lorempixel.com/400/200/?1">      <img src="http://lorempixel.com/400/200/?2">      <img src="http://lorempixel.com/400/200/?3">      <img src="http://lorempixel.com/400/200/?4">      <img src="http://lorempixel.com/400/200/?5">      <img src="http://lorempixel.com/400/200/?6">      <img src="http://lorempixel.com/400/200/?7">      <img src="http://lorempixel.com/400/200/?8">      <img src="http://lorempixel.com/400/200/?9">      <img src="http://lorempixel.com/400/200/?0">      <img src="http://lorempixel.com/400/200/?a">      <img src="http://lorempixel.com/400/200/?b">    </div>  </div>

Answers 2

Replace your .thumb-size

  .thumb-size    {       margin: 1vmin 0;      width: 16vw;     height: 12vh;     display: flex;      justify-content: center;      align-items: center;             } 

To

   .thumb-size    {       margin: 1vmin 0;      width: 16vw;     height: auto;     display: flex;      justify-content: center;      align-items: center;     } 

it will be worked as expected

Answers 3

You can use height in terms of percentages (%) so that the child elements will be aligned with respect to parent height. You no need to use JavaScript, you can use pure CSS to make this work.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment