Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why getComputedStyle() is not getting actual width and height is there any callback or event exists

I'm in such a situation where i need to wait till the image gets loaded once the image gets loaded i need to gets its computed height so that i can set the yellow color selector accordingly.

Question: based on computed height of image i'm setting yellow color selector. it works with setTimeout() randomly but i don't want such approach.

let images = ['https://via.placeholder.com/150','https://via.placeholder.com/110/0000FF/808080%20?Text=Digital.com','https://via.placeholder.com/80/0000FF/808080%20?Text=Digital.com'];

let image = `<img src="${images[Math.floor(Math.random()*images.length)]}"/>`


document.getElementById('content').innerHTML = `<div class="box">${image}</div>`;

//actual code

let height = window.getComputedStyle(document.querySelector('.box'), null).getPropertyValue('height');

let imageWidth = window.getComputedStyle(document.querySelector('.box img'), null).getPropertyValue('width');

console.log('height',height,'width',imageWidth);

wrapImage = `<div style="width:calc(${imageWidth} + 10px);height:calc(${height} + 10px);position:absolute;left:0;top:0;border:1px solid yellow;"></div>`;

document.querySelector('.box').insertAdjacentHTML('beforeend',wrapImage);
.box{
   width:100%;
   height:auto;
   border:1px solid red;
   position:relative;
}
<div id="content">

</div>

with setTimeout it works but i don't want such approach,i want callback or some event once element is ready

let images = ['https://via.placeholder.com/150','https://via.placeholder.com/110/0000FF/808080%20?Text=Digital.com','https://via.placeholder.com/80/0000FF/808080%20?Text=Digital.com'];

let image = `<img src="${images[Math.floor(Math.random()*images.length)]}"/>`


document.getElementById('content').innerHTML = `<div class="box">${image}</div>`;

//actual code

setTimeout(() => {
   let height = window.getComputedStyle(document.querySelector('.box'), null).getPropertyValue('height');

let imageWidth = window.getComputedStyle(document.querySelector('.box img'), null).getPropertyValue('width');

console.log('height',height,'width',imageWidth);

wrapImage = `<div class="select" style="width:calc(${imageWidth} + 10px);height:${height};position:absolute;left:0;top:0;border:1px solid yellow;"></div>`;

document.querySelector('.box').insertAdjacentHTML('beforeend',wrapImage);

document.querySelector('.select').height = document.querySelector('.select').height + 10;

console.log('after computed height and added 10px',window.getComputedStyle(document.querySelector('.box'), null).getPropertyValue('height'));

},700);
.box{
   width:100%;
   height:auto;
   border:1px solid red;
   position:relative;
}
<div id="content">

</div>

Please help me thanks in advance !!!

like image 457
EaBengaluru Avatar asked Nov 19 '21 06:11

EaBengaluru


People also ask

What does the window getComputedStyle () method return?

The Window. getComputedStyle() method returns an object containing the values of all CSS properties of an element, after applying active stylesheets and resolving any basic computation those values may contain.

How do you find the height of an element?

In JavaScript, you can use the clientHeight property, which returns an element's height, including its vertical padding. Basically, it returns the actual space used by the displayed content. For example, the following code returns 120, which is equal to the original height plus the vertical padding.

How do you set a computed style?

To set or copy JavaScript computed style from one element to another, we can loop through each style and call the setProperty method to set the styles on the target element. to add a div and a section element. We define the copyNode function that takes the sourceNode and targetNode .

What are the values returned by getcomputedstyle?

The values returned by getComputedStyle are resolved values. These are usually the same as CSS 2.1’s computed values, but for some older properties like width, height, or padding, they are instead the same as used values.

What is getcomputedstyle in CSS?

Definition and Usage The getComputedStyle () method gets all the actual (computed) CSS property and values of the specified element. The computed style is the style actually used in displaying the element, after "stylings" from multiple sources have been applied.

What is getcomputedstyle API used for?

getComputedStyle is a rather specialized API that should only be necessary in special situations. For more on the issue of getComputedStyle and shorthand properties, see this question.

What is RGB getcomputedstyle actually doing?

