Grinner
Grinner

Reputation: 347

Animate expansion of css display:table

First of all, the relevant JSFiddle.

I have a site that generates a table via PHP. It consists of quite a few entries, so I want to show only 5 lines and a more button that expands the div with the table using a JS .animate. Unfortunately it seems like height (or max-height) is not respected when the display:table property is set. It always displays all lines immediately rendering the 'more' button useless.

My second idea was to start out by hiding all lines after line 5 and then unhiding them on button press. That works, but animation does not. Rehiding and changing the div size via .animate does however. (see my JSFiddle implementation)

I am confused, is there any way to animate the growth of a div with display:table?

All of this was tested on Chrome and Edge btw.

Upvotes: 1

Views: 1286

Answers (1)

Rounin
Rounin

Reputation: 29463

Instead of animating the height of the display: table div, place it inside a parent div which has (by default) display: block.

Now you can animate() the height of the parent div via jQuery, revealing and hiding the table contained inside.

Example:

$(document).ready(function(){

    $('#more').click(function(e) {
        e.stopPropagation();
        var he = $('.clipping-div')[0].scrollHeight;
        $('.clipping-div').animate({height: he});
    });

    $(document).click(function() {
        $('.clipping-div').animate({height: '50px'});
    });

});
.clipping-div {
  height: 50px;
  overflow: hidden;
  }

.table {
  width: 50%;
  border: 1px solid black;
  display: table;
  }

.row {
  display: table-row;
  height: 25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="clipping-div">
<div class="table">
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
</div>
</div>

<a id="more" href="#">Read more </a>


[Experimental] Alternative Solution using native Javascript and CSS Transitions

I wanted to come up with an alternative solution using javascript and CSS and the original wrapper-less markup (since using the .clipping-div wrapper felt inelegant).

However, display: table and display: table-row (both of which I'im unused to working with) appear to have a lot of constraints:

  • neither type of display style appears to permit an animatable height or line-height
  • display: table-row won't permit border styles
  • display: table-row also won't permit z-index

and so on...

Conclusion: It appears that display: table is extraordinarily stubborn and difficult to work with.

Here is an attempt at a wrapper-less solution below, using opacity to compensate for the lack of z-index and outline to compensate for the lack of border, but... it's not my best work.

var more = document.getElementById('more');
var body = document.getElementsByTagName('body')[0];
var clippingTable = document.getElementsByClassName('clipping-table')[0];
var clippingTableRows = clippingTable.getElementsByClassName('row');

more.style.top = ((clippingTableRows.length - 2) * - 25) + 12 + 'px';

function moreTable(e) {
    e.stopPropagation();
    for (var i = (clippingTableRows.length - 1); i > 1; i--) {
        clippingTableRows[i].style.transform = 'translateY(0)';
        clippingTableRows[i].style.opacity = '1';
        more.style.top = '12px';
    }
}

function lessTable() {

    for (var i = (clippingTableRows.length - 1); i > 1; i--) {
        clippingTableRows[i].removeAttribute('style');
        more.style.top = ((clippingTableRows.length - 2) * -25) + 12 + 'px';
    }
}

more.addEventListener('click', moreTable, false);
body.addEventListener('click', lessTable, false);
#more {
position: relative;
transition: top 0.5s;
}

.clipping-table {
  display: table;
  width: 400px;
  }

.row {
  display: table-row;
  height: 25px;
  outline: 1px solid black;
}

.row:nth-of-type(odd) {
background-color: rgb(191,191,255);
}

.row:nth-of-type(even) {
background-color: rgb(127,127,255);
}

.row:nth-of-type(n+3) {
opacity: 0;
transition: all 0.5s;
}

.row:nth-of-type(3) {
  transform: translateY(-25px);
}

.row:nth-of-type(4) {
  transform: translateY(-50px);
}

.row:nth-of-type(5) {
  transform: translateY(-75px);
}

.row:nth-of-type(6) {
  transform: translateY(-100px);
}

.row:nth-of-type(7) {
  transform: translateY(-125px);
}

.row:nth-of-type(8) {
  transform: translateY(-150px);
}

.row:nth-of-type(9) {
  transform: translateY(-175px);
}

.row:nth-of-type(10) {
  transform: translateY(-200px);
}
<div class="clipping-table">
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
  <div class="row">asdasdasdasd</div>
</div>

<a id="more" href="#">Read more </a>

Upvotes: 3

Related Questions