Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get actual width and height of a component

We're facing a fairly scary issue in JavaScript that none of us seems to be quite capable of resolving:

How do we get the width and height of a DOM element, including children, entire box model etc. without the component actually being displayed on the page?

Remember: I'm looking for suggestions. Even answers which don't answer the question fully (or don't quite fit with the specified parameters) might, and probably will, be helpful.

Main goal: I'm adding HTML elements into the page via Javascript - HTML elements with sizes and styles from a database. Problem is that they misbehave, usually bad aligment, one element is larger than another due to padding/margin whatever, and so I need to check their actual size to fix these issues.

The resulting application is going to be a, as BigMacAttack has described it in the comments, a 'tightly knit mosaic of 3rd-party HTML controls' would pretty much be spot-on. It needs to look a lot like full-fledged desktop application, and HTML seems to hate the idea with passion. Not that I blame it.

Anyway, here's some example code:

JavaScript:

function exampleElement(caption, content) {
    this.caption = caption;
    this.content = content;
    this.rootElement = document.createElement("div");
}

exampleElement.prototype.constructElement = function() {
    var otherElement = document.createElement("p");
    this.rootElement.className = "exampleElement";
    this.rootElement.textContent = this.caption; 
    otherElement.className = "exampleP";
    otherElement.textContent = this.content;
    this.rootElement.appendChild(otherElement);
    /*I need to know size of the otherElement here*/
    /*here goes code adding stuff into rootElement*/
};

window.onload = function() {
    var ex = new exampleElement("Hello", "Here's text");
    ex.constructElement();
    document.body.appendChild(ex.rootElement);
};

CSS:

.exampleElement {
    padding: 5px;
    margin: 6px;
}

.exampleElement .exampleP {
    padding: 20px;
    margin: 6px;
}

A fiddle

Now, we need our page to dynamically react to size of the window and to contents of individual components, that's why it's important to be able to get size of an object before even displaying it. It's also important that creation of an object is clearly separated into three phases:

  • creation via new

  • construction of DOM tree (constructElement)

  • addition into the document (either directly into body or into another DOM tree)

It's important that we know sizes of individual elements during the construction phase.

So far we've tried measuring it via jQuery, DOM width and height attributes, but none of that works with DOM object not being directly displayed on page. Another approach I have tried were several functions adding the object into document.body, getting width and height, and then immediately removing it - however, since our CSS files are very specific, this is unreliable unless you insert the entire rootElement, which will be a terrible performance and memory hog as our components get fairly complex.

I suppose an approach of dropping .CSS files completely and defining styles directly trough JS would solve at least part of our predicament, but there has to be a better way.

Starting bounty to get more ideas and suggestions. Just shoot people, even if answer is not entirely within the boundaries of the question (how would/did you do it etc.) - the goal I'm trying to achieve is for my JS generated HTML controls to properly fit together.

like image 476
Fenixp Avatar asked Sep 19 '13 09:09

Fenixp


People also ask

How do you find the height and width of an element?

Use offsetWidth & offsetHeight properties of the DOM element to get its the width and height.

How do I get the size of an element in HTML?

If you need to know the total amount of space an element occupies, including the width of the visible content, scrollbars (if any), padding, and border, you want to use the HTMLElement. offsetWidth and HTMLElement. offsetHeight properties. Most of the time these are the same as width and height of Element.


2 Answers

You run into this often if you need to initially hide components like accordions, sliders, and other things that require bounding box information to work properly.

A simple trick is to just add css that hides the visibility of the content in question and ensures that it doesn't flicker or cause interfere with your layout.

It can be something as simple as:

{   visibility:hidden;
    position:absolute;
    left: -9999px;
}

And then setting position back to static or relative and visibility back to visible when you're ready to show the component.

The fiddle is here, but there's not much to it: http://jsfiddle.net/gwwar/ZqQtz/1/

like image 59
Kerry Liu Avatar answered Sep 30 '22 12:09

Kerry Liu


Getting the rendered width and height of a box-model DOM node using javascript without actually adding it to the DOM to be displayed is not possible.

To prove this, let's walk through how the rendered height and width of a DOM node is calculated internally to the browser. I will reference how WebKit handles this since it is the most commonly used layout engine.

As the document is parsed and DOM nodes are added to the "DOM Tree", Renderers are created for the DOM nodes that need to be displayed. This is how the "Render Tree" gets built.

Here is an excerpt from an article entitled "WebCore Rendering I – The Basics" by Dave Hyatt on the official WebKit Blog:

"Renderers are created through a process on the DOM called attachment. As a document is parsed and DOM nodes are added, a method called attach gets called on the DOM nodes to create the renderers.

void attach()

The attach method computes style information for the DOM node. If the display CSS property for the element is set to none or if the node is a descendant of an element with display: none set, then no renderer will be created."

So, in order to be efficient, the browser does not even bother computing style information for elements with display set to none. As a result, the information is not available to be accessed via javascript. However, if the display property is not set to none, the following occurs:

"During attachment the DOM queries CSS to obtain style information for an element. The resultant information is stored in an object called a RenderStyle... The RenderStyle can be accessed from a RenderObject using the style() method... One of the principal workhorse subclasses of RenderObject is RenderBox. This subclass represents objects that obey the CSS box model. These include any objects that have borders, padding, margins, width and height."

So if your use case allows for you to retrieve the box-model rendering height and width via C/C++ directly from the browser and pass it to your javascript code via some other means, then you could query the height/width methods of the RenderBox subclass of each DOM element. This is basically how the WebKit Developer Tools gets this information.

like image 27
BigMacAttack Avatar answered Sep 30 '22 12:09

BigMacAttack