Skip to content
Advertisement

jQuery offset(), position(), offsetTop and getBoundingClientRect() all returning wrong top values

I apologize if there is a simpler answer for this. I have been all over Stack Overflow and will probably get flamed for this question.

I am using a static site generator to dynamically generate API documentation. On one page I have a 2 column layout, and would like to align content from the right column with the left column. Because the generator dynamically generates content for each page, I need to avoid hardcoding in style values like top: 30px etc.

Currently jQuery’s offset(), position(), offsetTop and vanilla JS getBoundingClientRect() all return wrong values for the top position.

I’ve referenced jQuery documentation here, which states offset() excludes margins. In testing this however, I’ve found that even when margin’s are not declared, I still do not get the proper top values returned from offset(), or from position() or the vanilla JS getBoundingClientRect().

See the JS Fiddle below for a simple example of what I’m seeing. It’s clear I’m missing something obvious and despite reading through dozens of other offset() Stack posts, I still can’t seem to make heads or tails of it.

In my JsFiddle example, we have a simple 2-column setup. I’d like to position an h2 in the left column at the same height on the page as the h2 in the right column.

example JS from the fiddle to get top value of target element and assign to destination element:

let targetElement = document.getElementById('target-element');
let position = Math.round($(targetElement).position().top).toString() + 'px';
let destinationElement = document.getElementById('destination-element');

destinationElement.style.top = position;

If anyone has time to help me clear this up, I’d be extremely grateful

let targetElement = document.getElementById('target-element');
let position = Math.round($(targetElement).position().top).toString() + 'px';
let destinationElement = document.getElementById('destination-element');

destinationElement.style.top = position;
console.log(
  $(targetElement).offset().top,
  position,
  targetElement.offsetTop,
  targetElement.getBoundingClientRect().top
);
.flex-container {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: normal;
  align-items: normal;
  align-content: normal;
  margin: 0;
}

.flex-items:nth-child(1) {
  display: block;
  width: 50%;
  height: 100vh;
  background-color: tan;
  margin: 0;
}

.flex-items:nth-child(2) {
  display: block;
  background-color: grey;
  width: 50%;
  height: 100vh;
  margin: 0;
}

.has-margin {
  margin-bottom: 20px;
}

#destination-element {
  position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="flex-container">
  <div class="flex-items">
    <h2>First Column</h2>

    <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
    
    <h2 id="target-element">Target Element</h2>
  </div>

  <div class="flex-items">
    <h2>Second Column</h2>
    
    <p class="has-margin">Here's some more text It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>

    <h2 id="destination-element">Should align with target element</h2>
  </div>
</div>

Advertisement

Answer

Your code does what you want, but you should define position: absolute instead of relative for your #destination-element:

#destination-element {
  position: absolute;
}

Working example:

let targetElement = document.getElementById('target-element');
let position = Math.round($(targetElement).position().top).toString() + 'px';
let destinationElement = document.getElementById('destination-element');

destinationElement.style.top = position;
console.log(
  $(targetElement).offset().top,
  position,
  targetElement.offsetTop,
  targetElement.getBoundingClientRect().top
);
.flex-container {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: normal;
  align-items: normal;
  align-content: normal;
  margin: 0;
}

.flex-items:nth-child(1) {
  display: block;
  width: 50%;
  height: 100vh;
  background-color: tan;
  margin: 0;
}

.flex-items:nth-child(2) {
  display: block;
  background-color: grey;
  width: 50%;
  height: 100vh;
  margin: 0;
}

.has-margin {
  margin-bottom: 20px;
}

#destination-element {
  position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="flex-container">
  <div class="flex-items">
    <h2>First Column</h2>

    <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
    
    <h2 id="target-element">Target Element</h2>
  </div>

  <div class="flex-items">
    <h2>Second Column</h2>
    
    <p class="has-margin">Here's some more text It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>

    <h2 id="destination-element">Should align with target element</h2>
  </div>
</div>
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement