1

Consider this:

<div class="normal">
  <div class="abs1">
    ...
    <div class="abs2">
    </div>
  </div>
</div>

with this CSS

.abs1 {
  position: absolute;
}
.abs2 {
  position: absolute;
}

So, the position of the .abs2 div is relative to its .abs1 ancestor. What if I need it to be relative to the document, or to another ancestor higher up in the hierarchy? Is that possible? How?

matteo
  • 2,934
  • 7
  • 44
  • 59
  • 1
    I'm not sure I understand your question, in your comment below your code you say "So, the position of the .abs2 div is relative to its .abs1 ancestor. What if I need it to be relative to the document, or to another ancestor higher up in the hierarchy" how does that align with the question title? I'm just asking for clarity on what you're trying to do here. – Aaron Apr 14 '16 at 12:13
  • 1
    Basically...you can't. That's why absolute position should be used sparingly and only for specific effects. Sounds like it's being overused here. – Paulie_D Apr 14 '16 at 12:14
  • 2
    If you use `position:absolute` in ancestor then you cant. Basically the child div will be relative to the parent which has `position:relative` or `position:absolute` no matter the parent is immediate parent or not... – Gaurav Aggarwal Apr 14 '16 at 12:23
  • @Pauline_D "That's why absolute position should be used sparingly and only for specific effects" no, the fact that I can't doesn't mean that absolute position shoud be used sparingly, it only means that absolute positioning is designed poorly in the very specs. "sounds like it's being overused here" - my code snipped is obviously an oversimplified example. – matteo Apr 14 '16 at 16:02

3 Answers3

1

Great answer here:

Because position: absolute resets the relative position for children just as position: relative does.

There is no way around this - if you want the third div to be absolutely positioned relatively to the first one, you will have to make it a child of the first one.

Source: https://stackoverflow.com/a/5928069/5814976

Community
  • 1
  • 1
Sonny Prince
  • 1,094
  • 7
  • 15
  • Thanks. I hoped there was some way that I was missing, without having to modify the document logical structure for the sake of presentation. It's very sad that it can't be done. It reveals once more how narrow-minded the people who wrote the CSS specs are. As convulute as CSS is, it doesn't even allow do such basic stuff as this. – matteo Apr 14 '16 at 16:09
  • CSS does have its limitations, but you can work around most of them with JavaScript. – Jacob Apr 14 '16 at 16:30
1

You can sort of work around this limitation. If you know the absolutely positioned parent's computed position values you can use those combined with calc() to determine the child's required positioning values relative to the parent that would simulate it being positioned relative to the page. There are a lot of caveats with this solution, so it may not help you.

Scenario 1

We want to position the child using left as if it's positioned relative to the page. The parent is also positioned using left.

We can just subtract its left value from the desired page-relative left value to get the correct left value for the child.

var abs2 = document.querySelector('.abs2');

abs2.addEventListener('click',  displayPositionValues);

function displayPositionValues() {
  var top = abs2.getBoundingClientRect().top;
  var left = abs2.getBoundingClientRect().left;
  
  alert('I\'m ' + top + 'px from the top and ' + left + 'px from the left of the page')
}
html, body {
  margin: 0;
  padding: 0;
}

.normal {
  width: 100%;
  height: 200px;
  background-color: orange;
}

.abs1 {
  position: absolute;
  top: 40px;
  left: 20px;
  width: 150px;
  height: 150px;
  background-color: green;
}

/* we want this to be positioned 100px from the top and 180px from the left of the page */
.abs2 {
  position: absolute;
  top: calc(100px - 40px); /* top value = page relative top value - parent's top value */
  left: calc(180px - 20px); /* left value =  page relative left value - parent's left value */
  width: 100px;
  height: 100px;
  font-size: 12px;
  text-align: center;
  background-color: red;
  cursor: pointer;
}
<div class="normal">
  <div class="abs1">
    <div class="abs2">
      Click to display my position values
    </div>
  </div>
