Filter

CSS filter generator

Turn a hex value into a filter chain that recolours a black icon, for the times you cannot reach the fill.

Target colour

#0e8f8a

Hex, rgb(), hsl() or a CSS keyword.

Result

exact · ΔE 0
Source (black)
Filtered
wanted#0e8f8a
got#0e8f8a

Exact: indistinguishable from the target.

filter: brightness(0) saturate(100%) invert(8%) sepia(93%) saturate(508%) hue-rotate(128deg) brightness(453%) contrast(76%);
What each step does
  • brightness(0) saturate(100%): forces the source to solid black, so the chain behaves the same on any image.
  • invert(8%): lifts it off black.
  • sepia(93%): introduces a hue to work with.
  • saturate(508%): pushes the chroma.
  • hue-rotate(128deg): turns it to the target hue.
  • brightness(453%): sets the level.
  • contrast(76%): final correction.

Use it

On an img

<img src="icon.svg" style="filter: brightness(0) saturate(100%) invert(8%) sepia(93%) saturate(508%) hue-rotate(128deg) brightness(453%) contrast(76%);">

As a utility class

.icon-brand { filter: brightness(0) saturate(100%) invert(8%) sepia(93%) saturate(508%) hue-rotate(128deg) brightness(453%) contrast(76%); }
01

The problem it solves

An inline SVG is easy to recolour: set fill or use currentColor and you are done. The trouble starts everywhere else.

An SVG loaded through an <img> tag is a separate document, so CSS on your page cannot reach inside it. The same applies to a background-image, an icon in a sprite sheet, a PNG, and any asset from a third party you are not allowed to modify. In all of those the fill is out of reach.

A CSS filter does not care. It operates on the rendered pixels after the element is drawn, so it recolours the icon whatever its source.

02

How the chain works

There is no recolor() filter, so the effect is built out of the ones that do exist. Black has no hue and no saturation, so nothing can be rotated or saturated until it is lifted off black. That is what invert() is for. sepia() then introduces a fixed warm hue, which saturate() intensifies and hue-rotate() turns to wherever you actually wanted. brightness() and contrast() trim the level at the end.

No formula gives the six values that land on a specific colour, so finding them is a search problem. This page fits them numerically, evaluating the real filter maths from the Filter Effects specification at each step, and reports how close it got. The search is seeded, so the same hex always gives the same chain.

03

When not to use it

When you control the SVG. Inline it and set fill: currentColor. That is exact, readable and free.

When the icon is multicoloured. The chain assumes a single-colour source. A two-tone icon will come out as one tone.

When you need many colours. A separate filter chain per colour gets unmanageable quickly. Use an icon font, a sprite with mask-image, or inline SVG instead. A CSS mask over currentColor is the cleaner pattern when you own the assets.

When it must match exactly. If the tool reports the fit as approximate, and the icon sits next to something in the true brand colour, the difference will be visible. Check the two swatches above before committing.

Need the value in another notation first? The converter takes any input and gives you the hex to paste here.

Frequently asked questions

Why would I use a filter instead of just changing the fill?

Often you cannot. For an icon in an <img> tag, a background-image, a sprite sheet, or an SVG from a third party you are not allowed to edit, the fill is not reachable from CSS. A filter recolours the rendered pixels regardless.

Why does the chain start with brightness(0) saturate(100%)?

It forces whatever the source was to solid black first, so the rest of the chain has a known starting point. Without it the result would depend on the original colour of your icon, and the same filter would produce different results on different images.

Why is the result sometimes not exact?

Six filter functions do not span the whole colour space. Very dark saturated colours and some deep purples are hard to hit. The tool reports how close it actually got rather than presenting a near miss as a match. If it says approximate, compare the two swatches before shipping it.

Will I get the same CSS if I run it again?

Yes. The search is seeded from a fixed constant, so a given hex always produces the same chain. A tool that returned different values on every visit would be unusable in a stylesheet you have to maintain.

Is there a cost to using filters?

They are composited on the GPU and are cheap for static elements. Avoid animating a filter chain on many elements at once, and be aware that a filter creates a containing block, which can affect fixed-position descendants.

Read the guide

  • How to use color codes in CSSEvery way CSS accepts a colour, why custom properties beat repeating hex codes, and the relative-colour syntax that replaces most of your Sass functions.
  • What is a HEX color code?Reading a hex code by eye, the shorthand form, the alpha byte, and the arithmetic underneath.