M M M Madness
While I was preparing the slides from my full day CSS3 For Responsive Web Design at Smashing Magazine, I got very excited by the new filters in CSS. (313 onwards in my slide deck.) These filters — not to be confused with those legacy, proprietary Microsoft filters — are now well on their way to becoming part of a standard.
I’m also sketching out ideas for a new Stuff and Nonsense site header for launch in October and I thought now would be a good time to get familiar with using filters, perhaps to create something with a little more ‘depth’ than our previous designs, perhaps even something that could animated or respond to mouse movements (or touch.)
Playing around with our current header, I added a blur filter to the madness header division.
.madness {
-webkit-filter : blur(5px);
filter : blur(5px); }
Then i notice that the filter effect inherits to child elements.
The header’s made up of a <header> element, wrapper <div> to group (and help centre) the nutty boys and then the characters themselves, cheekily spelling the word Madness.
<header class="madness">
<div>
<span class="madness__m">M</span>
<span class="madness__a">a</span>
<span class="madness__d">d</span>
<span class="madness__n">n</span>
<span class="madness__e">e</span>
<span class="madness__s">s</span>
<span class="madness__s2">s</span>
</div>
</header>
I didn’t think ‘un-blurring’ the nutty boys would be a problem:
.madness {
-webkit-filter : blur(0);
filter : blur(0); }
or,
.madness {
-webkit-filter : none;
filter : none; }
Silly me.
Turns out there’s no way to un-filter a child element. (Who thought that was a good idea? Honestly?)
I wanted to blur the background and not the nutty boys so I had to use some CSS generated content gymnastics to accomplish that.
First up, turn the header into a positioning context:
.madness {
position : relative; }
Add a pseudo element using :before. Pseudo elements (:before and :after) are placed inside their parent element and can be positioned the same as any (real) element. Stretch out that pseudo element so that it covers its parent completely.
.madness:before {
content : "";
position : absolute;
top : 0;
right : 0;
left : 0;
bottom : 0; }
Now add the street background image to that pseudo element and blur it:
.madness:before {
background: transparent url(banner-madness-lg.png) repeat-x -20% 0;
-webkit-filter : blur(5px);
filter : blur(5px); }
Almost.
The blur effect makes for some nuttiness around the edges of the image, so reset the pseudo element’s position so that it extends outside of its parent.
.madness:before {
top : -10px;
right : -10px;
left : -10px;
bottom : -10px; }
Much better.
I thought it would be fun to move the blurred background while it was moving, so I added an animation:
@-webkit-keyframes slide {
from { background-position : 0 0; }
to { background-position : -10000px 0; }
}
@keyframes slide {
from { background-position : 0 0; }
to { background-position : -10000px 0; }
}
.madness:before {
background-position : 0 0;
-webkit-animation : slide 600s linear infinite;
-moz-animation : slide 600s linear infinite;
-ms-animation : slide 600s linear infinite;
-o-animation : slide 600s linear infinite;
animation : slide 600s linear infinite; }
While the animation and blur effect combined looked great, performance was terrible. The animation was jerky and scrolling the page become incredibly laggy.
David Yarham on Twitter suggested a 3D transformation with zero values might help..madness:before {
-webkit-transform : translate3d(0,0,0);
transform : translate3d(0,0,0); }
I’m still not sure why this works, but I’m not complaining.
Here’s everything wrapped into a nutty demo. You’ll need Chrome to see the effects.
So a few takeaways from this little experiment:
- Generated content is incredibly useful
- Filter inheritance can be a pain
- Not having the ability to override inherited filters is, you guessed it, madness