How to Transition the Flex-Grow of a Flex Box to Produce an Animation

Transitioning flex-basis from auto

flex-basis can be animated and transitioned (source). However, like other properties, it can only be done if you set the values to actual length values (like px, %, etc. and calc()). More info can be found in this question.

Flex transition: Stretch (or shrink) to fit content

It is possible to solve it using max-width and calc().

First, replace width: 100% with flex: 1 for the divs in CSS, so they will grow, which is better in this case. In addition, use transition for max-width.

Now, we have to store some relevant values:

  • The amount of divs that will be animated (divsLength variable) - 3 in this case.
  • The total width used for the fixed div and the borders (extraSpace variable) - 39px in this case.

With those 2 variables, we can set a default max-width (defaultMaxWidth variable) to all the divs, as well as using them later. That is why they are being stored globally.

The defaultMaxWidth is calc((100% - extraSpace)/divsLength).

Now, let's enter the click function:

To expand the div, the width of the target text will be stored in a variable called textWidth and it will be applied to the div as max-width. It uses .getBoundingClientRect().width (since it return the floating-point value).

For the remaining divs, it is created a calc() for max-width that will be applied to them.

It is: calc(100% - textWidth - extraScape)/(divsLength - 1).

The calculated result is the width that each remaining div should be.

When clicking on the expanded div, that is, to return to normal, the default max-width is applied again to all .div elements.

var expanded = false,

divs = $(".div:not(:first-child)"),

divsLength = divs.length,

extraSpace = 39, //fixed width + border-right widths

defaultMaxWidth = "calc((100% - " + extraSpace + "px)/" + divsLength + ")";

divs.css("max-width", defaultMaxWidth);

$(document).on("click", ".div:not(:first-child)", function (e) {

var thisInd = $(this).index();

if (expanded !== thisInd) {



var textWidth = $(this).find('span')[0].getBoundingClientRect().width;

var restWidth = "calc((100% - " + textWidth + "px - " + extraSpace + "px)/" + (divsLength - 1) + ")";



//fit clicked fluid div to its content and reset the other fluid divs

$(this).css({ "max-width": textWidth });

$('.div').not(':first').not(this).css({ "max-width": restWidth });

expanded = thisInd;

} else {

//reset all fluid divs

$('.div').not(':first').css("max-width", defaultMaxWidth);

expanded = false;

}

});
.wrapper {

overflow: hidden;

width: 100%;

margin-top: 20px;

border: 1px solid black;

display: flex;

justify-content: flex-start;

}

.div {

overflow: hidden;

white-space: nowrap;

border-right: 1px solid black;

text-align:center;

}

.div:first-child {

min-width: 36px;

background: #999;

}

.div:not(:first-child) {

flex: 1;

transition: max-width 1s;

}

.div:not(:first-child) span {

background: #ddd;

}

.div:last-child {

border-right: 0;

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

Click on the div you want to fit/reset (except the first div)

<div class="wrapper">

<div class="div"><span>Fixed</span></div>

<div class="div"><span>Fluid (long long long long text)</span></div>

<div class="div"><span>Fluid</span></div>

<div class="div"><span>Fluid</span></div>

</div>


Related Topics



Leave a reply



Submit