Is there any way to change the color of text “half

2019-01-14 14:38发布

问题:

One thing I've seen in some Desktop applications is the ability to change the color of text as the background changes -- to effectively have multiple colors on a single character. I've seen this most commonly with progress bars that display the percentage inside the bar. Generally a darker background color will be used as the progress bar color, and as it progresses, the dark color doesn't contrast enough with the dark text, so the text color changes as soon as the bar overlaps with the text. This image should explain what I mean:

As you can see, the text is black when it's at 0% -- when there is no dark background. When the background image fully progresses to 100%, the text is completely white. But in the middle, as you can see at 50%, the text is half black/half white, and it's actually split on the "0" character in this example.

Is there any way to do this at all on a webpage? CSS, Images, Jquery, otherwise? (Preferably not Flash or a Java applet though -- I'm really wondering whether an HTML-based solution is possible.) Thanks!

回答1:

I'll get you started:

  1. Create two equally sized "progress bars" (divs). Set their size to the full width they would be if they were at 100%.
  2. Set one bar to black text with a white background and the other to yellow text with a blue background, as per your example above.
  3. Set the yellow/blue bar in a parent div and increase the width of the parent on every percentage increase. Position the parent above the black/white bar.
  4. Also on every increase, update the labels of both progress bars to represent the percentage.

That will simulate the same effect without having to manually paint half a character. It will be difficult in CSS because you will have to position one over the other.

The benefit of doing it this way is that you can easily display half-painted characters. There is already a jQuery progress bar you can use, though.



回答2:

This is really interesting actually. Here is your progress bar. Works fine in IE5.5+ and Safari 5 (browsers that I tested).

Uses system colors. :D

Visualization here

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Progress</title>
    <meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
    <style type="text/css">
.progressbar, .progressbar strong {
    display:block;
    height:1.2em
}
.progressbar, .progressbar em {
    width:10em
}
.progressbar strong, .progressbar em {
    position:absolute;
    top:0;
    left:0
}
.progressbar {
    font:status-bar;
    color:windowtext;
    background:window;
    border:1px solid windowframe;
    text-align:center;
    position:relative
}
.progressbar strong {
    background:highlight;
    width:0;
    font-weight:normal;
    overflow:hidden
}
.progressbar em {
    color:highlighttext;
    font-style:normal
}
    </style>
    <script type="text/javascript">
function progress(bar) {
    var text1 = bar.getElementsByTagName('span')[0];
    var overlay = bar.getElementsByTagName('strong')[0];
    var text2 = bar.getElementsByTagName('em')[0];
    var value = parseInt(bar.getAttribute('progress'), 10);
    value += 1;
    overlay.style.width = value / 10 + 'em';
    text1.innerHTML = text2.innerHTML = value + '%';
    bar.setAttribute('progress', value);
    if (value < 100)
        setTimeout(function() { progress(bar) }, 20);
}
window.onload = function() {
    var span = document.getElementsByTagName('span');
    for (var i = 0; i < span.length; i++) {
        if (span[i].className == 'progressbar') {
            span[i].setAttribute('progress', 0);
            var el1 = document.createElement('span');
            el1.innerHTML = '0%';
            span[i].appendChild(el1);
            el1 = document.createElement('strong');
            var el2 = document.createElement('em');
            el2.innerHTML = '0%';
            el1.appendChild(el2);
            span[i].appendChild(el1);
            progress(span[i]);
        }
    }
}
    </script>
</head>
<body>
    <p><span class="progressbar"></span></p>
</body>
</html>

Note that I used setAttribute to assign the value to the progress bar using a custom attribute name.


Modifying the script for real progressing

The above example is just a dummy progress bar, because it uses a timer to increase the value. To do real progressing you have to modify the script a bit. You can change the function progress so that it adds the value to the current value, or you can do it so that it sets the value. The second approach is probably what you want to use.

function add(bar, value) {
    bar = document.getElementById(bar);
    value = parseInt(bar.getAttribute('progress'), 10) + value;
    value = value > 100 ? 100 : value < 0 ? 0 : value;
    var text1 = bar.getElementsByTagName('span')[0];
    var overlay = bar.getElementsByTagName('strong')[0];
    var text2 = bar.getElementsByTagName('em')[0];
    overlay.style.width = value / 10 + 'em';
    text1.innerHTML = text2.innerHTML = value + '%';
    bar.setAttribute('progress', value);
}
function set(bar, value) {
    value = value > 100 ? 100 : value < 0 ? 0 : value;
    bar = document.getElementById(bar);
    var text1 = bar.getElementsByTagName('span')[0];
    var overlay = bar.getElementsByTagName('strong')[0];
    var text2 = bar.getElementsByTagName('em')[0];
    overlay.style.width = value / 10 + 'em';
    text1.innerHTML = text2.innerHTML = value + '%';
}

You can leave out value = value > 100 ? 100 : value < 0 ? 0 : value if you make sure that the value passed to the function is between 0 and 100.

Test it here


Edit:

I changed innerText to innerHTML so that it works in Firefox. I wasn't aware of this. I also changed in the CSS display:inline-block to display:block. I know this way you can't have the progress bar inline anymore, but this makes it work in Netscape 9.



回答3:

Here's another implementation: http://jsfiddle.net/3rcav4s4/.

HTML:

<div class = "progressBar">
    <div class = "background">0%</div>
    <div class = "container">
        <div class = "foreground">0%</div>
    </div>
</div>
<button>Play</button>

CSS:

*:not(button) {
    padding: 0;
    margin: 0;
    border: 0;
    box-sizing: border-box;
}

body {
    padding: 10px;
}

.progressBar {
    width: 150px;
    height: 15px;
    border: 1px solid #000;
    position: relative;
    margin-bottom: 5px;
}

.progressBar .background,
.progressBar .foreground {
    width: 150px;
    height: 13px;
    font: normal 10px/13px Sans-Serif;
    text-align: center;
}

.progressBar .container {
    position: absolute;
    top: 0;
    left: 0;
    width: 0%;
    overflow: hidden;
}

.progressBar .foreground {
    background-color: navy;
    color: yellow;
}

JS/jQuery:

$(function() {
    $("button").click(function() {
        var start = 0;
        var interval = setInterval(function() {
            if(start >= 100) clearInterval(interval);
            $(".progressBar").find(".background, .foreground")
                             .text(start + "%")
                             .end()
                             .find(".container")
                             .css("width", start++ + "%");
        }, 10);    
    });
});