Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm trying to create an iOS 7 style frosted look with HTML5, CSS3 and JavaScript which can work on webkit browsers.

Technically, given the following HTML:

<style>
  #partial-overlay {
    width: 100%;
    height: 20px;
    background: rgba(255, 255, 255, .2); /* TODO frost */
    position: fixed;
    top: 0;
    left: 0;
  }
</style>
<div id="main-view">
  <div style="width: 50px; height: 50px; background: #f00"></div>
  To my left is a red box<br>
  Now there is just text<br>
  Text that goes on for a few pixels <br>
  or even more
</div>
<div id="partial-overlay">
  Here is some content
</div>

I'd like to apply something like a -webkit-filter: blur(5px) to the first 20px horizontally of #main-view.

If the CSS was modified to be #partial-overlay { width: 20px; height: 100%; ...} then I'd need to apply the -webkit-filter: blur(5px) to the first 20px vertically.

The obvious solution is to use javascript to make a clone of the #main-view, set overflow: hidden and then change the width/height as appropriate but that seems to me hard to generalize to more complex pages/CSS structures.

Is there a better way to achieve this with minimal performance hit and maximal generalizability?

EDIT: Here is an example of what I'm trying to achieve: Mockup

share|improve this question
CSS is an all or nothing thing. You can't just apply a property to an arbitrary portion of it. The closest you can get to "only the first 20px" is by using the :first-line pseudo element. – cimmanon Jun 13 at 16:37
@cimmanon see edited "obvious solution" – Aaron Yodaiken Jun 13 at 17:25
Could you show an image example of what you're looking to do? If I read the issue correctly you could try using the multiple backgrounds ability of css to achieve this. EDIT: also, here's a JSFIDDLE of his example for anyone who's answering this and want to test: jsfiddle.net/c6Lwf – Askanison4 2 days ago
@Askanison4 does that help? – Aaron Yodaiken 2 days ago
@cimmanon, just tried and webkit-filter: blur doesn't seem to work with first-line, looks like only some styles are allowed for that pseudo class – RDX yesterday
show 4 more comments

This question has an open bounty worth +300 reputation from Aaron Yodaiken ending in 5 days.

This question has not received enough attention.

7 Answers

Thanks for the inspiration... It led me to this canvas plugin which does the trick

Updated: -webkit- only Working Example

JS

$('#main-view').click(function () {
    html2canvas(document.body, {
        onrendered: function (canvas) {
            document.body.appendChild(canvas);
        },
        width: 300,
        height: 20
    });

    $('#cover').fadeIn('slow', function () {
        $('#partial-overlay').fadeIn('slow');
    });
});

CSS

  #partial-overlay {
    display:none;
    width: 100%;
    height: 20px;
    position: fixed;
    top: 0;
    left: 0;
    z-index:99; 
  }
canvas{
    height: 20px;
    position: fixed;
    top: 0;
    left: 0;
    -webkit-filter:blur(2px);
}
#cover{
    display:none;
    height:19px;
    width:100%;
    background:#fff;
    position:fixed;
    top:0;
    left:0;
}

HTML

<div id="main-view">
    <div style="width: 50px; height: 50px; background: #f00; float: left"></div>To my left is a red box
    <br>Now there is just text
    <br>Text that goes on for a few pixels
    <br>or even more</div>
<div id="cover"></div>
<div id="partial-overlay">Here is some content</div>

I put it in a click function, because I figured it would be the most likely use case. It will work just as well on document ready.

Although the canvas representation wont be pixel perfect, I don't think it will really matter in most cases because its being blurred.

Update: I added a white cover div between the content and the overlay and it seemed to solve the problem.

share|improve this answer
Hi, I added a picture to your post. I like that you can blur the background , but as @Antony pointed out, it just doesn't work for elements outside of the background image. – Aaron Yodaiken 22 hours ago
If you could somehow make an example where the background image is made by one of those "javascript screenshot" things and then blurred, that might be a really smart answer. – Aaron Yodaiken 22 hours ago
@AaronYodaiken thanks for the idea! – apaul34208 17 hours ago
@AaronYodaiken I just read through the comments on ken's answer. A little late I guess, but if you were still wondering if it would work... it does. Not sure about mixing this with blur.js as that plugin requires that the background image be served from the same source. – apaul34208 17 hours ago
This is just about the trick. The only problem is that the blur fades out at the edges of the canvas (not really a problem around the edges, but definitely at the bottom). Perhaps this can be fixed with some wrapper divs and whatnot, but I couldn't seem to get it to work quickly. – Aaron Yodaiken 17 hours ago
show 4 more comments

Is there a better way to achieve this with minimal performance hit and maximal generalizability?

The answer to this is no.

The reason is that in order to do what you want you would need direct access to the bitmap used for the browser window to extract or manipulate the pixels in the area you want to blur (I wish, "aero" in a browser could look pretty neat..) or a filter that works on the elements behind the one you apply it to (or can have a limiting region set to it).

As there is no native support to do this (besides canvas and extension API, or a library that generate canvas image from the html -> relatively slow) this will need to be done with trickery (images, splitting divs etc.) in either case.

If you made everything in your page on a canvas you could do a lot of interesting things, but you would also need to perform layout, update, filtering etc. yourselves and therefor you would be back no non-optimized as Javascript is slower than native (not to mention it would be error prone).

Until browsers allow you to grab a section of the window as a canvas (never? as that would require everything on that page to be same-origin or have content with special accept headers set) there is no way around but to do tricks.

Update

As an demonstration that you can do it by using html2canvas etc, but having to use compromises (-> slow performance) - the demo is rough, experimental and needs tweaks to work well - but for the sake of demo only:
http://jsfiddle.net/AbdiasSoftware/RCaLR/

