0

I'm trying to learn HTML and CSS. Yesterday night, when I was trying new things I came across a problem. I added a background image and wanted to make it black and white. It shows the image but its in colors. It didn't work however I tried. I'm out of answer at the moment. Thanks in advance.

body {
  background-image: url(https://cdn.pixabay.com/photo/2020/04/03/15/27/flower-meadow-4999277_1280.jpg);
  background-size: cover;
  filter: grayscale(100%);
}

#logo {
  font-family: 'Aladin', cursive;
  font-size: 50px;
  color: white;
  margin-top: 40px;
  margin-left: 75px;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Testing 1-2-3</title>
    <link rel="stylesheet" href="css/master.css">
    <link href="https://fonts.googleapis.com/css?family=Aladin&display=swap" rel="stylesheet">
  </head>
  <body>
    <div id="logo">
      VolviX
    </div>
  </body>
</html>
VolviX
  • 35
  • 5
  • 1
    I've fixed your snippet with simongcc's picture. Next time please check that your snippet actually works. – Álvaro González Apr 18 '20 at 15:13
  • 1
    @ÁlvaroGonzález I have updated the answer. I think it the question does not exactly duplicated since what the user would like to know is not explained in other posts. I have added those explanation to the answer. If the title change a bit like "what is different ways to create grayscale effect and the principal behind" would make it more unique question. – 西門 正 Code Guy Apr 19 '20 at 04:29

1 Answers1

2

It is because css greyscale() is for filtering image loaded with <img>. Updated as follow, it does WORK for CSS background except HTML and Body tag. So I try to wrap up all the situations here AFAIK.

Situation 1 - background image + blend

For background image, you need to apply other tricks like background-blend-mode property. You may refer some example online such as this

body {
      background-image: linear-gradient(black, black), url(../img/ejager.jpg);
      background-size: cover;
      background-blend-mode: saturation;
}

Since your image is relative, so I use free online image as example.

body {
       /* free image from https://pixabay.com/photos/flower-meadow-daisy-nature-flowers-4999277/ */
        background-image:  url(https://cdn.pixabay.com/photo/2020/04/03/15/27/flower-meadow-4999277_1280.jpg), linear-gradient(black, black);
        background-size: cover;
        background-blend-mode: saturation;
}

The principal behind this method:

The background-blend-mode CSS property sets how an element's background images should blend with each other and with the element's background color.

background-image property support multiple background images since quite a long time.

The above example could be replaced with a normal black background image. For convenient sake, the example use this to create a black background.

The linear-gradient() CSS function creates an image consisting of a progressive transition between two or more colors along a straight line. Its result is an object of the data type, which is a special kind of .

As a result, it could be seen as a black background image with another image together and then use the blend filter to blend their saturation together. According to the blend definition.

Creates a color with the saturation of the source color and the hue and luminosity of the backdrop color. Painting with this mode in an area of the backdrop that is a pure gray (no saturation) produces no change.

In this case, the saturation of the source color is the saturation of black and the hue and luminosity of the backdrop color (the flower image)

It then preserves the flower image but with black and white effect.

Situation 2 - filter a image tag

Here is example of greyscale for image tag

img {
     filter: grayscale(1);
}
<img src="https://cdn.pixabay.com/photo/2020/04/03/15/27/flower-meadow-4999277_1280.jpg" alt="">

Edited: After a thorough test with different filters. There is a few characteristic found as follow.

Situation 3 - Apply filter to html and body tag.

Filter is not working for background-image in HTML or Body tag. However, it works if you setup the background image in a psuedo element.

  • html, Safari works, FF, Chrome doesn't
  • body, Safari, FF, Chrome doesn't
  • html::before - before all content inside html
  • html::after - theoretically, it works but it should be out of the boundary, although ::after exists in DOM, nothing is displayed.
  • body::before - before all content of body
  • body::after - after all content of body

So, as a cross browser solution, to apply filter to body, body::before is sensible according to support of pseudo element across different browsers.

body::before {
  /* positioning */
  content: ' ';
  height: 100%;
  width: 100%;
  position: fixed;
  left: 0;
  right: 0;
  z-index: -1;
  
  background-image: url(https://cdn.pixabay.com/photo/2020/04/03/15/27/flower-meadow-4999277_1280.jpg);
  background-size: cover;
  background-repeat: no-repeat;
  filter: grayscale(1);
}
Related posts: about not working in body tag, it may be a bug because it behave inconsistently across different browsers.

Situation 4 - Apply filter to elements other than html and body

It works without issues.

#content {
    background-image: url(https://cdn.pixabay.com/photo/2020/04/03/15/27/flower-meadow-4999277_1280.jpg);
    background-size: cover;
    background-repeat: no-repeat;
    
    filter: grayscale(1);
}

body, html, #content {
  height: 100%;
}
<div id="content"></div>
Appendix

CSS Filter Functions How to apply post 1 Apply to partial element post 1