CSS filter Property
The filter property applies post-processing graphical effects like blurring or color shifting to an element before it is rendered.
| none | Ensures no filter effects are applied to the element. |
| blur(<length>) | Applies a Gaussian blur to the element using a radius defined by a length unit. |
| brightness(<number-percentage>) | Adjusts the brightness of the element where 0% is black and 100% is original. |
| contrast(<number-percentage>) | Adjusts the difference between the darkest and lightest parts of the element. |
| drop-shadow(<shadow>) | Applies a shadow effect that follows the alpha channel of the element's content. |
| grayscale(<number-percentage>) | Converts the element to black and white based on the specified intensity. |
| hue-rotate(<angle>) | Rotates the colors of the element by a specific angle on the color wheel. |
| invert(<number-percentage>) | Flips the colors of the element to their opposite values on the color spectrum. |
| opacity(<number-percentage>) | Sets the transparency level of the element similar to the standalone opacity property. |
| saturate(<number-percentage>) | Controls the intensity of the colors within the element. |
| sepia(<number-percentage>) | Applies a brownish-gray vintage tint to the element. |
| url(<url>) | References an external or inline SVG filter element to apply complex effects. |
Code Examples
This basic example turns an image black and white and increases contrast, then restores color and adds a drop shadow on hover.
<style>
.image-container img {
filter: grayscale(100%) contrast(120%);
transition: filter 0.4s ease;
}
.image-container img:hover {
filter: grayscale(0%) contrast(100%) drop-shadow(8px 8px 15px #000000);
}
</style>
<div class="image-container">
<img src="https://www.adamkhoury.com/images/adam_khoury.jpg" alt="Adam Khoury">
</div>This advanced example uses JavaScript to toggle a complex multi-filter string that simulates a night vision effect on a container.
<div id="stage" style="padding: 20px; background: #f0f0f0;">
<h1 id="statusText">Night Vision Mode</h1>
<button onclick="toggleNightVision()">Toggle Effect</button>
</div>
<script>
let isActive = false;
const stage = document.getElementById("stage");
function toggleNightVision() {
isActive = !isActive;
if (isActive) {
stage.style.filter = "invert(1) hue-rotate(90deg) brightness(1.5) contrast(1.2)";
stage.style.backgroundColor = "#ffffff";
} else {
stage.style.filter = "none";
stage.style.backgroundColor = "#f0f0f0";
}
}
</script>Pro Tip
You can use filter: drop-shadow() to create an outer glow for non-rectangular icons or text, which is much cleaner than trying to stack multiple shadows. Another slick trick is using filter: invert(1) hue-rotate(180deg) to quickly turn a light-themed interface into a dark-themed one while keeping your brand colors relatively consistent. This is a great shortcut for prototyping dark modes before you have the time to build a full custom color palette.
Deep Dive
Think of the filter property like a translucent lens or a piece of colored glass placed in front of your element. Instead of changing the actual source image or text data, the browser calculates a visual post-processing effect on the fly. It renders the element into a temporary buffer, applies the mathematical functions, and then draws the result to the screen. You can stack multiple filters by separating them with spaces, and the browser applies them in order from left to right, similar to an assembly line. This allows for complex visual pipelines where you can desaturate an image and then apply a drop shadow to the result. Because it happens at the final stage of rendering, it does not affect the layout or flow of other elements on the page, meaning a blurred element still occupies the same space it did before the filter was applied.
Best Practices
Keep performance in mind by not overusing filters on high-resolution images or large sections of the page, especially on mobile devices where GPU resources are limited. If you need to animate filters, stick to hardware-accelerated ones like opacity or simple color shifts. When using multiple filters, remember that order matters; applying a blur before a drop-shadow will yield a different visual result than applying the shadow first. Use CSS variables to control filter values if you are building themes, which makes it much easier to update several filters at once without re-writing long strings. Always test your UI with filters enabled to ensure that text remains legible against its background, particularly when using contrast or brightness adjustments.
Common Pitfalls
A common mistake is using box-shadow instead of drop-shadow() on transparent PNGs or SVGs; box-shadow only puts a shadow on the element's bounding box, while drop-shadow() respects the actual pixels of the image. Another pitfall is the performance hit caused by blur(); a large radius can make the page stutter during scrolling. Developers often forget that filters create a new stacking context, which can mess with z-index behavior in ways you might not expect. Also, remember that filters are applied after the element is painted, so they don't change the actual layout box of the element. If you apply a 20px blur, the element still technically occupies its original footprint in the DOM.
Accessibility
Filters can easily break color contrast ratios required for accessibility standards. If you use grayscale(100%) or invert(100%), check that your text is still readable for all users. Avoid hue-rotate() animations that cycle colors rapidly, as this can be problematic for users with photosensitive epilepsy. Be careful with opacity filters; if the background and foreground colors become too similar, users with low vision will struggle. Always provide a way to disable or toggle heavy visual filters if they are not essential to the content. Remember that screen readers do not see the filter, so they will read the original text regardless of how distorted the filter makes the element appear.
Dev Data Table: filter property
| default | none |
| animatable | yes |
| inherited | no |
| experimental | no |
| year_intro | 2012 |
| year_standard | 2018 |
| js_syntax_1 | element.style.filter = "blur(5px)"; |
| js_syntax_2 | element.style.setProperty("filter", "sepia(100%)"); |
| js_note | When manipulating multiple filter functions through JavaScript, you must provide them as a single space-separated string. |
| browsers | { "Chrome": 53, "Edge": 12, "Firefox": 35, "Safari": 9.1, "Opera": 40, "Chrome Android": 53, "Safari on iOS": 9.3, "Samsung Internet": 6, "Opera Mobile": 40 } |