For instance, it is probably actually doing the equivalent of rgb (255, 165, 0) none repeat scroll 0% 0% / auto padding-box border-box. getComputedStyle will not return the value of shorthand properties, except in Chrome as you've discovered.


Video Answer


5 Answers

The image hasn't finished loading when you retrieved the height and width. To solve this, you'll need to wait for the images to load first, then get their height and width.

Listen for the window load event, which will fire when all resources (including images) have loaded completely:

let images = ['https://via.placeholder.com/150', 'https://via.placeholder.com/110/0000FF/808080%20?Text=Digital.com', 'https://via.placeholder.com/80/0000FF/808080%20?Text=Digital.com'];

let image = `<img src="${images[Math.floor(Math.random()*images.length)]}"/>`


document.getElementById('content').innerHTML = `<div class="box">${image}</div>`;

//actual code

window.addEventListener('load', function() {
  let height = window.getComputedStyle(document.querySelector('.box'), null).getPropertyValue('height');

  let imageWidth = window.getComputedStyle(document.querySelector('.box img'), null).getPropertyValue('width');

  console.log('height', height, 'width', imageWidth);

  wrapImage = `<div class="select" style="width:calc(${imageWidth} + 10px);height:${height};position:absolute;left:0;top:0;border:1px solid yellow;"></div>`;

  document.querySelector('.box').insertAdjacentHTML('beforeend', wrapImage);

  document.querySelector('.select').height = document.querySelector('.select').height + 10;

  console.log('after computed height and added 10px', window.getComputedStyle(document.querySelector('.box'), null).getPropertyValue('height'));

});
.box {
  width: 100%;
  height: auto;
  border: 1px solid red;
  position: relative;
}
<div id="content">

</div>
like image 196
Spectric Avatar answered Oct 26 '22 02:10

Spectric


If you want more flexibility then you can use Resize Observer. With this when you change src attribute of image tag you'll able to change selection size.

const imageObserver = new ResizeObserver(function(entries) {
  for (let entry of entries) {
    var img = entry.target;
    let height = img.height + 10;
    let width = img.width + 10;

    console.log('Added 10px. height:', height, ' width:', width);

    wrapImage = `<div class="select" style="width:${width}px;height:${height}px;position:absolute;left:0;top:0;border:1px solid #f7d205;"></div>`;
    document.querySelector('.box').insertAdjacentHTML('beforeend', wrapImage);
  }
});

function init() {
  document.getElementById('content').innerHTML = `<div id="box" class="box"></div>`;

  var box = document.getElementById('box');
  var img = document.createElement("img");
  img.src = "https://via.placeholder.com/" + Math.floor(Math.random() * 50 + 80).toString() + "/0a0a0a/ffffff";
  box.appendChild(img);
  imageObserver.observe(img);
}
<!DOCTYPE html>
<html lang="en">
<style>
  #box {
    width: 100%;
    border: 1px dotted red;
    position: relative;
  }
</style>

<body onload="init()">
  <div id="content"></div>
</body>

</html>

Note: Using same ResizeObserver you can observe multiple images:

var images = document.getElementsByTagName('img');
for (var i = 0; i < images.length; i++) {
  imageObserver.observe(images[i]);
}

Edit: As requested, demonstrating observing img resize from parent div element. Here the image is wrapped in div #box. On resize img dispatches a custom event and parent handles it.

function handleChildResize(event) {
  console.log('parent: got it! handling it.. ')
  var img = event.data;
  let height = img.offsetHeight + 10;
  let width = img.offsetWidth + 10;

  console.log('Added 10px. height:', height, ' width:', width);

  wrapImage = `<div class="select" style="width:${width}px;height:${height}px;position:absolute;left:0;top:0;border:2px solid #f7d205;"></div>`;
  if (document.querySelector('.box > .select')) {
    document.querySelector('.box > .select').remove();
  }
  document.querySelector('.box').insertAdjacentHTML('beforeend', wrapImage);
  event.stopPropagation();
}

const imgObserver = new ResizeObserver(function(entries) {
  for (let entry of entries) {
    var img = entry.target;
    var event = new Event('childResized');
    event.data = img;
    console.log("img: i am resized. Raising an event.");
    img.dispatchEvent(event);
  }
});

