Advertisement
Advertisement


How to apply a CSS filter to a background image


Question

I have a JPEG file that I'm using as a background image for a search page, and I'm using CSS to set it because I'm working within Backbone.js contexts:

background-image: url("whatever.jpg");

I want to apply a CSS 3 blur filter only to the background, but I'm not sure how to style just that one element. If I try:

-webkit-filter: blur(5px);
-moz-filter: blur(5px);
-o-filter: blur(5px);
-ms-filter: blur(5px);
filter: blur(5px);

just underneath background-image in my CSS, it styles the whole page, rather than just the background. Is there a way to select just the image and apply the filter to that? Alternatively, is there a way to just turn the blur off for every other element on the page?

2019/07/26
1
476
7/26/2019 7:21:06 PM

Accepted Answer

Check out this pen.

You will have to use two different containers, one for the background image and the other for your content.

In the example, I have created two containers, .background-image and .content.

Both of them are placed with position: fixed and left: 0; right: 0;. The difference in displaying them comes from the z-index values which have been set differently for the elements.

.background-image {
  position: fixed;
  left: 0;
  right: 0;
  z-index: 1;
  display: block;
  background-image: url('https://i.imgur.com/lL6tQfy.png');
  width: 1200px;
  height: 800px;
  -webkit-filter: blur(5px);
  -moz-filter: blur(5px);
  -o-filter: blur(5px);
  -ms-filter: blur(5px);
  filter: blur(5px);
}

.content {
  position: fixed;
  left: 0;
  right: 0;
  z-index: 9999;
  margin-left: 20px;
  margin-right: 20px;
}
<div class="background-image"></div>
<div class="content">
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis aliquam erat in ante malesuada, facilisis semper nulla semper. Phasellus sapien neque, faucibus in malesuada quis, lacinia et libero. Sed sed turpis tellus. Etiam ac aliquam tortor, eleifend
    rhoncus metus. Ut turpis massa, sollicitudin sit amet molestie a, posuere sit amet nisl. Mauris tincidunt cursus posuere. Nam commodo libero quis lacus sodales, nec feugiat ante posuere. Donec pulvinar auctor commodo. Donec egestas diam ut mi adipiscing,
    quis lacinia mauris condimentum. Quisque quis odio venenatis, venenatis nisi a, vehicula ipsum. Etiam at nisl eu felis vulputate porta.</p>
  <p>Fusce ut placerat eros. Aliquam consequat in augue sed convallis. Donec orci urna, tincidunt vel dui at, elementum semper dolor. Donec tincidunt risus sed magna dictum, quis luctus metus volutpat. Donec accumsan et nunc vulputate accumsan. Vestibulum
    tempor, erat in mattis fringilla, elit urna ornare nunc, vel pretium elit sem quis orci. Vivamus condimentum dictum tempor. Nam at est ante. Sed lobortis et lorem in sagittis. In suscipit in est et vehicula.</p>
</div>

Apologies for the Lorem Ipsum Text.

Update

Thanks to Matthew Wilcoxson for a better implementation using .content:before http://codepen.io/akademy/pen/FlkzB

2020/05/28
540
5/28/2020 6:09:47 PM

pen

Abolishing the need for an extra element, along with making the content fit within the document flow rather than being fixed/absolute like other solutions.

Achieved using

.content {
  /* this is needed or the background will be offset by a few pixels at the top */
  overflow: auto;
  position: relative;
}

.content:before {
  content: "";
  position: fixed;
  left: 0;
  right: 0;
  z-index: -1;

  display: block;
  background-image: url('https://i.imgur.com/lL6tQfy.png');
  background-size:cover;
  width: 100%;
  height: 100%;

  -webkit-filter: blur(5px);
  -moz-filter: blur(5px);
  -o-filter: blur(5px);
  -ms-filter: blur(5px);
  filter: blur(5px);
}
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>

EDIT If you are interested in removing the white borders at the edges, use a width and height of 110% and a left and top of -5%. This will enlarge your backgrounds a tad - but there should be no solid colour bleeding in from the edges. Thanks Chad Fawcett for the suggestion.

.content {
  /* this is needed or the background will be offset by a few pixels at the top */
  overflow: auto;
  position: relative;
}

.content:before {
  content: "";
  position: fixed;
  top: -5%;
  left: -5%;
  right: -5%;
  z-index: -1;

  display: block;
  background-image: url('https://i.imgur.com/lL6tQfy.png');
  background-size:cover;
  width: 110%;
  height: 110%;

  -webkit-filter: blur(5px);
  -moz-filter: blur(5px);
  -o-filter: blur(5px);
  -ms-filter: blur(5px);
  filter: blur(5px);
}
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>

