I am trying to set elements (children of a container with transform
) to fixed position relative to the viewport. I'm attempting to find each of them, and assign to a variable via getBoundingClientRect()
, then define style properties from that variable.
<div>
<div >
<div>
<!-- Image -->
</div>
</div>
</div>
<div>
<div >
<div>
<!-- Image -->
</div>
</div>
</div>
<!-- more -->
JS v1
$('.preview-container').each(function(el) {
preview = this.getBoundingClientRect();
console.log(preview);
preview.style.position = "fixed";
preview.style.top = "0";
preview.style.left = "0";
});
This works without the three style
lines and console
displays all of the .preview-container
elements correctly. Adding the style
lines produces errors about those style
properties not being defined:
jQuery.Deferred exception: Cannot set properties of undefined (setting 'position')
Uncaught TypeError: Cannot set properties of undefined (setting 'position')
I don't understand that because preview
is working in console
.
JS v2
This attempt works as is, but is less complete. console
is producing all of the .preview-container
elements, but I haven't been able to incorporate getBoundingClientRect()
:
document.querySelectorAll(".preview-container").forEach(preview => {
preview.style.position = "fixed";
preview.style.top = "0";
preview.style.left = "0";
console.log(preview);
});
I feel like I am closer with JS v1, and am missing something simple with the style
properties. How should I proceed?
CodePudding user response:
You have a problem with the name of your variables, in the first one you call it el and you refer as preview. And to get the values of getBoundingClientRect you need to create another variable.
document.querySelectorAll(".preview-container").forEach(preview => {
previewValues = preview.getBoundingClientRect();
preview.style.position = "fixed";
preview.style.top = "0";
preview.style.left = "0";
console.log(preview);
console.log(previewValues);}
)
<div>
<div >
<div>
<!-- Image -->
</div>
</div>
</div>
<div>
<div >
<div>
<!-- Image -->
</div>
</div>
</div>
<!-- more -->
CodePudding user response:
Looking at the interfaces for DOMRect (there are several), it states that updating properties of a DOMRect
updates the position of the element it was called on, as in this example:
"use strict";
$('.preview-container').each(function(el) {
var rect = this.getBoundingClientRect();
this.style.position = "fixed";
// this.style.top = "0";
rect.x = 0;
// this.style.left = "0";
rect.y = 0;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- body-html -->
<div>
<div >
<div>
Image 1
</div>
</div>
</div>
<div>
<div >
<div>
Image 2
</div>
</div>
</div>
Note
this
has been used to refer to preview divisions in theeach
argument function, notel
.- Changes to position are made by setting properties of
rect
, notstyle
, as allowed in the standard, but this is uncommon. - Usually positions are set either in CSS, or using element
style
objects (thethis.style
lines commented out above), without callinggetBoundingClientRect
to obtain aDOMRect
first.
However when an element descends from an element with a transform
property, the transform
element behaves as the containing block for fixed
elements below as shown here:
$('.preview-container').each(function(el) {
this.style.position = "fixed";
this.style.top = "0";
this.style.left = "0";
});
/* CSS from https://developer.mozilla.org/en-US/docs/Web/CSS/transform */
div.ancestor {
border: solid red;
transform: translate(30px, 20px) rotate(20deg);
width: 140px;
height: 60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- body-html -->
<div >
<div >
<div>
Image 1
</div>
</div>
</div>
<div >
<div >
<div>
Image 2
</div>
</div>
</div>
If you want to fix preview container positioning relative to the view port, try moving them out from under the transform
ancestor by, say, appending them to the body
element. If aspects of the transform operation need to be retained on moved preview containers, a suitable CSS transform would need to be separately applied to them after the move.