2

I'm trying to learn the basics of front-end web development and I'm struggling to understand why body::before behaves the way it does. I have the following CSS code:

body::before {
  content: "";
  position: fixed;
  width: 100%;
  height: 100%;
  background: linear-gradient(rgba(0, 0, 0, 0), rgba(255, 255, 0, 0.45)), url(https://cdn.pixabay.com/photo/2015/03/03/05/56/avenue-656969_960_720.jpg);
  background-repeat: no-repeat;
  background-size: cover;
  z-index: -1;
}

This way the background will appear moved to the bottom-left by some pixels (CodePen screenshot), and will only cover the entirety of the screen if top/bottom and left/right are set to 0. Why does the body::before position behave that way but normal body's position doesn't? Also, why doesn't the body::before even appear if the position is set to relative?

BaridunDuskhide
  • 107
  • 1
  • 5
  • 2
    See `::before` as a child element of body. In order for it to cover the full size of its parent, it needs to be taken out of the document flow: hence `position: relative` will not work. The top/bottom/left/right are needed to position the edges of the element. – Terry Jul 01 '21 at 14:12
  • 1
    Your `` still has the default `margin` styling. Remove it with `body {margin: 0;}`. Thats why you have the white border – jona Jul 01 '21 at 14:14

2 Answers2

1

The body element by default has margin of 8px on all sides which causes it to move slightly to bottom-right, so when you remove the margins of the body body { margin: 0; }, it fixes that.

Secondly, when you set position: relative; width: 100%; height: 100%, the element goes with the normal flow of the document and takes up 100% of width and height but you did not define the width and height of the body element. So the normal flow of ::before becomes the 100% of the parent which is 0 (i.e. not defined) and hence doesn't show up. Thus in order to use position: relative; on a child element, you need to atleast define the width and height of the parent element with absolute length units.

Hence, the following works

body{
  background: #000;
  width: 100vw;
  height: 100vh;
}

body::before {
  content: "";
  position: relative;

  /* 100% is a relative unit and requires its
  parent to have dimensions with absolute units */
  width: 100%;
  height: 100%;
  ...
}
ahmedazhar05
  • 580
  • 4
  • 7
1

In CSS, ::before creates a pseudo-element that is the first child of the selected element. It is often used to add cosmetic content to an element with the content property. It is inline by default.

  1. Since ::before pseudo element is first child of body. The background appears moved to the bottom-left by some pixels due to default margin of body element. Because that margin is added to offset of pseudo element which has position:fixed;.

An absolutely positioned element is an element whose computed position value is absolute or fixed. The top, right, bottom, and left properties specify offsets from the edges of the element's containing block. (The containing block is the ancestor relative to which the element is positioned.) If the element has margins, they are added to the offset. The element establishes a new block formatting context (BFC) for its contents.

  1. Pseudo element does not appear when we use position: relative;. Because in position relative element is positioned according to the normal flow of the document, also since ::before pseudo element is inline, it only takes space required by it and setting height and width don't work. Since there is no content it does not take any space, background image disappear. If you want it to cover its full height and width, use display : inline-block/block; or just remove it from normal flow of document by using position:fixed; which actually changes the display property to block.
Suryansh Singh
  • 1,123
  • 7
  • 15