10

I want to position a div ".indicator" just where a li element starts, so for example, if I want to position the div in relation to the second li, I do:

indicator.style.left = li[1].getBoundingClientRect().left+"px";

This is my code:

var li = document.querySelectorAll(".ulcontainer > li");

var indicator = document.querySelector(".indicator");

indicator.style.left = li[1].getBoundingClientRect().left+"px";
html {
  box-sizing: border-box;
}
*, *:before, *:after {
  box-sizing: inherit;
}
.ulcontainer {
    white-space: nowrap;
    padding: 0;
    position: relative;
}
.ulcontainer li {
    list-style: none;
    display: inline-block;
    border: 1px solid;
    padding: 0 20px;
}

.indicator {
    background-color: red;
    display: inline-block;
    position: relative;
}
<ul class="ulcontainer">
    <li>OPTION 1</li><li>OPTION 2</li><li>OPTION 3</li>
</ul>
<div class="indicator">indicator</div>

The problem is that the div getBoundingClientRect().left is not returning the correct value for the li elements. If you run the example, you will see that ".indicator" is not starting in the beggining of the current li.

Why is not getBoundingClientRect().left returning the current value?

1
  • 1
    I think it may have something to do with your CSS style display: inline-block; and/or position: relative;. Try messing around with those and tell me if that did anything. Commented Jun 8, 2015 at 14:24

1 Answer 1

8

.indicator has relative positioning. So any offset will be relative to its default position, not relative to the browser window. (To contrast, fixed position is nearly always relative to the browser window, and absolute position is relative to the nearest-positioned ancestor – which is often the browser window.)

Since .indicator is a block-level element, and its immediate parent is the document body, its default left position is equal to the left margin of the document body.

Set body margin to 0, and it will line up:

var li = document.querySelectorAll(".ulcontainer > li");

var indicator = document.querySelector(".indicator");

indicator.style.left = li[1].getBoundingClientRect().left+"px";
body {
  margin: 0;
}
html {
  box-sizing: border-box;
}
*, *:before, *:after {
  box-sizing: inherit;
}
.ulcontainer {
    white-space: nowrap;
    padding: 0;
    position: relative;
}
.ulcontainer li {
    list-style: none;
    display: inline-block;
    border: 1px solid;
    padding: 0 20px;
}

.indicator {
    background-color: red;
    display: inline-block;
    position: relative;
}
<ul class="ulcontainer">
    <li>OPTION 1</li><li>OPTION 2</li><li>OPTION 3</li>
</ul>
<div class="indicator">indicator</div>

Sign up to request clarification or add additional context in comments.

2 Comments

Why some CSS elements has default margin?) It's hurt. There are also table elements contains default margin.
@noszone welcome to front end world! they have default values because not having visual values (likes spaces of margin or padding) will result with unusable UI. thats where the point of absolute technical mathematics meets visual graphics which forces us to apply very basic attributes to the "mathematics" and have a decent looking UI (same question apply to "why input have default border?" because otherwise it will be visibly ugly or impossible to see - same for margin/padding etc - they are there to tell the difference between those elements to other elements applied after them/before etc

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.