22

I'm trying it since hours, but I'm not getting any solution that works. The task is: create a progressbar with dynamic width and a centered label, that changes its text color between progressed and unprogressed part. Here is an image for clarification:

Example

So this works great, if i know the width of the whole progressbar. But it's not usable in a responsive design, where it's width is calculated automatically.

Here is my code:

<div class="progress" style="width: 400px;">
 <div class="progressValue" style="width: 50%">
  <div class="progressInnerLabel" style="width: 400px;">I'm a progress text</div>
 </div>
 <div class="progressLabel">I'm a progress text</div>
</div>

And my CSS:

.progress {
    position: relative;
}

.progressValue {
    overflow: hidden;
    position: absolute;
    height: 20px;
    background-color: blue;    
}

.progressInnerLabel {
    position: absolute;
    text-align: center; 
    color: white;  
    height: 20px;    
}

.progressLabel {
    background-color: #eee; 
    text-align: center; 
    color: black;    
}

I've also created a fiddle, so you can play around with it: http://jsfiddle.net/Q82kF/2/

I would like to remove the width: 400px of my first div (class = progress) of my html, so the progress automatically gets the full available width. Does anybody have a solution for this?

I DON'T wand to do it with javascript (or any lib). I think there must be a CSS/HTML only solution.

SuperNova
  • 2,792
  • 2
  • 25
  • 34
  • Here's a good article on the subject: http://css-tricks.com/html5-progress-element/. – Niklas Feb 20 '14 at 13:43
  • 1
    possible duplicate of [Invert CSS font-color depending on background-color](http://stackoverflow.com/questions/16981763/invert-css-font-color-depending-on-background-color) – onalbi Sep 23 '15 at 07:07
  • 3
    @onalbi: No it's not a duplicate. The solution provided there just works, because the text is NOT centered. With centered Text, the solution does not work (you need to sync the width of inner container with outer container). – SuperNova Sep 24 '15 at 07:23

2 Answers2

19

This can be implemented by using clip-path: inset():

.progress {
  position: relative;
  display: flex;
  height: 100px;
  border: 3px solid #566573;
  border-radius: 8px;
  font-size: 50px;
  font-family: Courier, monospace;
  overflow: hidden;
}

.back {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  background: #5D6D7E;
  color: white;
}

.front {
  position: absolute;
  display: flex;
  justify-content: center;
  align-items: center;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background: white;
  color: black;
  clip-path: inset(0 0 0 50%);
  -webkit-clip-path: inset(0 0 0 50%);
  transition: clip-path 1s linear;
}
<div class="progress">
  <div class="back">progress 100%</div>
  <div class="front">progress 100%</div>
</div>
user1675631
  • 376
  • 3
  • 3
  • 1
    Maybe a little late, but this solution seems to work. I think it's using new stuff, that was not available 6 years ago. – SuperNova Apr 23 '20 at 05:57
  • Works great but if you add a overflow: hidden; and border-radius: 20p; to .progress you'll get some jagged edges. Anyone got a solution for this? – t0byman Feb 26 '21 at 16:35
10

I don't believe it is possible in pure CSS because the text within the filled part of the bar needs to be at 100% of its parent's parent's width. One option may be to use webkit masking, but of course it would only work in Chrome & Safari.

I know you said you didn't want a JS solution, but it's the only method I could think of. Here's how you'd do it with jQuery: http://jsfiddle.net/kthornbloom/zkL29/

CSS:

.progress-bar {
    background:#ccc;
    padding:10px 0;
    width:100%;
    text-align:center;
    position:relative;
}

.progress-fill {
    background:blue;
    color:#fff;
    width:50%;
    padding:10px 0;
    position:absolute;
    left:0;
    top:0;
    overflow:hidden;
}

JS:

function barWidth() {
    var barWidth = $('.progress-bar').width();
    $('.progress-fill-text').css('width',barWidth);
}
barWidth();
window.onresize = function() {
    barWidth();
}
kthornbloom
  • 3,660
  • 2
  • 31
  • 46
  • Thanks, but that's not what I need. I've many progressbars, in different situations. The status bar should become an "universal" control. – SuperNova Feb 21 '14 at 10:08
  • What exactly do you need then? This will work with multiple scrollbars. Just set the a width inline. http://jsfiddle.net/kthornbloom/zkL29/4/ – kthornbloom Feb 21 '14 at 15:35