Why does body::before code work and not body?

Why does body::before code work and not body?
0

So first off, I am looking at the basic HTML CSS projects, the survey page project.

If you look at the CSS code on that example, you’ll see it has a body::before declared, I understand a bit about how ::before works, it applies code before something. But I understand it more clearly with

or examples like that.

p::before{
 content:"HEY LOOK ";
}
<p>Hi there</p>

Would look like this: HEY LOOK Hi there

But on that example, I don’t understand how body::before works in this example.

body::before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  z-index: -1;
  background: var(--color-darkblue);
  background-image: linear-gradient(
      115deg,
      rgba(58, 58, 158, 0.8),
      rgba(136, 136, 206, 0.7)
    ),
    url(https://raw.githubusercontent.com/lasjorg/fcc-form-example-image/master/67103817-7c51e200-f18b-11e9-975f-f74561336a9a-lj.jpg);
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}

This code for the most part makes sense, but my question is, why doesn’t it work in just a body tag? Why must ::before be included for this to work?

If you don’t include the ::before, and you just put everything in body{}, it will show everything normally, even the background, but the RGBA color part will not display, actually it will display but it will be UNDER the background, why is this? Can someone explain why it appears this way?

I mean, why can’t I put it this way???

body{
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  z-index: -1;
  background: var(--color-darkblue);
  background-image: linear-gradient(
      115deg,
      rgba(58, 58, 158, 0.8),
      rgba(136, 136, 206, 0.7)
    ),
    url(https://raw.githubusercontent.com/lasjorg/fcc-form-example-image/master/67103817-7c51e200-f18b-11e9-975f-f74561336a9a-lj.jpg);
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}

WITHOUT A BEFORE TAG, that is my question, clearly you can see it doesn’t work, you wont see the gradient background color ontop the image, why is this? I want to understand why this happens and why you need body::before to make this work.

There is no easy way to explain, but the story goes this way :slight_smile:

First of all, background-image: property can take multiple values and here you indeed have two images: gradient and image from url.

Then, background-size will tell browser, what size these images should take. If you enter just one value here browser will presume you want to apply this size to all of images.

background-size: cover; has logic such as “make sure image covers container without changing its aspect ratio and regardless of container’s aspect ratio”. This is awesome logic and we all love it! Basically it’s 100% 100% without skewing.

And here we have a problem, because 100% is a relative unit that means 100% of something, right? You can tell “It’s 100% of body, you fool!”… and you kinda right, except for the moment when body is so called out-of-flow element (with position fixed or absolute). Because in that way this statement:

 body {
  height: 100%;
  width: 100%;
}

… would also mean “100% relative to a parent”.

OK! So the parent of body is html. It’s a normal block citizen and as all block elements he obeys following rule: “If block element has no (in-flow) children if takes 100% width and 0 height by default”.

You probably have guessed now, what width and height body inherits from parent and later background image inherits from body? :wink:
How do fix it?

// Hint, try:
html {
  height: 100%;
}

So that was the story!

Why it works with body::before? Because body::before is a pseudo child of body, which in this case in-flow element that naturally has height that is inherited by pseudo child body::before.

Hope this will clear things a bit!

I kinda understand a bit more now. The bit with html not having height makes sense, I didn’t know what html default size values were, now I know.
So is body::before inheriting size values from body? or is body inheriting size values from body::before?

With pseudo elements it’s a bit counter intuitive because they positioned either before or after element, but nevertheless they are children of the element, so body::before is a child of body, and as in real world any inheritance always go one direction from parent to a child.