Result:

enter image description here

Generalized function to grab part of background:

getBlurredBG(x, y, width, height, id);

Get part of window using html2canvas:

function getBlurredBG(x, y, w, h, id) {

    html2canvas(document.body, {
        onrendered: function (canvas) {
            process(canvas, x, y, w, h, id);
        },
        width: (x + w),
        height: (y + h)
    });
}

Process the content:

function process(canvas, x, y, w, h, id) {

    //create new canvas to enable clipping
    //As html2canvas returns a canvas from 0,0 to width and height
    //we need to clip it.
    var ocanvas = document.createElement('canvas');
    ocanvas.width = w;
    ocanvas.height = h;
    ocanvas.style.left = x + 'px';
    ocanvas.style.top = y + 'px';
    ocanvas.style.position = 'absolute';
    ocanvas.id = id;

    var ctx = ocanvas.getContext('2d');
    ctx.drawImage(canvas, x, y, w, h,
                          0, 0, w, h);

    stackBlurCanvasRGB(ocanvas, x, y, w, h, 28)
    lighten(ocanvas);

    ctx.fillStyle = 'rgba(255,255,255,0.5)';
    ctx.fillRect(x, y, w, h);

    ctx.fillStyle = '#999';
    ctx.font = '32px arial';
    ctx.fillText("Partial overlay content", 10, 60);

    document.body.appendChild(ocanvas);
}
share|improve this answer
I know that I've seen things that take screenshots of the whole page and you can send as PNG or whatever (like Google+ used to have). Isn't that window -> canvas? – Aaron Yodaiken 22 hours ago
@AaronYodaiken that's canvas. Libraries such as html2canvas can do this. It's however not an actual snapshot, but a close representation based on the element's geometry (element->boundaries->type->render close approx.). And for none-origin images it needs to use a proxy. But works for the purpose. – Ken - Abdias Software 18 hours ago
@AaronYodaiken I do mention this in my answer, but it would be slow for "real-time" use (perhaps an optimized partial "snapshot" could work well enough). One can always cache the snapshot but the user would need to wait while that happen. There will always be a need for a compromise as there is no native support. – Ken - Abdias Software 18 hours ago

http://thiv.net/frost

Live sample of what I did ( and updated to look just like the image above )

Code:

<style>
  #partial-overlay {
    width: 100%;
    height: 45px;
    background: #ffffff; /* TODO frost */
    -webkit-opacity:0.70;
    -webkit-filter: blur(5px);
    position: absolute;
    top: 20px;
    left: 0px;
    z-index:5;
  }
  #main-view
  {
   position: fixed;
   top: 20px;
   left: 80px;
   z-index:-1;
  }
</style>
<div id="main-view">
  <div style="width: 50px; height: 50px; background: #f00; position:fixed; left:10px; top: 40px; -webkit-filter: blur(2px); "></div>
    <div style="width: 80px; height: 60px; background: #fff; position:fixed; left:0px; top: 66px; -webkit-filter: blur(5px);"></div>
    <div style="width: 50px; height: 30px; background: #f00; position:fixed; left:10px; top: 60px;"></div>
  <p style="font-family:Sans, Arial, Verdana;">
  To my left is a red box<br>
  Now there is just text<br>
  Text that goes on for a few pixels <br>
  or even more
  </p>
</div>
<div id="partial-overlay">

</div>

I made it look a bit prettier than it needs to be, but It works!

share|improve this answer
2  
Sorry, I am trying to blur the background of the rectangle, not the rectangle itself. – Aaron Yodaiken yesterday
What do you mean? Inside it? or behind it? – Connor yesterday
Did you see the image in the question? Yours looks nothing like it. – Antony yesterday
+1 for your effort! – Grigor yesterday
Thanks man, seems like the asker has gone offline... I can host the page till he comes back... Also what you do come back, what is this being used for? It looks pretty cool! – Connor yesterday
show 4 more comments

Unfortunately there is no nice way of doing this, as you figured out you will need a copy of the main div:

<div class="wrapper">
   <div class="overlay"></div>
   <div id="main-copy"></div>
</div>

Overlay will push the wrapper width around while, main-copy will be in the background with blur. Obviously there will be performance issues if the content in main-copy is complex.

share|improve this answer

It has still very limited suport (only Firefox) but one way to get it could be this:

Firefox only demo

The CSS is quite simple:

#partial-overlay {
    width:400px; 
    height:100px; 
    background: -moz-element(#main-view);
    top: 0px;
    left: 200px;
    position: absolute;
    opacity: 0.3;
}

and the key is to use as background for partial overlay the main-view element.

This demo uses only opacity because filters are not availables for Firefox.

The element property for the background has been approved by w3c, so it could show sometime in the future in webkit

In the demo partial-overlay has been shift to the right to make more clear what is what

share|improve this answer

you can use SVG blur filter applied to a SVG element

I think it may help with your situation

http://css-plus.com/2012/03/gaussian-blur/

share|improve this answer

You can try with this code, for blur effect you have to use images.
So I have changed the color of overlay to black also made width as 400px, you can change as you want. Css:

<style>
#main
{
    width:400px;
    font-size:20pt;
    top:0px;
    left:0px;
}
#partial-overlay
{
    position: absolute;
    top:0px;
    left:0px;
    width:400px;
    height:50px;
    font-size:22pt;
    color:white;
    font-weight:bold;
    background: rgba(0, 0, 0, .5);  
}
</style>

html:

<div id="main">
        <div style="width: 50px; height: 50px; background: #f00; float:right;"></div>
        To my left is a red box<br>
        Now there is just text<br>
        Text that goes on for a few pixels <br>
        or even more
    </div>
    <div id="partial-overlay">
        Partial overlay content
    </div>
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.