4

I'm just learning the positioning in CSS. Based on the article that I've found useful, I'd started to playing around.

With the following code, I cannot understand why the absolute grey-box div is outside of it's relative parent. I expected that the grey-box will be on the top-left corner of the container.

.container {
  background: lightblue;
  position: relative;
}

.box-orange {
  background: orange;
  height: 100px;
  width: 100px;
  position: relative;
  top: 100px;
  left: 100px;
  z-index: 2;
}

.box-blue {
  background: lightskyblue;
  height: 100px;
  width: 100px;
  /*position: static;*/
}

.box-green {
  background: lightgreen;
  height: 100px;
  width: 100px;
  position: relative;
  top: -105px;
  left: 105px;
  z-index: 2;
}

.box-grey {
  background: grey;
  height: 100px;
  width: 100px;
  position: absolute;
}
<div class="container">
  <div class="box-orange"></div>
  <div class="box-blue"></div>
  <div class="box-green"></div>
  <div class="box-grey"></div>
</div>

Also can't understand in the following case why the grey-box not in the top-left corner, but moved after the empty space left by the orange-box there. I've just moved the grey-box to the second place inside the container div.

.container {
  background: lightblue;
  position: relative;
}

.box-orange {
  background: orange;
  height: 100px;
  width: 100px;
  position: relative;
  top: 100px;
  left: 100px;
  z-index: 2;
}

.box-blue {
  background: lightskyblue;
  height: 100px;
  width: 100px;
  /*position: static;*/
}

.box-green {
  background: lightgreen;
  height: 100px;
  width: 100px;
  position: relative;
  top: -105px;
  left: 105px;
  z-index: 2;
}

.box-grey {
  background: grey;
  height: 100px;
  width: 100px;
  position: absolute;
}
<div class="container">
  <div class="box-orange"></div>
  <div class="box-grey"></div>
  <div class="box-blue"></div>
  <div class="box-green"></div>
</div>

All the detailed documentation (e.g. MDN) and tutorials that I've found just demonstrating very simple examples with 2-3 boxes.

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
MontyX
  • 129
  • 1
  • 1
  • 10
  • 3
    you didn't set any top/left .. set top/left to control the position or it will be positionned based on its *static* place. Since you are still learning no need to get confused about that default position – Temani Afif Feb 19 '19 at 20:43

3 Answers3

1

You must always set top:0; left:0; on absolutely-positioned elements (or whatever values you want for top, right, bottom, left).

isherwood
  • 58,414
  • 16
  • 114
  • 157
