3

In the following example, I demonstrate the issue where the colors are perfect, except for portions at different %'s results in some or all of the text being obscured.

What I would like to achieve, is to somehow assign the font color to be the difference of the background. I recall seeing something many years ago in DHTML which allowed for this. The result I am looking for is as follows

  • In the 50% sample, the '5' would be in white, and the '0' would be in black.
  • In the 75% sample, the '75' would be in white.
  • In the 20% sample, the '20' would be in black.

I believe there is a way to do this using CSS/CSS3, but I am unable to locate information on it.

The resulting style information should be contained inside the 'p' style in the CSS file. No 'tricks' like splitting data or altering the HTML using JavaScript / etc. The number inside the <p> element should remain whole and in tact.

body {
  background: #000000; 
}

p {
 background: #ffffff;
 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAA1BMVEVilQmZw+RvAAAAAXRSTlOF3TSvyQAAAD1JREFUeNrtwQENAAAAwqD3T20PBxQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPBmnQgAAd4aVNwAAAAASUVORK5CYII=");
 background-repeat: repeat-y;
    background-size: 0% auto;
 color: #ffffff;
 padding: 5px;
 text-align: center;
 border: 1px solid #3E8096;
 display: block; 
}
<p style="background-size: 50% auto !important">50</p>
<p style="background-size: 75% auto !important">75</p>
<p style="background-size: 20% auto !important">20</p>

Note:

I was considering a drop-shadow, however this would result in a funny looking font when it is a white font. I also considered encapsulating the text in a border, however the ideal result would be for the font to adjust based on background.

