user51462
user51462

Reputation: 2022

CSS grid - Animating content placement

I have a 2x2 grid that contains three divs: #blue (2x1), #red (1x1) and #yellow (1x1) (see JSFiddle). This is what the grid looks like initially:

enter image description here

NOTE: #red is overlapped by #blue and hence not visible. To make it visible, the user must click Show. This is what the grid looks like after Show has been clicked:

enter image description here

In my current setup, clicking the Show button adds the .expanded class to #red, which changes the line placement of #red from grid-column: 1/2 to grid-column: 1/span2 and makes #red visible. This works fine, however, I don't like the abruptness of the change and would like to give #red the appearance of sliding out from under #blue when Show is clicked. The problem is that since grid-column has a discrete animation type, it cannot be tween-transitioned in the way that a continuous property like width can.

My attempt at a work-around:

I tried specifying a width property for #red. It is initially set to 100px and transitioned to 200px when Show is clicked.

This almost gives me the desired result in that #red slides smoothly when Show is clicked but not when Hide is clicked. My guess is that grid-column does not wait for the transition to complete and I also don't like having to hardcode the values of width.

I also tried using translateX with transition but once again grid-column is set before the transition finishes.

Is there a solution to this problem that uses pure CSS? (I don't mind using JS but it is a last resort and do not want to use anything that involves setTimeout or jQuery.)

Upvotes: 2

Views: 228

Answers (1)

Alexandre Elshobokshy
Alexandre Elshobokshy

Reputation: 10922

You could add another class that could take care of the hide transition combined with an webkitTransitionEnd event.

Also note that I added a width: 50% rather than your fixed width.

const show = document.getElementById('show');
const hide = document.getElementById('hide');
const red = document.getElementById('red');

show.addEventListener('click', function() {
  red.classList.add('expanded');
  red.classList.remove('notexpanded');

});

hide.addEventListener('click', function() {
  red.classList.remove('expanded');
  red.classList.add('notexpanded');
  red.addEventListener('webkitTransitionEnd',
    function(event) {
      red.classList.remove('notexpanded');
    }, false);
});
#page {
  display: grid;
  grid-template-columns: 100px 100px;
  grid-template-rows: 100px 100px;
  /* grid-auto-flow: column dense; */
}

#blue {
  background-color: lightblue;
  grid-row: 1/span 2;
  grid-column: 1/2;
  z-index: 1;
}

#yellow {
  background-color: yellow;
  height: 100%;
}

#red {
  background-color: red;
  text-align: right;
  grid-column: 1;
  grid-row: 1;
  /* z-index: -1; cant click hide */
  /* float: right; */
  /* transform: translateX(0);
  transition: transform 2s; */
  width: 50%;
  transition: width 2s;
}

#red.expanded {
  /* transform: translateX(100%); */
  width: 100%;
  grid-column: 1/span 2;
}

#red.notexpanded {
  /* transform: translateX(100%); */
  width: 50%;
  grid-column: 1/span 2;
}
<div id='page'>
  <div id='blue'>
    <button type='button' id='show'>Show</button>
  </div>
  <div id='red'>
    <button type='button' id='hide'>Hide</button>
  </div>
  <div id='yellow'></div>
</div>

Upvotes: 1

Related Questions