Using CSS transitions in CSS Grid Layout
According to the spec, transitions should work on grid-template-columns
and grid-template-rows
.
7.2. Explicit Track Sizing: the
grid-template-rows
andgrid-template-columns
propertiesAnimatable: as a simple list of length, percentage, or calc, provided the only differences are the values of the length, percentage, or calc components in the list
So, if my interpretation is correct, as long as the only changes are to the values of the properties, with no changes to the structure of the rule, transitions should work. But they don't.
UPDATE
This does work but is so far only implemented in Firefox. Follow here for other browser updates. https://codepen.io/matuzo/post/animating-css-grid-layout-properties
~ a contribution in the comments by @bcbrian
Here's a test I created:
grid-container {
display: inline-grid;
grid-template-columns: 100px 20vw 200px;
grid-template-rows: repeat(2, 100px);
background-color: black;
height: 230px;
transition: 2s;
/* non-essential */
grid-gap: 10px;
padding: 10px;
box-sizing: border-box;
}
grid-container:hover {
grid-template-columns: 50px 10vw 100px;
grid-template-rows: repeat(2, 50px);
background-color: red;
height: 130px;
transition: 2s;
}
grid-item {
background-color: lightgreen;
}
<grid-container>
<grid-item></grid-item>
<grid-item></grid-item>
<grid-item></grid-item>
<grid-item></grid-item>
<grid-item></grid-item>
<grid-item></grid-item>
</grid-container>
jsFiddle demo
In the test, the transition works on the height and background color, but not on grid-template-rows
or grid-template-columns
.
I used GSAP to animate the grid-template-columns and grid-template-rows properties:
function changeGridTemplateColumns(pattern) {
TweenMax.to(".container",
1, {
gridTemplateColumns: pattern
}
);
}
function changeGridTemplateRows(pattern) {
TweenMax.to(".container",
1, {
gridTemplateRows: pattern
}
);
}
$(document).ready(
function() {
$(".el-a,.el-b,.el-c").mouseenter(
function() {
changeGridTemplateRows("2fr 1fr");
}
);
$(".el-d,.el-e,.el-f").mouseenter(
function() {
changeGridTemplateRows("1fr 2fr");
}
);
$(".el-a,.el-d").mouseenter(
function() {
changeGridTemplateColumns("2fr 1fr 1fr");
}
);
$(".el-b,.el-e").mouseenter(
function() {
changeGridTemplateColumns("1fr 2fr 1fr");
}
);
$(".el-c,.el-f").mouseenter(
function() {
changeGridTemplateColumns("1fr 1fr 2fr");
}
);
$(".container").mouseleave(
function() {
changeGridTemplateColumns("1fr 1fr 1fr");
changeGridTemplateRows("1fr 1fr");
}
);
}
);
.container {
width: 50vw;
height: 50vw;
margin: auto;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
grid-template-areas: "a b c" "d e f";
}
.el-a {
grid-area: a;
background-color: skyblue;
}
.el-b {
grid-area: b;
background-color: darkseagreen;
}
.el-c {
grid-area: c;
background-color: coral;
}
.el-d {
grid-area: d;
background-color: gold;
}
.el-e {
grid-area: e;
background-color: plum;
}
.el-f {
grid-area: f;
background-color: beige;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="el-a"></div>
<div class="el-d"></div>
<div class="el-b"></div>
<div class="el-e"></div>
<div class="el-c"></div>
<div class="el-f"></div>
</div>
As a workaround, you can work with the size of the grid items instead with grid-template-columns
or grid-template-rows
.
You could do:
grid-container {
display: inline-grid;
grid-template-columns: 100px 20vw 200px;
background-color: black;
height: 230px;
transition: 2s;
/* non-essential */
grid-gap: 10px;
padding: 10px;
box-sizing: border-box;
}
grid-container:hover {
background-color: red;
height: 130px;
}
grid-item {
height: 100px;
transition: height 2s;
background-color: lightgreen;
}
grid-container:hover .first-row {
height: 25px;
}
grid-container:hover .last-row {
height: 75px;
}
<grid-container>
<grid-item class='first-row'></grid-item>
<grid-item class='first-row'></grid-item>
<grid-item class='first-row'></grid-item>
<grid-item class='last-row'></grid-item>
<grid-item class='last-row'></grid-item>
<grid-item class='last-row'></grid-item>
</grid-container>
Here's another 2x2 example: https://codepen.io/erik127/pen/OvodQR
and here a more extensive example where you can add more columns or rows: https://codepen.io/erik127/pen/rdZbxL
Unfortunately it's a lot of javascript, it would be nice if grid-template-columns
and grid-template-rows
would be animatable.
Another alternative which might work in some usecases (if your grid items don't span multiple rows) is the use of flexbox together with a grid.
In my case I was trying to open sidebar-menu by using this code:
.wrapper{
display: grid;
grid-template-columns: 0 100%;
transition: all 1s;
.sidebar{
background-color: blue;
}
.content{
background-color: red;
}
}
.wrapper.sidebar-open{
grid-template-columns: 300px 100%;
transition: all 1s;
}
but transition was not working for grid-template-columns. This is my solution:
.wrapper{
display: grid;
grid-template-columns: auto 100%;
.sidebar{
width: 0;
background-color: blue;
transition: all 1s;
}
.content{
background-color: red;
}
}
.sidebar.sidebar-open{
width: 300px;
transition: all 1s;
}
Perhaps, it helps someone.