</div>

Scenario 2

We want to position the child using left as if it's positioned relative to the page. The parent is positioned using right.

If the page's width equals the viewport's width AND we know the parent's width, then we can determine the child's right value that corresponds to an equivalent left value using this formula:

right value = viewport width - desired left value - child's width - parent's right value

var abs2 = document.querySelector('.abs2');

abs2.addEventListener('click',  displayPositionValues);

function displayPositionValues() {
  var top = abs2.getBoundingClientRect().top;
  var left = abs2.getBoundingClientRect().left;
  
  alert('I\'m ' + top + 'px from the top and ' + left + 'px from the left of the page')
}
html, body {
  margin: 0;
  padding: 0;
}

.normal {
  width: 100%;
  height: 200px;
  background-color: orange;
}

.abs1 {
  position: absolute;
  top: 40px;
  right: 20px;
  width: 150px;
  height: 150px;
  background-color: green;
}

/* we want this to be positioned 100px from the top and 180px from the left of the page */
.abs2 {
  position: absolute;
  top: calc(100px - 40px); /* top value = page relative top value - parent's top value */
  right: calc(100vw - 180px - 100px - 20px); /* right value = viewport width - desired left value - child's width - parent's right value */
  width: 100px;
  height: 100px;
  font-size: 12px;
  text-align: center;
  background-color: red;
  cursor: pointer;
}
<div class="normal">
  <div class="abs1">
    <div class="abs2">
      Click to display my position values
    </div>
  </div>
</div>
Jacob
  • 2,212
  • 1
  • 12
  • 18
  • Of course it's easy to work around it in JavaScript. Even easier than calculating the position, you can just move the element from one ancestor to another. The question was whether it was possible with CSS only. – matteo Apr 14 '16 at 19:47
  • 1
    Well this is a CSS only "solution". It's not very practical, but it works! – Jacob Apr 15 '16 at 02:31
  • Whops sorry, I had had a quick look and seen javascript and I thought you were computing and assigning the position via js :S – matteo Apr 15 '16 at 22:55
-1

If you don't want the position to be relative to the parent, why is the element a child of that parent in the first place? Hierarchically, that makes no sense.

Simply place the second div after the first and give them both an absolute position.

Jon Story
  • 2,881
  • 2
  • 25
  • 41
  • 1
    *"If you don't want the position to be relative to the parent, why is the element a child of that parent in the first place?"* Source order or semantics? – Jacob Apr 14 '16 at 15:31
  • 1
    The hierarchy of the elements should be determined by semantics, not by the desired appearence. Actually, the impossibility to do what I ask demonstrate a great deficiency in the CSS specification. – matteo Apr 14 '16 at 16:00
  • 1
    If you don't want to display the items together though, are they really semantically linked? And if so, why are you presenting them separately? It may be that you have a specific use-case for this, but I'm struggling to visualise what that could be – Jon Story Apr 14 '16 at 16:16
  • *"It may be that you have a specific use-case for this, but I'm struggling to visualise what that could be"* I'm also interested in this. – Jacob Apr 14 '16 at 16:28
  • @JonStory "If you don't want to display the items together though, are they really semantically linked?" yes they can be, why not. "And if so, why are you presenting them separately?" for a number of reasons; "because I want to" should be enough. "It may be that you have a specific use-case for this" - yes, but the people who wrote the specs for CSS shouldn't need to have a use case for everything to see that a feature is needed, that's incredibly narrow-minded. I'll provide a use case in the next comment – matteo Apr 15 '16 at 23:02
  • The use case is the most obvious ever. Since formatting a comment is a pain in the ass, I'll post it here: http://jsbin.com/cupobi/edit?html,css,js,output - It's a menu with submenus. The menu is absolutely positioned just because. I may want to render a submenu as a popup when it's displayed, so it makes sense to want it positioned regardless of its parent menu (note that there may be more than one top-level menus), but it still belongs to it logically. – matteo Apr 15 '16 at 23:13