Home > Software engineering >  How to set multiple elements style via getBoundingClientRect()
How to set multiple elements style via getBoundingClientRect()

Time:08-28

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 the each argument function, not el.
  • Changes to position are made by setting properties of rect, not style, as allowed in the standard, but this is uncommon.
  • Usually positions are set either in CSS, or using element style objects (the this.style lines commented out above), without calling getBoundingClientRect to obtain a DOMRect 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.

  • Related