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 >
<div >
<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 >
<h2>Second Column</h2>
<p >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>
CodePudding user response:
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 >
<div >
<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 >
<h2>Second Column</h2>
<p >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>