EvilDr
EvilDr

Reputation: 9610

Using CSS transition and class toggle to show/hide table rows

I have a number of tables that have many rows. I want to initially only show the first three table rows. When a user clicks the Show/Hide link, then all hidden rows will be toggled. I have achieved this so far with CSS3 and JavaScript (see Fiddle).

CSS (only show three rows by default):

.hide tr:nth-child(n+4) {
  display:none;
}

JavaScript (toggle above class to show all rows):

function ShowHide() {
  var tables = document.getElementsByClassName('foo');
  for(i=0; i<tables.length; i++) {
    tables[i].classList.toggle("hide");  
  }
}

Is it possible to use the transition functionality of CSS3 to make the rows appear slowly, rather than instantly? For example, fade in/out over 2 seconds?

I know this can be done easily in JQuery, but I'm looking for a pure CSS solution.

Upvotes: 2

Views: 2859

Answers (2)

Apolo
Apolo

Reputation: 4050

best way to do this is indeed to play with height and opacity. But you can't set height on table elements (tr/td)

so here is an example on how to do it with only CSS

#expand {
 /* hide the checkbox */
 display: none
}

label {
  /* style as a button (you can't use button inside label with for attribute) */
  padding: 2px 5px;
  border: 1px solid rgba(0,0,0,.2);
  border-radius: 5px;
  font-size: .7rem;
  cursor: pointer;
}

table {
  border-spacing: 0;
  border-collapse: collapse;
}

table tr:nth-child(n+4)>td {
  padding: 0;
}

table tr:nth-child(n+4)>td>div {
  opacity: 0;
  max-height: 0;
  transition: all 250ms ease-in;
}

#expand:checked + table tr:nth-child(n+4)>td {
  padding: 1px;
  /* default */
}

#expand:checked + table tr:nth-child(n+4)>td>div {
  opacity: 1;
  /* try to use something just slightly above the true height */
  max-height: 20px;
  overflow: hidden;
  transition-timing-function: ease-out;
}
<input type="checkbox" id="expand"/>
<table id="table">
  <tbody>
    <tr>
      <td>
        <div>Row 1</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Row 2</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Row 3</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Row 4</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Row 5</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Row 6</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Row 7</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Row 8</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Row 9</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Row 10</div>
      </td>
    </tr>
  </tbody>
</table>
<br/>
<label for="expand">Toggle</label>


Edit

Similar trick to hide columns:

#expand {
  /* hide the checkbox */
  display: none
}

label {
  /* style as a button (you can't use button inside label with for attribute) */
  padding: 2px 5px;
  border: 1px solid rgba(0, 0, 0, .2);
  border-radius: 5px;
  font-size: .7rem;
  cursor: pointer;
}

table {
  border-spacing: 0;
  border-collapse: collapse;
}

tr>*:nth-child(n+2)>div {
  opacity: 0;
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  transition: all 250ms ease-in;
}

#expand:checked+table tr>*:nth-child(n+2)>div {
  max-width: 100%;
  opacity: 1;
  transition-timing-function: ease-out;
}
<input type="checkbox" id="expand" />
<table id="table">
  <thead>
    <tr>
      <th>Column1</th>
      <th>
        <div>Column2</div>
      </th>
      <th>
        <div>Column3</div>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
        <div>Cell 1-1</div>
      </td>
      <td>
        <div>Cell 1-2</div>
      </td>
      <td>
        <div>Cell 1-3</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Cell 2-1</div>
      </td>
      <td>
        <div>Cell 2-2</div>
      </td>
      <td>
        <div>Cell 2-3</div>
      </td>
    </tr>
    <tr>
      <td>
        <div>Cell 3-1</div>
      </td>
      <td>
        <div>Cell 3-2</div>
      </td>
      <td>
        <div>Cell 3-3</div>
      </td>
    </tr>
  </tbody>
</table>
<br/>
<label for="expand">Toggle</label>

Upvotes: 4

Shilly
Shilly

Reputation: 8589

Implementation of my 'you can use opacity to simulate a fading' comment based on your Fiddle code.

var theButton = document.getElementById("bar");
theButton.onclick = ShowHide;

function ShowHide() {
  var tables = document.getElementsByClassName('foo');
  for(i=0; i<tables.length; i++) {
  	tables[i].classList.toggle("hide");  
  }
}
td { border-bottom:1px solid #ccc; }

.foo tr:nth-child(n+4) {
  display: block;
  opacity: 1;
  transition: opacity 2s ease-in-out;
}

.foo.hide tr:nth-child(n+4) {
  opacity: 0;
  transition: opacity 2s ease-in-out;
}

.foo.gone tr:nth-child(n+4) {
  display: none;
}
<p>
 <input type="button" id="bar" value="Show/Hide" />
</p>

<h2>Table 1</h2>
<table class="foo hide">
  <tr><td>Text</td></tr>
  <tr><td>Text</td></tr>
  <tr><td>Text</td></tr>
  <tr><td>Text</td></tr>
  <tr><td>Text</td></tr>
  <tr><td>Text</td></tr>
</table>

<h2>Table 2</h2>
<table class="foo hide">
  <tr><td>Text</td></tr>
  <tr><td>Text</td></tr>
  <tr><td>Text</td></tr>
  <tr><td>Text</td></tr>
  <tr><td>Text</td></tr>
  <tr><td>Text</td></tr>
</table>

Optionally you can include transitionstarts and transitionend events on the tables to toggle the .gone class after the transition finishes to toggle their display property. That way you can retain things like positioning, since elements with opacity 0 will still take up room on the page.

Upvotes: 0

Related Questions