1

I have a list of elements (cards I'm calling them) which are each 33% width in order to fill the page. Inside them is a header and a detail and I want to show the detail of all of them from the click of a checkbox. The length of the detail is variable between all the cards so when the user clicks to show the details I attempt to get the height of each card's detail, set them all the same, and then show the details on them all.

I set the heights correctly but once slideDown() is called on them they are given a height that is greater than what I set. I was finally able to figure out that it has something to do with data-set-label and data-set-data being inline-block and having a width of 50%. If I remove that, slideDown() shows the proper height. It's almost as if slideDown() is not taking into consideration that the inline block elements are on the same line, but that doesn't seem right...

What's going wrong?

$(document).ready(function() {
  $("#ShowDetailsCheckBox").change(function() {
    if ($(this).is(":checked")) {
      setContentDataHeights();
      $(".cards-card-detail").slideDown();
    } else {
      $(".cards-card-detail").slideUp();
    }
  });
});

function setContentDataHeights() {
  var maxContentDataHeight = 0;

  $(".cards-card-detail").each(function() {
    if ($(this).height() > maxContentDataHeight)
      maxContentDataHeight = $(this).height();
  });

  if (maxContentDataHeight > 0) {
    $(".cards-card-detail").each(function() {
      //$(this).css("height", maxContentDataHeight.toString() + "px");
      $(this).height(maxContentDataHeight);
    });
  }
}
* {
  box-sizing: border-box;
}

.cards {
  font-size: 0;
}

.cards-card {
  font-size: 12pt;
  display: inline-block;
  width: 33%;
  vertical-align: top;
  border: 1px solid red;
}

.cards-card:nth-child(2n) {
  width: 34%;
  border: 1px solid green;
}

.cards-card-header {
  height: 100px;
}

.cards-card-detail {
  padding: 10px;
  border-top: 1px solid red;
  display: none;
}

.data-set-wrapper {
  width: 100%;
  font-size: 0;
}

.data-set-label {
  font-size: 12px;
  border: 1px solid red;
  width: 50%;
  display: inline-block;
}

.data-set-data {
  font-size: 12px;
  border: 1px solid red;
  width: 50%;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<input type="checkbox" id="ShowDetailsCheckBox" />Show details
<div class="cards">
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
</div>

View on JSFiddle

showdev
  • 28,454
  • 37
  • 55
  • 73
sourkrause
  • 178
  • 8

1 Answers1

0

That's pretty funky.

A Theory:

When .cards-card-detail elements have display:none, their widths are undefined. The .data-set-label elements have width:50% but, with their parents' widths undefined, their widths get calculated in a strange way which causes inner text to wrap and heights to get thrown off.

Some Tests:

In the test below, the width of .data-set-label is computed as "50 pixels", even though it's defined as "50%". But when .cards-card-detail is display:block, a more accurate width is returned.

$(function() {
  console.log("display:none - " + $('.data-set-label').width());
  $('.cards-card-detail').show()
  console.log("display:block - " + $('.data-set-label').width());
});
* {
  box-sizing: border-box;
}

.cards {
  font-size: 0;
}

.cards-card {
  font-size: 12pt;
  display: inline-block;
  width: 33%;
  vertical-align: top;
  border: 1px solid red;
}

.cards-card:nth-child(2n) {
  width: 34%;
  border: 1px solid green;
}

.cards-card-header {
  height: 100px;
}

.cards-card-detail {
  padding: 10px;
  border-top: 1px solid red;
  display: none;
}

.data-set-wrapper {
  font-size: 0;
}

.data-set-label {
  font-size: 12px;
  border: 1px solid red;
  width: 50%;
  display: inline-block;
}

.data-set-data {
  font-size: 12px;
  border: 1px solid red;
  width: 50%;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<div class="cards">
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
</div>

Setting the width of .data-set-label explicitly to "50px" makes the text wrap and increases the height of .cards-card-detail, seemingly to the same "wrong" height as in your example (coincidence?).

* {
  box-sizing: border-box;
}

.cards {
  font-size: 0;
}

.cards-card {
  font-size: 12pt;
  display: inline-block;
  width: 33%;
  vertical-align: top;
  border: 1px solid red;
}

.cards-card:nth-child(2n) {
  width: 34%;
  border: 1px solid green;
}

.cards-card-header {
  height: 100px;
}

.cards-card-detail {
  padding: 10px;
  border-top: 1px solid red;
}

.data-set-wrapper {
  font-size: 0;
}

.data-set-label {
  font-size: 12px;
  border: 1px solid red;
  width: 50px;
  display: inline-block;
}

.data-set-data {
  font-size: 12px;
  border: 1px solid red;
  width: 50px;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<div class="cards">
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
</div>

A Solution:

I had some success by defining the width of .cards-card-detail at "100%" in the hopes that the childrens' "50%" width would then be set correctly.

$(function() {

  $("#ShowDetailsCheckBox").change(function() {
    if ($(this).is(":checked")) {
      setContentDataHeights();
      $(".cards-card-detail").slideDown();
    } else {
      $(".cards-card-detail").slideUp();
    }
  });

});

function setContentDataHeights() {

  var maxContentDataHeight = 0;

  $(".cards-card-detail").each(function() {
    if ($(this).height() > maxContentDataHeight)
      maxContentDataHeight = $(this).height();
  });

  if (maxContentDataHeight > 0) {
    $(".cards-card-detail").height(maxContentDataHeight);
  }

}
* {
  box-sizing: border-box;
}

.cards {
  font-size: 0;
}

.cards-card {
  font-size: 12pt;
  display: inline-block;
  width: 33%;
  vertical-align: top;
  border: 1px solid red;
}

.cards-card:nth-child(2n) {
  width: 34%;
  border: 1px solid green;
}

.cards-card-header {
  height: 100px;
}

.cards-card-detail {
  padding: 10px;
  border-top: 1px solid red;
  display: none;
  width: 100%;
}

.data-set-wrapper {
  font-size: 0;
}

.data-set-label {
  font-size: 12px;
  border: 1px solid red;
  width: 50%;
  display: inline-block;
}

.data-set-data {
  font-size: 12px;
  border: 1px solid red;
  width: 50%;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<input type="checkbox" id="ShowDetailsCheckBox" />Show details
<div class="cards">
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
</div>

I'm curious about other explanations.


EDIT:

I see what you mean: the solution above doesn't work consistently.
Here's a alternative technique:

Set .cards to opacity:0 until the heights of .card-card-detail are set. Then reveal the cards.

$(document).ready(function() {

  setContentDataHeights();
  $('.cards-card-detail').hide();
  $('.cards').addClass('show');

  $("#ShowDetailsCheckBox").change(function() {
    if ($(this).is(":checked")) {
      $(".cards-card-detail").slideDown();
    } else {
      $(".cards-card-detail").slideUp();
    }
  });
});

function setContentDataHeights() {
  var maxContentDataHeight = 0;

  $(".cards-card-detail").each(function() {
    if ($(this).height() > maxContentDataHeight)
      maxContentDataHeight = $(this).height();
  });

  if (maxContentDataHeight > 0) {
    $(".cards-card-detail").height(maxContentDataHeight);
  }
}
* {
  box-sizing: border-box;
}

.cards {
  font-size: 0;
  opacity: 0;
  transition: opacity .25s;
}

.cards.show {
  opacity: 1;
}

.cards-card {
  font-size: 12pt;
  display: inline-block;
  width: 33%;
  vertical-align: top;
  border: 1px solid red;
}

.cards-card:nth-child(2n) {
  width: 34%;
  border: 1px solid green;
}

.cards-card-header {
  height: 100px;
}

.cards-card-detail {
  padding: 10px;
  border-top: 1px solid red;
}

.data-set-wrapper {
  font-size: 0;
}

.data-set-label {
  font-size: 12px;
  border: 1px solid red;
  width: 50%;
  display: inline-block;
  vertical-align: top;
}

.data-set-data {
  font-size: 12px;
  border: 1px solid red;
  width: 50%;
  display: inline-block;
  vertical-align: top;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="checkbox" id="ShowDetailsCheckBox" />Show details
<div class="cards">
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">label label label label label label </label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">label label label label label label label label label label </label>
        <div class="data-set-data">
          some data
        </div>
      </div>
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
  <div class="cards-card">
    <div class="cards-card-header">
      Here is some header information
    </div>
    <div class="cards-card-detail">
      <div class="data-set-wrapper">
        <label class="data-set-label">Label</label>
        <div class="data-set-data">
          some data
        </div>
      </div>
    </div>
  </div>
</div>
showdev
  • 28,454
  • 37
  • 55
  • 73
  • 1
    Excellent idea with the width 100%...I hadn't thought of that. However, it's not quite working. Take a look at this [link]https://jsfiddle.net/tn86cs2k/29/. If the data runs onto more than 1 line the height gets calculated incorrectly and the content extends outside the detail. Also, not sure if this is worth pointing out, but you had mentioned the display: none width being 50? If I change the width of the label to 55%, just for grins, jquery calculates a width of 55, so, can we really trust that it's width is 50 when display is none? – sourkrause Aug 24 '17 at 13:22
  • This some help from this link https://stackoverflow.com/questions/3632120/jquery-height-width-and-displaynone I added position: relative to cards-card and that seems to nearly fix the content stretching outside the detail. I'm still not getting perfect heights on things yet though. – sourkrause Aug 24 '17 at 14:07