37

Is it possible to tint an image with a specific color using CSS without an overlay in a WebKit browser?

Failed attempts

  • Managed to tint the image sepia or an arbitrary color using hue-rotate but couldn't find a way to tint it with a specific color.
  • Creating a "tint" SVG filter and calling it with -webkit-filter: url(#tint) doesn't work on Chrome.
  • All possible combinations of opacity/box-shadow css properties with drop-shadow/opacity filters don't generate the desired effect.

Ideas

  • Given a color, wouldn't it be possible to combine the HSB filters (hue-rotate, saturation, brightness) to generate its tint?
hpique
  • 119,096
  • 131
  • 338
  • 476
  • 20
    I wonder why sepia got a royal treatment. – hpique Sep 22 '12 at 18:27
  • I've seen several solutions which rely on a canvas and javascript to do exactly that...which is less than ideal. – Lorenz Lo Sauer Sep 22 '12 at 18:34
  • You've made a typo with `-webkit-filter` in the question. Might be good to confirm that you didn't make the same typo in your code? ;-) – Spudley Sep 22 '12 at 21:00
  • The `filter` CSS style was just for SVG, but it is coming to standard HTML now as well. I'm not certain which browsers support it yet, but if it's implemented in your target browsers, then you don't need to use SVG for this; just apply the style directly on the `` HTML tag. (see http://caniuse.com/#feat=css-filters for browser support matrix) – Spudley Sep 22 '12 at 21:03
  • @hpique: w. Adobe FilterLabs, Chrome Canary Builds and the git community it may come down to hours till you have a ready solution... – Lorenz Lo Sauer Sep 24 '12 at 18:37
  • Rik Cabanier from Adobe (I think) seems to have been the first to suggest specific CSS filter shorthands (not all of these made it) http://lists.w3.org/Archives/Public/public-fx/2011JanMar/0107.html – Michael Mullany Jul 28 '16 at 00:14

5 Answers5

26

Eventually it will be, using shaders. See the W3C Docs on Filters.

At the moment, what is possible for instance is:

-webkit-filter: grayscale; /*sepia, hue-rotate, invert....*/
-webkit-filter: brightness(50%); 

See

Update:

Adobe released its HTML5 based CSS Filter Labs with support for custom filters (Shaders) on supported browsers:

enter image description here

Community
  • 1
  • 1
Lorenz Lo Sauer
  • 23,698
  • 16
  • 85
  • 87
20

While there are no stand alone tint filter you can make kind of one by composition of existing filters without shading.

Combine sepia to unify the color, then hue-rotate to the color you want it to be tinted with

-webkit-filter: sepia(90%) hue-rotate(90deg);

I use borders with an alpha value for my tints, its really an overlay but doesn't use any extra DOM elements making the transition to sepia+hue-rotate simpler when the other browsers get those filters.

krs
  • 4,096
  • 19
  • 22
  • hue-rotate is pretty much broken - it does a very inaccurate job on saturated colors - particularly yellows because it's actually doing a pretty poor approximation in RGB space, not true HSL space. – Michael Mullany Jul 05 '15 at 22:29
  • Unless I'm missing something, this largely doesn't work for white-on-black images, because sepia & hue-rotate don't much affect white. – Grant Birchmeier Jan 25 '16 at 15:42
  • 1
    @GrantBirchmeier `brightness(50%);` will turn white to gray. – GKFX Jul 24 '16 at 14:52
19

This is possible using an SVG filter today without having to use shaders. You can use this as a CSS filter (although it won't work in IE) through the -webkit-filter: "url(#yourfilterID)" etc. syntax.

<svg width="800px" height="600px" viewbox="0 0 800 600">
    <defs>
        <filter id="f1" x="0%" y="0%" width="100%" height="100%" color-interpolation-filters="sRGB">
        <feColorMatrix id="tinter" type="matrix" values=".6 .6 .6 0 0 
                                                            .2 .2 .2 0 0 
                                                            .0 .0 .0 0 0 
                                                             0    0   0 1 0"/>
        </filter>     
    </defs>

 <image x="0" y="0" width="550" height="370" preserveAspectRatio="true"
    filter="url(#tinter)" xlink:href="http://www.crossfitwaxahachie.com/wp-content/uploads/2012/04/IMG_0752.jpg"/>
</svg>

Dynamic demo at http://codepen.io/mullany/details/baLkH/

Michael Mullany
  • 30,283
  • 6
  • 81
  • 105
  • 2
    why hasnt this been upvoted more? @Michael Mullany is there a way you know of to translate hex colors to matrix values? – dopatraman Jul 05 '15 at 18:25
  • 2
    matrix values are on a 0 to 1 scale - so just take your hex value and divide it by 255 (or FF) to get the values you want. e.g if you want 100% red, then the first row will be 1 1 1 0 0. If you want 50% green, the second row will be 0.5 0.5 0.5 0 0 etc. – Michael Mullany Jul 05 '15 at 21:47
  • I understand the first 4 columns are RGBA but... what is the 5th column for? – dopatraman Jul 05 '15 at 22:18
  • 1
    the fifth column adds a fixed sum to the color. here is a link to a mostly still accurate presentation on filters: http://www.slideshare.net/mullany1/svg-filters-html5-devconf-apr-2013. This was a much later answer - so that's why not so many upvotes. Also the original answer is now obsolete/wrong - CSS Shaders have been dropped from the web roadmap – Michael Mullany Jul 05 '15 at 22:25
13
box-shadow: inset 0px 0px 64px 64px cornflowerblue, 0px 0px 4px 4px cornflowerblue;

A tint in any color (rather than sepia or rotation filters which aren't supported everywhere) could be achieved by an inset box-shadow, in the appropriate size.

Soviut
  • 88,194
  • 49
  • 192
  • 260
Frevd
  • 147
  • 1
  • 3
  • 4
    Please add some explanation to your answer too! – ρss Jun 10 '14 at 20:38
  • Very nice! I was looking for something with text; This technique can be applied to text by using `text-shadow` only to color the back of the text then just apply some transparent `color`.... – cvsguimaraes Sep 02 '15 at 12:01
  • 4
    Am I crazy, or does this not actually tint any foreground elements? Per CSS3, inset shadows appear below content, meaning they don't affect images or text *at all*, which is exactly what I'm seeing in my experimental page. – Grant Birchmeier Jan 25 '16 at 15:44
  • This is a nice trick. Indeed, it only works on background, it doesn't change the foreground. (But that is enough for my need.) Semi-transparent colors can be set using `rgba` syntax: `box-shadow: 0 0 0 9999px rgba(255, 0, 0, 0.25) inset;` – Denilson Sá Maia Sep 05 '17 at 15:27
7

How about an underlay then?

HTML:

<span class="tint"><img src="..." /></span>

CSS:

.tint { background-color:red; display:inline-block; }
.tint img { opacity:0.8 }

Tweak the color and opacity as you wish. Doesn't really work on images with transparency in them.

DanMan
  • 11,323
  • 4
  • 40
  • 61