function init() {
  var box = document.getElementById('box');
  box.addEventListener('load', (event) => {
    console.log('The page has fully loaded');
  });
  var img = document.createElement("img");
  img.src = "https://via.placeholder.com/" + Math.floor(Math.random() * 50 + 80).toString() + "/0a0a0a/ffffff";
  box.appendChild(img);
  imgObserver.observe(img);
  box.addEventListener('childResized', handleChildResize, true);
}
<!DOCTYPE html>
<html>
<head>
  <style>
    #box {
      width: 100%;
      padding: 10px;
      border: 1px solid red;
      position: relative;
    }
  </style>
</head>

<body onload="init()">
  <div id="content">
    <div id="box" class="box"></div>
  </div>
</body>

</html>
like image 29
the Hutt Avatar answered Oct 26 '22 04:10

the Hutt


You could consider adding the 'load' event listener as a callback for image loading. Please check the example:

const image = document.getElementById('image');
const handler = () => {
  alert(image.height);
};

image.addEventListener('load', handler);
<img src="https://image.shutterstock.com/z/stock-vector-sample-stamp-grunge-texture-vector-illustration-1389188336.jpg" id="image" />
like image 44
aleks korovin Avatar answered Oct 26 '22 04:10

aleks korovin


I see that you want to compute the final value of the get computed style you see. The thing is that the getComputedStyle doesn't get updated. So just make a function to do it!

let images = ['https://via.placeholder.com/150','https://via.placeholder.com/110/0000FF/808080%20?Text=Digital.com','https://via.placeholder.com/80/0000FF/808080%20?Text=Digital.com'];'

let image = `<img src="${images[Math.floor(Math.random()*images.length)]}"/>`


document.getElementById('content').innerHTML = `<div class="box">${image}</div>`;

//actual code

setTimeout(() => {
   let height;
   let imageWidth;
   function calculateHeightAndWidth() {
        
height = window.getComputedStyle(document.querySelector('.box'), null).getPropertyValue('height');

imageWidth = window.getComputedStyle(document.querySelector('.box img'), null).getPropertyValue('width');

   }
   calculateHeightAndWidth()


console.log('height',height,'width',imageWidth);

wrapImage = `<div class="select" style="width:calc(${imageWidth} + 10px);height:${height};position:absolute;left:0;top:0;border:1px solid yellow;"></div>`;

document.querySelector('.box').insertAdjacentHTML('beforeend',wrapImage);

document.querySelector('.select').height = document.querySelector('.select').height + 10;

calculateHeightAndWidth()
console.log('after computed height and added 10px',window.getComputedStyle(document.querySelector('.box'), null).getPropertyValue('height'));

},700);
.box{
   width:100%;
   height:auto;
   border:1px solid red;
   position:relative;
}
<div id="content">

</div>
like image 39
haider Avatar answered Oct 26 '22 02:10

haider


I see that you are creating your imgNode on a fly using ternary which means you do not have it pre-created in your HTML. So for that, you can use the solution as below by creating an Image constructor.

const images = [
  "https://via.placeholder.com/150",
  "https://via.placeholder.com/110/0000FF/808080%20?Text=Digital.com",
  "https://via.placeholder.com/80/0000FF/808080%20?Text=Digital.com"
];

const img = new Image();

img.addEventListener("load", (ev) => {
  console.log(ev);

  document.getElementById(
    "content"
  ).innerHTML = `<div class="box">${ev.target}</div>`;

  const height = window
    .getComputedStyle(document.querySelector(".box"), null)
    .getPropertyValue("height");

  const imageWidth = window
    .getComputedStyle(document.querySelector(".box img"), null)
    .getPropertyValue("width");

  console.log("height", height, "width", imageWidth);

  const wrapImage = `<div style="width:calc(${imageWidth} + 10px);height:calc(${height} + 10px);position:absolute;left:0;top:0;border:1px solid yellow;"></div>`;

  document.querySelector(".box").insertAdjacentHTML("beforeend", wrapImage);
});

img.src = `${images[Math.floor(Math.random() * images.length)]}`;
like image 40
Emmanuel Onah Avatar answered Oct 26 '22 04:10

Emmanuel Onah