css grid children scale transition/animation

Viewed 1063

I'm trying to scale the size of a children in a css grid when you click it, but I didn't success. The problem is that I actually didn't scale it, I just changed the column and the row position in order to fill all the grid.

div {
      width: 100%;
      height: 140px;
      display: grid;
      grid-template-columns: 1fr 1fr 1fr;
      grid-template-rows: 1fr 1fr;
      grid-gap: 20px;
  }


div:active {
    grid-column-start: 1;
    grid-column-end: 5;
    grid-row-start: 1;
    grid-row-end: 4;
    height: 140px; //the size of the grid is 140px just because it doesn't work if you do 100%
    z-index: 3;
 }

enter image description here

As you can see the result is not the best, they don't seems to "scaled" but just coming down from the top. I tried with css grid but i don't know if it's the best way to do that (css grid instead of flexbox).

enter image description here

2 Answers

Try to add an inner element with absolute position on parent active.

.box {
    width: 100%;
    height: 140px;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 1fr 1fr;
    grid-gap: 20px;
    position: relative;
}

.inner-child {
  height: 100%; width: 100%;
}

.element:nth-child(1) .inner-child {background: #ff0000}
.element:nth-child(2) .inner-child {background: #ffe600}
.element:nth-child(3) .inner-child {background: #14ff00}
.element:nth-child(4) .inner-child {background: #00fff0}
.element:nth-child(5) .inner-child {background: #001aff}
.element:nth-child(6) .inner-child {background: #d400ff}

.element:active .inner-child {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}
<div class="box">
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
</div>

For animation we have to add a script.

setTimeout(function(){ // need to whati untill grid loads.
  let gridWidth = $('.box').width();
  let gridHeight = $('.box').height();
  
  $('.element').each(function () {
    let elementW = $(this).width();
    let elementH = $(this).height();    
    let thisP = $(this).position();

    $(this).find('.inner-child').css({'left': thisP.left + 'px', 'right': gridWidth - (elementW + thisP.left) + 'px', 'top': thisP.top + 'px', 'bottom': gridHeight - (elementH + thisP.top) + 'px'});

  });

}, 200);
.box {
    width: 100%;
    height: 140px;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 1fr 1fr;
    grid-gap: 20px;
    position: relative;
}

.inner-child {
  position: absolute;
  z-index: 1;
  transition: all .5s ease;
}

.element:nth-child(1) .inner-child {background: #ff0000}
.element:nth-child(2) .inner-child {background: #ffe600}
.element:nth-child(3) .inner-child {background: #14ff00}
.element:nth-child(4) .inner-child {background: #00fff0}
.element:nth-child(5) .inner-child {background: #001aff}
.element:nth-child(6) .inner-child {background: #d400ff}

.element:active .inner-child {
  left: 0 !important;
  right: 0 !important;
  top: 0 !important;
  bottom: 0 !important;
  z-index: 100;
}
<script
  src="https://code.jquery.com/jquery-3.5.1.min.js"
  integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
  crossorigin="anonymous"></script>
<div class="box">
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
  <div class="element">
    <div class="inner-child">
    </div>
  </div>
</div>

Here's a Pure CSS solution, relying on the fact that there's only 6 items Which means it's not dynamic by nature and requires extra care.

How it works

  1. We define a grid area for each element, This way the grid items will be relative to their grid area instead of the grid container So we can transition the width/height.
  2. we place the grid items in their respective grid area.
  3. we position the grid items absolutely, Since the grid area is defined there will be no overlap.
  4. We give the grid items the proper anchor so they grow from where they are (example: An element on the top right corner will have top:0;right:0)

The middle elements requires extra care it's pointed out in the code

[grid] {
  width: 100%;
  height: 140px;
  display: grid;
  grid-template-areas: "a b c""d e f";
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  grid-gap: 20px;
  position: relative;
}

[grid]>[item]:nth-child(1) {
  background: #ff0000;
  grid-area: a;
  top: 0;
  left: 0;
}

[grid]>[item]:nth-child(2) {
  background: #ffe600;
  grid-area: b;
  top: 0;
}

[grid]>[item]:nth-child(3) {
  background: #14ff00;
  grid-area: c;
  top: 0;
  right: 0;
}

[grid]>[item]:nth-child(4) {
  background: #00fff0;
  grid-area: d;
  bottom: 0;
  left: 0;
}

[grid]>[item]:nth-child(5) {
  background: #001aff;
  grid-area: e;
  bottom: 0;
}

[grid]>[item]:nth-child(6) {
  background: #d400ff;
  grid-area: f;
  bottom: 0;
  right: 0;
}
/* Extra care for the middle elements
 * So they can transition from the middle  
*/
[grid]>[item]:nth-child(5),
[grid]>[item]:nth-child(2) {
  left: 50%;
  transform: translateX(-50%);
}

[grid]>[item] {
  position: absolute;
  width: 100%;
  height: 100%;
}

/* width: calc(300% + 40px); 
 * 300% beacause we have 3 columns each column is 100%
 * becasue the grid item is relative to it's grid area not the grid container
 * 3 columns is 100% * 3 = 300%
 * 40px is the grid gap, You can css variables to make it accessible for the grid items.
 * Same applies to the height.
*/

[grid]>[item]:hover {
  height: calc(200% + 20px);
  width: calc(300% + 40px);
  transition: all .5s linear;
  z-index: 5;
}
<div grid>
  <div item></div>
  <div item></div>
  <div item></div>
  <div item></div>
  <div item></div>
  <div item></div>
</div>

Related