Howdy_McGee Howdy_McGee - 1 month ago 19
CSS Question

Flexbox Progress Bar Animation - Incorrect Width

I'm trying to create a progress bar with an animation. It works if I don't have inner text but as soon as I add the inner text the width calculations are different for some reason. I've tried working with the different

width()
functions and I've tried adding up each segment but every time the text throws off the width for some reason.

Here's what I have - JSFiddle



/** Progress Bar Animation **/
function animate_progress_bar() {
if (!$('.progressBar').length) {
return false;
}

$('.progressBar').each(function() {
var num_total = $(this).find('.seg').length;
var num_fill = $(this).find('.fill').length;
var percent = 100 - ((num_fill / num_total) * 100);
var speed = 2000 / num_fill;

$(this).find('.progradient').animate({
'width': percent + '%'
}, speed);
});
}
animate_progress_bar();

.flex {
display: -webkit-flex;
display: flex;
}
.flex > * {
-ms-flex: 0 1 auto;
}
.progressBar {
display: -webkit-flex;
display: flex;
border: 1px solid #000;
border-radius: 20px;
overflow: hidden;
position: relative;
margin-bottom: 40px;
}
.progressBar .seg {
-webkit-flex-grow: 1;
flex-grow: 1;
min-height: 20px;
border-right: 1px solid #000;
z-index: 2;
}
.progressBar .seg:last-of-type {
border-right: 0;
}
.progressBar:before {
content: '';
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
background: rgb(30, 87, 153);
background: -moz-linear-gradient(left, rgba(30, 87, 153, 1) 0%, rgba(41, 137, 216, 1) 27%, rgba(30, 87, 153, 1) 74%, rgba(125, 185, 232, 1) 100%);
background: -webkit-linear-gradient(left, rgba(30, 87, 153, 1) 0%, rgba(41, 137, 216, 1) 27%, rgba(30, 87, 153, 1) 74%, rgba(125, 185, 232, 1) 100%);
background: linear-gradient(to right, rgba(30, 87, 153, 1) 0%, rgba(41, 137, 216, 1) 27%, rgba(30, 87, 153, 1) 74%, rgba(125, 185, 232, 1) 100%);
filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#1e5799', endColorstr='#7db9e8', GradientType=1);
}
.progressBar .progradient {
position: absolute;
top: 0;
right: 0;
z-index: 1;
width: 100%;
height: 100%;
background-color: #fff;
}
.progressBar.large {
border-radius: 40px;
}
.progressBar.large .seg {
min-height: 40px;
}
.progressBar.large .text {
-webkit-flex-grow: 1;
flex-grow: 1;
-webkit-align-self: center;
align-self: center;
font-size: 18px;
text-align: center;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="max-width: 160px">
<div class="progressBar small">
<div class="seg fill"></div>
<div class="seg fill"></div>
<div class="seg"></div>
<div class="seg"></div>
<div class="seg"></div>
<div class="progradient"></div>
</div>
</div>

<div class="progressBar large">
<div class="seg fill"></div>
<div class="seg fill"></div>
<div class="seg fill"></div>
<div class="seg"></div>
<div class="seg"></div>
<div class="progradient"></div>
</div>

<div class="progressBar large">
<div class="seg fill flex">
<div class="text">Test</div>
</div>
<div class="seg fill flex">
<div class="text">Test</div>
</div>
<div class="seg fill flex">
<div class="text">Test</div>
</div>
<div class="seg"></div>
<div class="seg"></div>
<div class="progradient"></div>
</div>




Answer

You just need to add flex: 1; to your segment class.


flex: <positive-number>:

Equivalent to flex: <positive-number> 1 0. Makes the flex item flexible and sets the flex basis to zero, resulting in an item that receives the specified proportion of the free space in the flex container. If all items in the flex container use this pattern, their sizes will be proportional to the specified flex factor.

Source: W3C


Class changed:

.progressBar.large .seg {
    min-height: 40px;
    flex: 1; /* Added property*/
}

Code Snippet:

/** Progress Bar Animation **/
function animate_progress_bar() {
  if (!$('.progressBar').length) {
    return false;
  }

  $('.progressBar').each(function() {
    var num_total = $(this).find('.seg').length;
    var num_fill = $(this).find('.fill').length;
    var percent = 100 - ((num_fill / num_total) * 100);
    var speed = 2000 / num_fill;

    $(this).find('.progradient').animate({
      'width': percent + '%'
    }, speed);
  });
}
animate_progress_bar();
.flex {
  display: -webkit-flex;
  display: flex;
}
.flex > * {
  -ms-flex: 0 1 auto;
}
.progressBar {
  display: -webkit-flex;
  display: flex;
  border: 1px solid #000;
  border-radius: 20px;
  overflow: hidden;
  position: relative;
  margin-bottom: 40px;
}
.progressBar .seg {
  -webkit-flex-grow: 1;
  flex-grow: 1;
  min-height: 20px;
  border-right: 1px solid #000;
  z-index: 2;
}
.progressBar .seg:last-of-type {
  border-right: 0;
}
.progressBar:before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  background: rgb(30, 87, 153);
  background: -moz-linear-gradient(left, rgba(30, 87, 153, 1) 0%, rgba(41, 137, 216, 1) 27%, rgba(30, 87, 153, 1) 74%, rgba(125, 185, 232, 1) 100%);
  background: -webkit-linear-gradient(left, rgba(30, 87, 153, 1) 0%, rgba(41, 137, 216, 1) 27%, rgba(30, 87, 153, 1) 74%, rgba(125, 185, 232, 1) 100%);
  background: linear-gradient(to right, rgba(30, 87, 153, 1) 0%, rgba(41, 137, 216, 1) 27%, rgba(30, 87, 153, 1) 74%, rgba(125, 185, 232, 1) 100%);
  filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#1e5799', endColorstr='#7db9e8', GradientType=1);
}
.progressBar .progradient {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  background-color: #fff;
}
.progressBar.large {
  border-radius: 40px;
}
.progressBar.large .seg {
  min-height: 40px;
  flex: 1;
}
.progressBar.large .text {
  -webkit-flex-grow: 1;
  flex-grow: 1;
  -webkit-align-self: center;
  align-self: center;
  font-size: 18px;
  text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="max-width: 160px">
  <div class="progressBar small">
    <div class="seg fill"></div>
    <div class="seg fill"></div>
    <div class="seg"></div>
    <div class="seg"></div>
    <div class="seg"></div>
    <div class="progradient"></div>
  </div>
</div>

<div class="progressBar large">
  <div class="seg fill"></div>
  <div class="seg fill"></div>
  <div class="seg fill"></div>
  <div class="seg"></div>
  <div class="seg"></div>
  <div class="progradient"></div>
</div>

<div class="progressBar large">
  <div class="seg fill flex">
    <div class="text">Test</div>
  </div>
  <div class="seg fill flex">
    <div class="text">Test</div>
  </div>
  <div class="seg fill flex">
    <div class="text">Test</div>
  </div>
  <div class="seg"></div>
  <div class="seg"></div>
  <div class="progradient"></div>
</div>