8

I have a CP437 tileset:

enter image description here

which I want to use as a CSS sprite on a webpage Currently, I have a very simple markup and css:

.tile {
    display: inline-block;
    width: 16px;
    height: 16px;
}

.cp437-0 {
    background: url('tileset/tileset.png') 0 0;
}

.cp437-1 {
    background: url('tileset/tileset.png') 16px 0;
}

// ...

<span class="tile, cp437-0">&nbsp;</span>

This works very well, but I'd also like to add color to these grayscale sprites. How can I do this with using HTML/CSS or Javascript?

Is it possible to set background color for the resulting image?

Clarification:

I'd like to be able to draw things like these to the browser window using the sprite:

enter image description here enter image description here

Adam Arold
  • 29,285
  • 22
  • 112
  • 207
  • What do you mean by "background color"? There is a simple CSS property called `background-color` that will do it. Please clarify your question. As it stands everyone, me included, seems to have understood you wanted to change the white to black into some other shade. Is it so? And then, since your image is made of a shade of color, what should be the master one? I.e, if you set it to *color1* should it be *white to color1* or *color1 to black* or *color1 to color2* maybe? – Kaiido Sep 28 '18 at 14:54
  • I have a single file (pasted into my question) and I want to use it as you would use a Text Icon (FontAwesome for example). I would also like to set the background and foreground (this is what color the grayscale sprite will get converted to) individually. I've updated my question for clarification. – Adam Arold Sep 28 '18 at 21:26
  • So from color1 to black no background on your example (well the ivory one but I hope you know how to make it). Why do you use a css spritesheet if what you want is actually a font? What doesn't work with Lazar's solution? – Kaiido Sep 28 '18 at 23:42
  • Because fonts are not pixel perfect. I tried that approach before. – Adam Arold Sep 29 '18 at 00:20

4 Answers4

5

You can abuse the fact that the sepia filter can saturate a grayscale input:

.blue {
  filter: sepia(100%) hue-rotate(150deg) brightness(80%) saturate(420%);
}

.red {
  filter: sepia(100%) hue-rotate(300deg) brightness(80%) saturate(420%);
}
<img src="https://i.stack.imgur.com/nQET4.png" class="blue" />
<img src="https://i.stack.imgur.com/nQET4.png" class="red" />

Tuning the filters to get the desired results is tricky, but as you can see in this example, it's doable just fine.

John Weisz
  • 30,137
  • 13
  • 89
  • 132
  • Is there a way to map the desired colors to these CSS properties? – Adam Arold Oct 14 '22 at 19:17
  • @AdamArold I'm sure there is, `hue-rotate` is the key filter here: it changes from the brownish-sepia color by "rotating" the color hue, like you would in photoshop. So the first thing you need to do here is computing what you pass into `hue-rotate`, e.g. from an input RGB value. Sounds tricky, but 100% doable. – John Weisz Oct 17 '22 at 08:13
4

There's no pure CSS way to do this -- you'll need at least some SVG magic. For example, you can define a filter. It's, however, tricky to nail the color as it requires some not-so-trivial knowledge of maths, matrices and how computers work with colors.

Here's an example with golden images.

.defs-only {
  position: fixed;
  left: -9999px;
  top: -9999px;
  z-index: -1;
  width: 1px;
  height: 1px;
}

img {
  filter:  url(#monochrome);
}
<svg class="defs-only">
  <filter id="monochrome" color-interpolation-filters="sRGB"
          x="0" y="0" height="100%" width="100%">
    <feColorMatrix type="matrix"
      values="1.00 0 0 0  0 
              0.80 0 0 0  0  
              0.65 0 0 0  0 
                0  0 0 1  0" />
  </filter>
</svg>

<img src="https://i.stack.imgur.com/nQET4.png">

Check out, for example, this article for more info.

Lazar Ljubenović
  • 18,976
  • 10
  • 56
  • 91
  • Is there some code for this which can just convert a css color like `#ab1248` to a filter like this? – Adam Arold Sep 27 '18 at 21:21
  • As I mentioned: "It's, however, tricky to nail the color as it requires some not-so-trivial knowledge of maths, matrices and how computers work with colors." – Lazar Ljubenović Sep 27 '18 at 21:21
  • You can check out the linked article from the answer for the maths. – Lazar Ljubenović Sep 27 '18 at 21:22
  • And with javascript? – Adam Arold Sep 27 '18 at 21:22
  • JavaScript would require some usage of canvas, with even more low-level handling than SVG. I don't think it's possible -- not trivially, at least. But sure: it _can_ be done. If you can get a non-grayscale image you would easily be able to rotate the hue. But your image is _really_ working against all possible solutions (the transparency is also screwing up, see my other answer). – Lazar Ljubenović Sep 27 '18 at 21:34
  • I can change the image. But I'd want to set fore and background colors individually. Imagine it like this: https://cdn.discordapp.com/attachments/363771631727804416/491721308217016321/unknown.png – Adam Arold Sep 27 '18 at 21:39
  • Ouch, with changing both background _and_ foreground color (independently), I think it's completely impossible. You'd need some pretty elaborate JavaScript to generate such images on the client. Sorry! :/ – Lazar Ljubenović Sep 27 '18 at 21:41
  • I think this should be pretty easy with the `canvas` component, no? – Adam Arold Sep 27 '18 at 21:46
  • Check this: https://stackoverflow.com/questions/45706829/change-color-image-in-canvas – Adam Arold Sep 27 '18 at 21:47
  • Do not hide your svg with display none. Some browsers won't render your filter (like FF). Instead set their size to 0 position to absolute and z-index to a negative value. – Kaiido Sep 28 '18 at 23:45
  • @Kaiido Do you know if that's by spec? – Lazar Ljubenović Sep 29 '18 at 10:05
  • I don't think so no, but it's an outstanding bug since browsers started to implement SVG. It has been argued it was actually a specs bug since it wasn't technically compatible with how CSS works (display:none elements should be completely ignored), but I'm not sure they did ever change the specs... An interesting discussion [here](https://bugzilla.mozilla.org/show_bug.cgi?id=376027) (that I didn't read all myself...) – Kaiido Sep 29 '18 at 11:21
2

You could also use blend-modes but since your image is transparent, it will unfortunately apply the background-color to the... background, as well. If you can get the same image with the black background, it would work. A full list of blend modes if available at MDN, so you can play with different values.

.sprite {
  width: 256px;
  height: 256px;
  background-image: url(https://i.stack.imgur.com/nQET4.png);
  background-color: #ab1248;
  background-blend-mode: hard-light;
  
}
<div class="sprite">
Lazar Ljubenović
  • 18,976
  • 10
  • 56
  • 91
  • I'd like to set background and foreground colors individually. Something like this: https://cdn.discordapp.com/attachments/363771631727804416/491721308217016321/unknown.png – Adam Arold Sep 27 '18 at 21:38
1

If you work with transparent png, you can combine mask and mix-blend-mode

.bubble{
  display: inline-block;
  float: left;
  -webkit-mask: url(https://i.stack.imgur.com/og0JD.png);
  mix-blend-mode: normal;
  width:20px;
  height:20px;
}

#color1{
  background-color:blue;
}

#color2{
  background-color:red;
}

#color3{
  background-color:green;
}
#color4{
  background-color:yellow;
}
#color5{
  background-color:pink;
}
<div id="color1" class="bubble"></div>
<div id="color2" class="bubble"></div>
<div id="color3" class="bubble"></div>
<div id="color4" class="bubble"></div>
<div id="color5" class="bubble"></div>

enter image description here

scraaappy
  • 2,830
  • 2
  • 19
  • 29