2020/07/22

As stated in other answers this can be achieved with:

  • A copy of the blurred image as the background.
  • A pseudo element that can be filtered then positioned behind the content.

You can also use backdrop-filter

There is a supported property called backdrop-filter, and it is currently supported in Chrome 76, Edge, Safari, and iOS Safari (see caniuse.com for statistics).

From Mozilla devdocs:

The backdrop-filter property provides for effects like blurring or color shifting the area behind an element, which can then be seen through that element by adjusting the element's transparency/opacity.

See caniuse.com for usage statistics.

You would use it like so:

.background-filter::after {
  -webkit-backdrop-filter: blur(5px); /* Use for Safari 9+, Edge 17+ (not a mistake) and iOS Safari 9.2+ */
  backdrop-filter: blur(5px); /* Supported in Chrome 76 */

  content: "";
  display: block;
  position: absolute;
  width: 100%; height: 100%;
}

.background-filter {
  position: relative;
}

.background {
  background-image: url('https://upload.wikimedia.org/wikipedia/en/6/62/Kermit_the_Frog.jpg');
  width: 200px;
  height: 200px;
}
<div class="background background-filter"></div>

Update (12/06/2019): Chromium will ship with backdrop-filter enabled by default in version 76 which is due out 30/07/2019.

Update (01/06/2019): The Mozzilla Firefox team has announced it will start working on implementing this soon.

Update (21/05/2019): Chromium just announced backdrop-filter is available in chrome canary without enabling "Enable Experimental Web Platform Features" flag. This means backdrop-filter is very close to being implemented on all chrome platforms.

2019/08/01

You need to re-structure your HTML in order to do this. You have to blur the whole element in order to blur the background. So if you want to blur only the background, it has to be its own element.

2014/11/29

Please check the below code:-

.backgroundImageCVR{
 position:relative;
 padding:15px;
}
.background-image{
 position:absolute;
 left:0;
 right:0;
 top:0;
 bottom:0;
 background:url('http://www.planwallpaper.com/static/images/colorful-triangles-background_yB0qTG6.jpg');
 background-size:cover;
 z-index:1;
 -webkit-filter: blur(10px);
  -moz-filter: blur(10px);
  -o-filter: blur(10px);
  -ms-filter: blur(10px);
  filter: blur(10px); 
}
.content{
 position:relative;
 z-index:2;
 color:#fff;
}
<div class="backgroundImageCVR">
    <div class="background-image"></div>
    <div class="content">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis aliquam erat in ante malesuada, facilisis semper nulla semper. Phasellus sapien neque, faucibus in malesuada quis, lacinia et libero. Sed sed turpis tellus. Etiam ac aliquam tortor, eleifend rhoncus metus. Ut turpis massa, sollicitudin sit amet molestie a, posuere sit amet nisl. Mauris tincidunt cursus posuere. Nam commodo libero quis lacus sodales, nec feugiat ante posuere. Donec pulvinar auctor commodo. Donec egestas diam ut mi adipiscing, quis lacinia mauris condimentum. Quisque quis odio venenatis, venenatis nisi a, vehicula ipsum. Etiam at nisl eu felis vulputate porta.</p>
      <p>Fusce ut placerat eros. Aliquam consequat in augue sed convallis. Donec orci urna, tincidunt vel dui at, elementum semper dolor. Donec tincidunt risus sed magna dictum, quis luctus metus volutpat. Donec accumsan et nunc vulputate accumsan. Vestibulum tempor, erat in mattis fringilla, elit urna ornare nunc, vel pretium elit sem quis orci. Vivamus condimentum dictum tempor. Nam at est ante. Sed lobortis et lorem in sagittis. In suscipit in est et vehicula.</p>
    </div>
</div>

2016/01/20

The following is a simple solution for modern browsers in pure CSS with a 'before' pseudo element, like the solution from Matthew Wilcoxson.

To avoid the need of accessing the pseudo element for changing the image and other attributes in JavaScript, simply use inherit as the value and access them via the parent element (here body).

body::before {
    content: ""; /* Important */
    z-index: -1; /* Important */
    position: inherit;
    left: inherit;
    top: inherit;
    width: inherit;
    height: inherit;
    background-image: inherit;
    background-size: cover;
    filter: blur(8px);
}

body {
  background-image: url("xyz.jpg");
  background-size: 0 0;  /* Image should not be drawn here */
  width: 100%;
  height: 100%;
  position: fixed; /* Or absolute for scrollable backgrounds */
}
2019/03/07