Ted Fitzpatrick
  • 910
  • 1
  • 8
  • 18
  • 2
    *must always* --> it's not a must, it will simply be easier – Temani Afif Feb 19 '19 at 20:45
  • [From the MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/position#Syntax) >> _The element is removed from the normal document flow, and no space is created for the element in the page layout. It is positioned relative to its closest positioned ancestor, if any; otherwise, it is placed relative to the initial containing block. Its final position is determined by the values of top, right, bottom, and left._ This is what I cannot understand why I need to use the offsets – MontyX Feb 19 '19 at 22:07
1

To correctly understand this, you need to refer to the official specification where you find the equation the element must satisfy:

'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block

We don't have any border and padding so in your case it will simply be:

'top' + 'margin-top' + 'height' + 'margin-bottom' + 'bottom' = height of containing block

And if you read under you will find this:

  1. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to the static position, set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom'.

So in your case, you have set a height and kept top/bottom to auto thus top will be set to static position

..More precisely, the static position for 'top' is the distance from the top edge of the containing block to the top margin edge of a hypothetical box that would have been the first box of the element if its specified 'position' value had been 'static'..

To make it easy, it's the position of the element if you didn't set position:absolute.

Here is an easy illustration to better understand

.container {
  background: lightblue;
  position: relative;
  padding:40px 20px;
  display:inline-block;
  vertical-align:top;
  width: 250px;
}


.box-grey {
  background: grey;
  height: 100px;
  width: 100px;
  position: absolute;
}

.box-green {
  height:20px;
  background:green;
}
<div class="container">
  <div class="box-green"></div>
  <div class="box-grey" style="position:static;">I am static</div>
</div>

<div class="container">
  <div class="box-green"></div>
  <div class="box-grey">I am absolute</div>
</div>

Note the static position of the first element that is kept if we add position:absolute. We didn't specify any top value so the browser will use a default one that is the one of the position:static (default position) of the element.

If you don't want this, simply set the top value and you fall into this rule:

  1. 'bottom' is 'auto', 'top' and 'height' are not 'auto', then set 'auto' values for 'margin-top' and 'margin-bottom' to 0 and solve for 'bottom'

.container {
  background: lightblue;
  position: relative;
  padding:40px 20px;
  display:inline-block;
  vertical-align:top;
  width: 250px;
}


.box-grey {
  background: grey;
  height: 100px;
  width: 100px;
  position: absolute;
  top:0;
}

.box-green {
  height:20px;
  background:green;
}
<div class="container">
  <div class="box-green"></div>
  <div class="box-grey" style="position:static;">I am static</div>
</div>

<div class="container">
  <div class="box-green"></div>
  <div class="box-grey"></div>
</div>

Same logic apply to the left property


You may also notice the use of the word containing block which very important here and explained in the same specification

The position and size of an element's box(es) are sometimes calculated relative to a certain rectangle, called the containing block of the element. The containing block of an element is defined as follows:

...

  1. If the element has 'position: absolute', the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed', in the following way:

...

And it's not enough as there is other properties (listed below) that also establish a containing block so you can have an element positionned relatively to an ancestor that is not positionned!

Related: Why does applying a CSS-Filter on the parent break the child positioning?

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
-1

First of all, the element is positioned relative to its first positioned (not static) ancestor element.

In this case, the position absolute works with the sibling, not with the ancestor.

About the ancestors and siblings, there are a godd documentation about it : Ancestors and siblings

.container {
  background: lightblue;
  position: relative;
}

.box-orange {
  background: orange;
  height: 100px;
  width: 100px;
  position: relative;
  top: 100px;
  left: 100px;
  z-index: 2;
}

.box-blue {
  background: lightskyblue;
  height: 100px;
  width: 100px;
  /*position: static;*/
}

.box-green {
  background: lightgreen;
  height: 100px;
  width: 100px;
  position: relative;
  top: -105px;
  left: 105px;
  z-index: 2;
}

.box-grey {
  background: grey;
  height: 100px;
  width: 100px;
  position: absolute;
}
<div class="container">
  <div class="box-grey"></div>
  <div class="box-orange"></div>
  <div class="box-blue"></div>
  <div class="box-green"></div>
</div>

If i put the element after the div container all works without problem

Documentation of postion

About the second part, that box appears there because the box-gery doesnt matter about the top and right of box-green, got it? Ill put an example:

.container {
  background: lightblue;
  position: relative;
}

.box-orange2 {
  background: orange;
  height: 100px;
  width: 100px;
  position: relative;
  z-index: 2;
}

.box-orange {
  background: orange;
  height: 100px;
  width: 100px;
  position: relative;
  top: 100px;
  left: 100px;
  z-index: 2;
}

.box-blue {
  background: lightskyblue;
  height: 100px;
  width: 100px;
  /*position: static;*/
}

.box-green {
  background: lightgreen;
  height: 100px;
  width: 100px;
  position: relative;
  top: -105px;
  left: 105px;
  z-index: 2;
}

.box-grey {
  background: grey;
  height: 100px;
  width: 100px;
  position: absolute;
}

.box-yellow {
  background: yellow;
  height: 100px;
  width: 100px;
  position: absolute;
}
<div class="container">
  <div class="box-orange2"></div>
  <div class="box-grey"></div>
  <div class="box-orange"></div>
  <div class="box-yellow"></div>
</div>

You can see that the grey and yellow boxes do not change the behavior even if the top and right are in the sibling or not.

  • Thanks a lot Alejandro I'd like to ask you regarding the first part that, you mentioned, as it was written in every documentation: the element is positioned relative to its first positioned (not static) ancestor element this means for me the container is the first positioned ancestor in this case. Why the grey-box is not positioned to its? Why it isn't in the top left corner of the container? – MontyX Feb 19 '19 at 21:18
  • Hi, the ancestor of box-grey isn't container, it's box-green. box-green is postioned top: -105px; and left: 105px;, if you remove this propesrties you'll see that box-grey it's just under box-green. That's because the ancestor it's the element that is just before Regards – Alejandro Granados Feb 19 '19 at 21:35
  • so but what you are saying is wrong, box-green isn't an ancestor of box-grey, it's a sibling element. The ancestor is not the *before* element – Temani Afif Feb 19 '19 at 21:43
  • That's ture, srry. But, the propertie position works well with the siblings, so i supposed that the ancestor were in the top. – Alejandro Granados Feb 19 '19 at 21:50
  • Alejandro you are right. I don't know why, but you are right, because I thought that as Temani has written that the ancestor is the element which contains the current element. Not the sibling one. But I've tested it, and the sibling works like an ancestor in the current case. If you edit your answer to contain this information, I'm going to accept is as an answer. Please highlight the most important part, the first line of your answer – MontyX Feb 19 '19 at 21:51
  • 1
    @MontyX no! he's not right. It's false. like I told you, you have to set `top`/`left` properties to see the desired result (`top:0;left:0`) .. and the ancestor is not the previous element – Temani Afif Feb 19 '19 at 21:54
  • Of course, but, the information that the ancestor it's the item that contain the current item? I mean, that information: https://sebastian.expert/ancestor-descendant-sibling-parent-child-explained/ – Alejandro Granados Feb 19 '19 at 21:56
  • @AlejandroGranados yes an ancestor is at least on level up, not necessarely the first container, it can be the container of the container of the container – Temani Afif Feb 19 '19 at 21:58
  • @MontyX If I don't find a duplicate I will add a detailed answer to explain it – Temani Afif Feb 19 '19 at 21:59
  • Temani, you are right, but can you explain me please why it's not working without the top: 0;left: 0;? I'd like to understand it, because the documentation doesn't say anything about that the top/left/etc. properties are mandatory in case of absolute to reach the expected result. – MontyX Feb 19 '19 at 21:59
  • @MontyX here is the official doc : https://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-height .. not easy to tackle at the start, you may read it many times – Temani Afif Feb 19 '19 at 22:32
  • @TemaniAfif can you add this to your answer please? I'd like to approve it. – MontyX Feb 19 '19 at 22:47