How to create a progressbar with inverted text color for "progressed" part
Asked Answered
S

2

24

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.

Salmons answered 20/2, 2014 at 13:37 Comment(3)
Here's a good article on the subject: css-tricks.com/html5-progress-element.Annulment
possible duplicate of Invert CSS font-color depending on background-colorToothed
@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).Salmons
C
21

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>
Crepuscular answered 21/4, 2020 at 21:2 Comment(2)
Maybe a little late, but this solution seems to work. I think it's using new stuff, that was not available 6 years ago.Salmons
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?Raquelraquela
P
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();
}
Perturbation answered 20/2, 2014 at 14:30 Comment(5)
Thanks, but that's not what I need. I've many progressbars, in different situations. The status bar should become an "universal" control.Salmons
What exactly do you need then? This will work with multiple scrollbars. Just set the a width inline. jsfiddle.net/kthornbloom/zkL29/4Perturbation
@Perturbation I believe he means that it should be CSS only solution, not jQueryCaliper
@Caliper - heh heh, what a blast from the past. This was a decade ago! Thank goodness we've moved on from jQuery <3Perturbation
@Perturbation sadly, not everyone has ;`(Caliper

© 2022 - 2024 — McMap. All rights reserved.