How can I tint a background image with CSS?
Asked Answered
D

6

65

I have a background image set up through CSS.

html {
background-image: url('../img/cello.jpg');
background-attachment: fixed;
background-size: 100%;
}

I plan on having a different background image for different pages of the website: so it's important that text is legible over it. Right now I've got a translucent black background to my #main content box in the middle like this in order to ensure legibility:

#main {
background: rgba(0, 0, 0, 0.5);
}

What I really want to do, though, is to have that kind of translucent background over the entire background image, because the black box looks a bit clunky. I've tried making a <div id=#tint> which includes the whole HTML document and giving rgba(0, 0, 0, 0.5) to #tint, but that doesn't work at all--I can either get nothing to change or I can get the entire background to become a simple grey with no background image visible at all. Is this simply not possible?

Donegan answered 24/8, 2012 at 15:53 Comment(0)
A
24

I think you need to create an overlay element (potentially div) which has the sought translucent background. Something like:

.overlay {
    z-index: 1;
    height: 100%;
    width: 100%;
    position: fixed;
    overflow: auto;
    top: 0px;
    left: 0px;
    background: rgba(0, 0, 0, 0.7); /*can be anything, of course*/
}

And of course, a little demo: little link.

Abednego answered 24/8, 2012 at 16:32 Comment(9)
OK that was helpful thanks--however, though my background image is now successfully dimmed, now my content box/column in the centre can't be seen... Well, it's not so much a box/column as much as it is simply giving <body> a margin of 10% 30%. Now that content has vanished. I am not really experienced enough with web design to know why.Donegan
@Donegan You need to nest all your content within the overlay div -- treat it as if it's body. Edit: Oh, well, it's a bad idea to give body margins. Use another element and give it the same margins instead.Abednego
OK, all of my content is nested within the overlay div, and I've moved the margins to a special div just for them. Both of these divs are nested within body but outside anything else. Now I've got the overlay tint working perfectly, but my content has no margins...Donegan
@Donegan Can you please share a demo or a link to your site if it's live?Abednego
OK well I've just whacked the whole page into Jsfiddle: jsfiddle.net/TqNqT/15Donegan
@Donegan Are you trying to achieve this? (You can view source here: little link).Abednego
Yes, I'm trying to achieve that, but with the tint covering the whole page. In that demo (and I've tried using it on my computer too, same result) the tint only covers parts visible without scrolling.Donegan
@Donegan So sorry -- please update your CSS to match my edited answer. Basically just change the tinting div's position: absolute; to position: fixed; and add overflow: auto;. Working demo: little link (another link to view source). (If this is what you're trying to achieve, don't forget to tick this answer as "accepted" and upvote it so that the question is no longer open!)Abednego
Brilliant thanks! (Don't have enough reputation to be able to upvote but I ticked it)Donegan
S
142

Use background-blend-mode for a simple tint

You can use the background-blend-mode css property:

.box {
  width: 300px;
  height: 300px;
  background-size: cover;
  background-image: url('https://picsum.photos/300');
}

.background-tint {
  background-color: rgba(200,100,0,.5);
  background-blend-mode: multiply;
}
<div class="box background-tint"></div>

Place it on any element with a background image and you're good to go.

The property is well supported in modern browsers NOT including IE 11. For non supporting browsers you can use a polyfill.

Working demo


Other Options

Use filter for a complex tint

You can use the filter css property:

.box {
  width: 300px; height: 300px;
  background-size: cover;
  background-image: url('https://picsum.photos/300');
}

.background-tint {
  filter: sepia(100%) saturate(200%) brightness(70%) hue-rotate(330deg);
}
<div class="box background-tint"></div>

Place it on any element with a background image and you're good to go. In order to change the color change the hue-rotate value.

The property is well supported in modern browsers NOT including IE 11.

Working demo

Use a flat linear-gradient and a multiple background overlay

.background-tint {
  background-image: 
    linear-gradient( rgba(0,0,0,.5), rgba(0,0,0,.5) ),
    url('http://placehold.it/420')
}

I think this is the most widely used technique but it has the downside of being hardcoded i.e. you can't just take a class, stick it on an element and make a tint.

You could make this into a less or sass mixin, something like:

less

.background-tint(@tint-color, @image-url) {
  background-image: 
    linear-gradient( @tint-color, @tint-color ),
    url( @image-url )
}

sass

@mixin background-tint($tint_color, $image_url) {
  background-image: 
    linear-gradient( $tint_color, $tint_color ),
    url( $image_url )
}

Working demo

Use a transparent background

This method has the advantage of working on most browsers and is just a nice class you add to any element. The downside is that if you have anything else inside of that element you will have to wrap it in a div with some kind of positioning position: relative would work best.

Example:

.box {
  width: 300px; height: 300px;
  background-size: cover;
  background-image: url('https://picsum.photos/300');
  color: #facebc;
}

.background-tint { position: relative; }

.background-tint::after {
  content: "";
  position: absolute; 
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  /* Tint color */
  background-color: rgba(100,0,0,.5);
  margin: auto;
}

.u-relative { position: relative; z-index: 1; }
<div class="box background-tint">
    <div class="u-relative">300 x 300</div>
  </div>

Working Demo

Serif answered 3/2, 2016 at 12:40 Comment(5)
only one that worked that didn't sewer the colour of the font within the divCampinas
@Campinas What do you mean by "sewer"? I tested out all examples and the color of the font is what you set the color param to be.Serif
Note: if your looking for the most browser support use the linear-gradient. caniuse.com/#feat=css-gradientsGamp
very good solutions. unfortunately, this always create a complete fill. p.e. if i have a partially transparent background image, the overlay-color will also fill the tranparent areas of the background image. so the multiply does not fully behave like a tint.Corum
@Corum Thanks for pointing that out. I added another method using the filter property that should allow for covering only the non transparent areas. The downside is that it's not easy to choose the color of the tint.Serif
A
24

I think you need to create an overlay element (potentially div) which has the sought translucent background. Something like:

.overlay {
    z-index: 1;
    height: 100%;
    width: 100%;
    position: fixed;
    overflow: auto;
    top: 0px;
    left: 0px;
    background: rgba(0, 0, 0, 0.7); /*can be anything, of course*/
}

And of course, a little demo: little link.

Abednego answered 24/8, 2012 at 16:32 Comment(9)
OK that was helpful thanks--however, though my background image is now successfully dimmed, now my content box/column in the centre can't be seen... Well, it's not so much a box/column as much as it is simply giving <body> a margin of 10% 30%. Now that content has vanished. I am not really experienced enough with web design to know why.Donegan
@Donegan You need to nest all your content within the overlay div -- treat it as if it's body. Edit: Oh, well, it's a bad idea to give body margins. Use another element and give it the same margins instead.Abednego
OK, all of my content is nested within the overlay div, and I've moved the margins to a special div just for them. Both of these divs are nested within body but outside anything else. Now I've got the overlay tint working perfectly, but my content has no margins...Donegan
@Donegan Can you please share a demo or a link to your site if it's live?Abednego
OK well I've just whacked the whole page into Jsfiddle: jsfiddle.net/TqNqT/15Donegan
@Donegan Are you trying to achieve this? (You can view source here: little link).Abednego
Yes, I'm trying to achieve that, but with the tint covering the whole page. In that demo (and I've tried using it on my computer too, same result) the tint only covers parts visible without scrolling.Donegan
@Donegan So sorry -- please update your CSS to match my edited answer. Basically just change the tinting div's position: absolute; to position: fixed; and add overflow: auto;. Working demo: little link (another link to view source). (If this is what you're trying to achieve, don't forget to tick this answer as "accepted" and upvote it so that the question is no longer open!)Abednego
Brilliant thanks! (Don't have enough reputation to be able to upvote but I ticked it)Donegan
S
8

This worked great for me:

https://css-tricks.com/tinted-images-multiple-backgrounds/

.tinted-image {
  background: 
    /* top, transparent red, faked with gradient */ 
    linear-gradient(
      rgba(255, 0, 0, 0.45), 
      rgba(255, 0, 0, 0.45)
    ),
    /* bottom, image */
    url(image.jpg);
}

And building on another answer, you can do this with existing colors in less like:

linear-gradient(
  fade(@brand-primary, 50%),
  fade(@brand-primary, 50%)
),
Sisak answered 21/9, 2015 at 19:33 Comment(1)
This is supported on all major browsers including IE11 + edge, the second response using background-blend-mode isn't supported on IE or Edge" caniuse.com/#feat=css-gradientsGamp
N
1

It would be the overlay property https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingoverlay But it's a draft. Don't rely on it

Nope answered 24/8, 2012 at 16:19 Comment(0)
I
0

Try opacity:

opacity:0.4;
filter:alpha(opacity=40); /* For IE8 and earlier */
Imperforate answered 24/8, 2012 at 16:0 Comment(1)
No change. I really don't get it--rgba works fine for the main content box.Donegan
L
0

This is the simplest solution to the problem in my opinion.

.parent-div{
     background-color : desired-color
}
#image-id{
     opacity: dersired_value%
}

To increase readibity background-color: black and opacity percentages of range 50 to 60% seem to work nicely.

Levorotation answered 12/1, 2023 at 6:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.