Reputation: 1760
I am experimenting with css filters.
And I would like use the blur and grayscale at the same time, but I can't seem to use both simultaneously on the same image?
See fiddle here...
http://jsfiddle.net/joshmoto/fw0m9fzu/1/
.blur {
filter: blur(5px);
-webkit-filter: blur(5px);
-moz-filter: blur(5px);
-o-filter: blur(5px);
-ms-filter: blur(5px);
}
.grayscale {
filter: grayscale(1);
-webkit-filter: grayscale(1);
-moz-filter: grayscale(1);
-o-filter: grayscale(1);
-ms-filter: grayscale(1);
}
.blur-grayscale {
filter: blur(5px) grayscale(1);
-webkit-filter: blur(5px) grayscale(1);
-moz-filter: blur(5px) grayscale(1);
-o-filter: blur(5px) grayscale(1);
-ms-filter: blur(5px) grayscale(1);
}
Upvotes: 126
Views: 160809
Reputation: 56
Building off of Billy Mitchell's answer, you could set fallbacks for each custom property removing the need to define "empty" variables up front in the :root
. Depending on how many filters you're using, this could get quite long, but possibly still a cleaner option.
.filter {
filter: blur(var(--blur, 0)) contrast(var(--contrast, 1)) brightness(var(--brightness, 1)) grayscale(var(--grayscale, 0)) hue-rotate(var(--hue-rotate, 0deg)) invert(var(--invert, 0)) saturate(var(--saturate, 1)) sepia(var(--sepia, 0));
}
From MDN CSS custom properties (variables) article
The first argument to the function is the name of the custom property. The second argument to the function is an optional fallback value, which is used as the substitution value when the referenced custom property is invalid. The function accepts two parameters, assigning everything following the first comma as the second parameter. If the second parameter is invalid, the fallback will fail.
EXAMPLE
.myImage {
/* Set baseline vars */
--filter_Sepia: 0%;
--filter_HueRotate: 0deg;
--filter_Blur: 0px;
/* Set one filter that handles multiple dynamic properties */
/* Extra fallback (after the comma) if there's a problem getting a var */
filter: sepia(var(--filter_Sepia, 0%)) hue-rotate(var(--filter_HueRotate, 0deg)) blur(var(--filter_Blur, 0px));
}
/* Classes for different external contexts; change var value accordingly */
.myImage.useSepia {
--filter_Sepia: 90%;
}
.myImage.useHueRotate {
--filter_HueRotate: 336deg;
}
.myImage.useBlur {
--filter_Blur: 10px;
}
Upvotes: 1
Reputation: 3759
If that can be applied to your situation, you can use filter classes on parent elements. If you have an arbitrary number of classes to apply, you can create the containing div
s using javascript.
<div class="blur">
<div class="grayscale">
<img />
</div>
</div>
Upvotes: 0
Reputation: 7856
As this seems to be missing from the answers so far and only mentioned in a comment, here is what works:
Simply combine multiple filters separated by space, such as:
filter: grayscale() blur(5px);
Also see here.
Upvotes: 8
Reputation: 21
I am using this.
/* Multiple filters */
backdrop-filter: url(filters.svg#filter) blur(4px) saturate(150%);
Upvotes: 2
Reputation: 149
I'm trying to create utility classes in vanilla CSS and this would be helpful but it looks like it can not be done this way.
<img class="brightness-20 image-grayscale-100">
.brightness-20 {
filter:brightness(20%);
}
.image-grayscale-100 {
filter: grayscale(100%);
}
I'm not sure why they didn't just create a more specific property like:
filter-brightness: 20%; filter-grayscale: 100%
After some more work I came up with this solution:
/*Initalize Variables No Adjustments*/
:root {
--blur:0px;
--contrast:100%;
--brightness:100%;
--contrast:100%;
--dropshadow:0px 0px 0px black;
--grayscale:0%;
--hue-rotate:0deg;
--invert:0%;
--opacity:100%;
--saturate:100%;
--sepia:0%;
}
/*Apply Defult Variables To Image*/
.filter {
filter: blur(var(--blur)) contrast(var(--contrast)) brightness(var(--brightness)) contrast(var(--contrast)) drop-shadow(var(--dropshadow)) grayscale(var(--grayscale)) hue-rotate(var(--hue-rotate)) invert(var(--invert)) opacity(var(--opacity)) saturate(var(--saturate)) sepia(var(--sepia));
}
/*Override Defults*/
.brightness-20 {
--brightness:20%;
}
.image-grayscale-100 {
--grayscale: 100%;
}
Upvotes: 11
Reputation: 6176
Because it's one property named filter
, every time you want to add a style to it you override it.
Fortunately you can add multiple styles in some properties like background-image and filter! To get this working you'll have to put all the filter styles in one space separated filter property.
.grayscale.blur {
filter: blur(5px) grayscale(1);
}
An alternative, flexible, solution would be to create a "div soup" on purpose and set different filters in the html stack. e.g.
<div class='demo__blurwrap' style='filter: blur(5px);'>
<div class="demo__graywrap" style='filter: grayscale(1);'>
<img src="awesome_image.jpeg" alt="">
</div>
</div>
edit: just realised I just wrote this version with transforms, but the same idea applies.
Yet another solution is CSS vars. I wouldn't say it's ideal but it's a nice experiment. The major downside is that you need to declare a lot of variables, have default long rules for transform
and nested transforms will definitely break.
// Added just for fun
setInterval(() => {
yes_this_works_and_one_of_many_reasons_ids_are_bad.classList.toggle('translate');
}, 1000);
setInterval(() => {
yes_this_works_and_one_of_many_reasons_ids_are_bad.classList.toggle('scale');
}, 1500);
:root {
--scale: 1;
--translate: 0px;
}
.box {
background: blue;
width: 20px;
height: 20px;
transform:
scale(var(--scale))
translate(var(--translate), var(--translate));
transition: transform .3s;
}
.box.translate {
--translate: 20px;
}
.box.scale {
--scale: 3;
}
<div
id='yes_this_works_and_one_of_many_reasons_ids_are_bad'
class='box scale translate'
></div>
Lastly, if you were to use JavaScript to render the styles you can read the current applied filters using getComputedStyle and add more to the mix.
And a relevant article - this is more for animations and not yet supported by many browsers: Additive animations
And another relevant article on css-tricks: Houdini
Upvotes: 197