Kraang Prime
  • 9,981
  • 10
  • 58
  • 124
  • @Rhumborl - The simplicity of that statement did bring humor to my morning. I am not looking for a solid color replacement that will work on both colors depicted in the example. I am looking for some form of text masking / clipping / whatever feature that manipulates the text appearance to be visible regardless of the background it is on. Eg, invert, or whatever. Problem is there is very little information to go on when searching (google/etc). I can clip the entire background, but the text still remains the same -- eg `mix-blend-mode: screen;` – Kraang Prime Feb 13 '16 at 12:17
  • Maybe [THIS](http://stackoverflow.com/questions/16981763/invert-css-font-color-depending-on-background-color) will help. It won't automatically detect the background color and adjust the text color, but it does provide a static solution. – sideroxylon Feb 13 '16 at 12:18
  • @sideroxylon - yes, that definitely looks feasible. could you provide a sample that isn't dependent on the contents of the element being set using a tag hard coded in CSS ? I will also try playing around to see if i can simplify the calling functions. – Kraang Prime Feb 13 '16 at 12:20
  • @sideroxylon yes i was starting to play with the same idea, but did still require an attribute. It's a bit annoying there is not something like `content:text()` in CSS. – Rhumborl Feb 13 '16 at 12:24
  • @Rhumborl - also, there is no way to add html elements using `content:`, so that rules out something dynamic using `::before` and `::after` . I am digging through the various specs now to see if there is a selector for the text/contents only portion inside an element. – Kraang Prime Feb 13 '16 at 12:29
  • Tried using `:first-line` in the hopes that would select the text, but it failed to style it. Tested `p:first-line { mix-blend-mode: difference; }` and while it does select the element, in this case, that particular style has no effect. – Kraang Prime Feb 13 '16 at 12:44

1 Answers1

3

body { background: navy }

div {
    background-color: white;
    display: inline-block;
    border: 1px solid red;
    width: 200px;
    font-size: 50px;
    text-align: center;
    position: relative;
    color: red;
}

span {
    content: '';
    position: absolute;
    background: cyan;
    width: 50%;
    top: 0;
    left: 0;
    height: 100%;
    display: inline-block;
    mix-blend-mode: difference;
}
<div>
   0000 <span></span>
</div>

body { background: navy }

div {
    background-color: white;
    display: inline-block;
    border: 1px solid red;
    width: 200px;
    font-size: 50px;
    text-align: center;
    position: relative;
    color: red;
}

div:after {
    content: '';
    position: absolute;
    background: cyan;
    width: 50%;
    top: 0;
    left: 0;
    height: 100%;
    display: inline-block;
    mix-blend-mode: difference;
}
<div>00000</div>
kanudo
  • 2,119
  • 1
  • 17
  • 33
  • Can you do this without the additional nested element please :) – Kraang Prime Feb 13 '16 at 12:22
  • @SanuelJackson here is the code without nested elements – kanudo Feb 13 '16 at 12:36
  • Nice job. I guess from what I am seeing, is the only way to have the actual text inside the element at page load while keeping the clipping is if it is inside a nested element. Aside from that, since you can not actually apply a style to the text, it won't work. I'm going to dig through my ancient DHTML book and see if I can locate what was used before to achieve this (probably nested as well). In the meantime, could you put the other solution you provided back up along-side of this one. From what I can tell, both answers are correct and may be the only ways to really do this. – Kraang Prime Feb 13 '16 at 12:42
  • ya sure i will just put it back – kanudo Feb 13 '16 at 12:46
  • Marking this solution as correct. While it isn't what I was hoping for, the limitations of CSS/CSS3 at this time do not include the capability of a `:text` type selector or further, the ability to mask it based on the contents of the background within the same element or DOM level inside the same element. In either case, the above solution merits acceptance until such a time when this functionality is included as part of CSS. :) – Kraang Prime Feb 13 '16 at 12:51
  • 1
    You said true.. when `:text` would be available to style using css, there will remain no need for `:before`, `:after` or any nesting of elements. – kanudo Feb 13 '16 at 12:53
  • I did notice a small issue with this. Set the background color of the page to `navy` or add another element inside, and it seems to pick up the top most background color in the DOM for masking. Think you can adjust the css to account for this ? Really only interested in masking based on the parent dom only, not the highest element in the dom's background :) – Kraang Prime Feb 13 '16 at 13:00
  • 1
    I was also testing it right now, i seen the same thing. And also finding the solution for the same. Will update soon. – kanudo Feb 13 '16 at 13:02
  • https://jsfiddle.net/0wx2mo8k/ here is my fiddle on this. I tried to use `mixed-blend-mode: unset` as well as `mixed-blend-mode: initial` on the parent element but seems to have no effect. – Kraang Prime Feb 13 '16 at 13:10
  • 1
    @SanuelJackson I also updated the answer with the improved one. In this we can specify the width of the main div with any accepted value and the internal or the pseudo element with the percent value. – kanudo Feb 13 '16 at 13:43
  • @SanuelJackson is the updated answer what you are looking for? – kanudo Feb 13 '16 at 13:54
  • 2
    Just a quick question on the coloring. How did you come up with the color 'cyan' for being the alternate 'red'. Just looking to figure the conversion as I am using a different color. Thanks again, and good job. Also, yes, that answer works well for me, and much less inline css / elements than I had making the complete rendering much smaller. Using this as part of an editable datagrid I am writing. I like how i can just apply the % value using `width: 50%` instead of `background-size: 50% auto !important` and also no need for any images. – Kraang Prime Feb 13 '16 at 14:06
  • 1
    The main reason of red color was where i learned it on css-tricks, I tried it with red, blue and black color, when i applied the white color to the current inner pseudo or the span element, the result was font on covered part displayed as cyan for red color. So i just adapted that. – kanudo Feb 13 '16 at 14:46
  • Which color do you will to use? I would like to find the color for that. – kanudo Feb 13 '16 at 14:52
  • 1
    I have put the whole project on jsbin so you can play. For some reason jsfiddle doesn't like my code anymore as it has funky rendering issues due to the way it injects the headers and such. http://jsbin.com/bowefokena/edit?css,output every field is 'editable' aside from the date/time and rating ones as I am sorting this progress bar issue out first. You can edit just by clicking the field and popping in a new value. It's also sortable on each column. Waiting until I have the core features done to publish initial version as a free oss script. – Kraang Prime Feb 13 '16 at 15:09
  • 1
    Ideally, I am looking for the progressbar skin to match the header, and the font on the bar to be dark on the white portion, and light on the dark portion. simple concept -- pita to implement apparently. – Kraang Prime Feb 13 '16 at 15:15
  • One question? even though `mix-blend-mode` has much less browser support, why you use it? do you use any poly-fill or patch? – kanudo Feb 13 '16 at 15:22
  • 1
    since mix-blend-mode is really only applicable to the progress bar state, it isn't of the highest importance if visibility of the numbers in older browsers is not supported. This is more 'default' settings, but the user can use or not depending on their preferences by adjusting the css. All modern browsers do support it. (not including IE since MS replaced it with Edge). I'm looking to keep this library as light as possible given the alternatives are generally quite bloated / slow / lacking. – Kraang Prime Feb 13 '16 at 15:26
  • Friend i was not able to find the perfect or near color which is required. But here is a [**different technique**](http://codepen.io/pmk/full/emBErK/) which may help you with the case. It used two elements with the text, one with base color and the other is after process color. Just have a look at the same. – kanudo Feb 13 '16 at 15:46