/    Sign up×
Community /Pin to ProfileBookmark

DOM: offset* and relative units?

I’ve come across a rather nasty predicament. How do you determine value of offset* properties of an element in relative units? Because as far as I can tell, even in W3C DOM, the offset family will return a string in px.

MS has created a pos(Top, Left, Width, ect) family that will allow retrieval and arithmetic of dimensions in any unit, for as long as the unit remains consistant throughout the page. But what is the equivalent in DOM? Ironically enough DOM margin and padding will return a string in relative units.

It’s all fine and dandy that I can use getElementById to get Gecko’s attention, but if all my page’s units are in ’em’ it doesn’t help if I can’t use offsetWidth and offsetHeight.

Here’s an example:

[CODE]<script type=”text/javascript”>
var a = 1;
var b = 0.5;
var c = a + b;
alert(c);
</script>
[/CODE]

Will display 1.5. But everytime I try to add using units (em, ex, cm, inch, px, ect) I can’t add them. I can’t manipulate the variables at all, even though I had this working at W3Schools, it doesn’t anymore….

So I guess this is a bigger problem than just offset* ? .

How do we create layouts based on relative units if we can’t retrieve the elements dimensions?

to post a comment
JavaScript

15 Comments(s)

Copy linkTweet thisAlerts:
@TageMar 30.2004 — Forgive me if I don't quite understand what you are trying to do. It's 5:30am as well and I've been up since yesterday morning, lol. Now, you cannot add anything but integers in javascript. Adding strings together is different and irrelevant. I don't even know why I brought it up. Anyway, if you know what unit you want to [B]end[/B] up with you just have to manually convert the offset* pixel number into that unit. Like...

1em=16px

1ex=8px

1cm=38px

1in=96px

1mm=3.8px

1pt=1.33px

1pc=16px

So all your pages are in em, that's probably what you want to end up with. I've attached an example of what I'm talking about. You can reverse it to make px's into em's I guess. I hope this helps considering how dead-tired I am, lol. Later

[upl-file uuid=5d2f4168-cab5-4edd-b97f-cd91c738aa1b size=659B]emtopx-pxtoem.zip[/upl-file]
Copy linkTweet thisAlerts:
@David_HarrisonMar 30.2004 — [i]Originally posted by Tage [/i]

[B]1em=16px

1ex=8px

1cm=38px

1in=96px

1mm=3.8px

1pt=1.33px

1pc=16px[/B]
[/QUOTE]
These values won't always hold true. If they did then all units would be absolute units. em for example depends on the text size, which is specified by the user.
Copy linkTweet thisAlerts:
@tonyhauthorMar 30.2004 — [i]Originally posted by lavalamp [/i]

[B]These values won't always hold true. If they did then all units would be absolute units. em for example depends on the text size, which is specified by the user. [/B][/QUOTE]

Exactly.

Now I could just leave things in int or float, add use arithmetic as required and then +'em' at the end, but I may still get problems.

For example: I'm trying to determine the width and height on an implicitly position div within another div. The parent div has a width of 20em and height of 30em. I should be able to do *something* like this (please provide correct code if I'm wrong):

[CODE]el = document.getElementById(id);
elBorder = el.style.borderWidth + el.style.margin + el.style.padding;

childWidth = el.parentNode.offsetWidth - elBorder;
childHeight = el.parentNode.offsetHeight - elBorder;

alert(childWidth+" "+childHeight);
[/CODE]

But, if width, height, border-width, margin and padding are all in 'em' units, how is this calculated? I've tried something similar and all that is returned is undefined. And I believe it's because JS cannot convert relative units into pixels or vice versa.

And what if any of the measurements contain decimal places? Such as "margin: 0.5em; padding: 0.5em". We've already determined that JS will add two numbers together containing decimal places. But, I've also read that parseInt() will only read upto the decimal, and if the first letter is a 0, ie 09, it will return 0 rather than 9. There maybe better luck with parseFloat(), but what will it do with the units that are part of the string?
[code]<script type="text/javascript">
var a = parseFloat("0.50em");
var b = parseFloat("1.75em");
var c = a + b;
var a1 = "0.50em";
var b1 = "1.75em";
var c1 = eval(a1 + b1);</script>
<a href="#" onmouseover="alert('a='+a+' b='+b);"
onmouseout="alert('c='+c);">a + b= c</a><br />
<a href="#" onmouseover="alert('a1='+a1+' b1='+b1);"
onmouseout="alert('c1='+c1);">a + b= c</a>[/CODE]

The first link will return '2.25'. But I can't get the second link to return the same because eval() returns either a concatenated string or undefined.

So how do we apply parseFloat to offset* in order to return the relative unit rather than the pixel unit? Or can we use the non-offset* properties (Left, Top, ect) to retreive the same value? Again, please correct my code if I'm wrong:
[CODE]
<style type="css/text">
#parent {
width: 20em;
height: 30em;
overflow: auto;
}

#child {
position: absolute;
width: 20em;
margin: 0.5em;
padding: 0.5em;
border: 0.1em solid black;
}
</style>
<script type="javascript/text">
el = document.getElementById(child);
elBorder = parseFloat(el.style.borderWidth) +
parseFloat(el.style.margin) +
parseFloat(el.style.padding);

childWidth = parseFloat(el.parentNode.style.width) -
elBorder + 'em';
childHeight = parseFloat(el.parentNode.style.height) -
elBorder + 'em';

alert(childWidth+" "+childHeight);
</script>[/CODE]

Will this work? Are there better solutions?

How do we do the same in previous versions of IE or NN? Because IE reles on 'pixelLeft', 'pixelTop,' ect? And I'm not even sure what NN returns as units?
Copy linkTweet thisAlerts:
@TageMar 30.2004 — [CODE]var a1 = "0.50em";
var b1 = "1.75em";
var c1 = eval(a1 + b1);[/CODE]


That does not work because all eval() does (that I know of) is basically take strings and turn their values into code. eval(a1+b1) would look like this is normal code. 0.50em+1.75em and we already know it can't add anything but integers, I'll get back to you on the other parts in a sec.

EDIT: Maybe in a while, I have to go somewhere And I've never worked with nodes ever >.>
Copy linkTweet thisAlerts:
@David_HarrisonMar 30.2004 — Here's a script that contains a function that will add up numbers whether they are decimals and/or have em's at the end. You can use them just as you would a normal number except that you have to put the function code around them to convert them first.

For example, instead of this:

<i>
</i>
var a1 = "0.50em";
var b1 = "1.75em";
var c1 = eval(a1 + b1);

Just have this:

<i>
</i>
var a1 = "0.50em";
var b1 = "1.75em";
var c1 = num(a1) + num(b1);



[upl-file uuid=ebc4cdc9-1a2a-4af2-8c90-298f7e713ba7 size=675B]addition.txt[/upl-file]
Copy linkTweet thisAlerts:
@TageMar 31.2004 — Oh, is that what he wanted all along? = I was confused then. I may still be confused. Anyway, um, I dunno what. P= Later...
Copy linkTweet thisAlerts:
@tonyhauthorMar 31.2004 — Thanx lavalamp.

[i]Originally posted by Tage [/i]

[B]Oh, is that what he wanted all along?[/B][/QUOTE]

Well that will come in handy, but it's only part of the solution.

Let me try this again:

What is the work around to retrieve dimensions in relative units from properties and methods that only return pixel dimensions?

The following are examples that only return integer numbers in pixels:[list]
  • [*]height - screen/frame

  • [*]leftMargin - body

  • [*]offsetHeight

  • [*]offsetLeft

  • [*]offsetTop

  • [*]offsetWidth

  • [*]pixelBottom - IE

  • [*]pixelHeight - IE

  • [*]pixelLeft - IE

  • [*]pixelRight - IE

  • [*]pixelTop - IE

  • [*]pixelWidth - IE

  • [*]rightMargin - body

  • [*]screenLeft - window

  • [*]screenTop - window

  • [*]topMargin - body

  • [*]width - screen/object/frame

  • [/list]

    The following will return floating-point numbers in any unit:[list]
  • [*]border*

  • [*]bottom

  • [*]fontSize

  • [*]height

  • [*]left

  • [*]margin*

  • [*]padding*

  • [*]posBottom - IE

  • [*]posHeight - IE

  • [*]posLeft - IE

  • [*]posRight - IE

  • [*]posTop - IE

  • [*]posWidth - IE

  • [*]right

  • [*]top

  • [*]width

  • [/list]


    '*' = extened family(Bottom, Left, Top, ect.)



    To reiterate, how do we get the first list to behave like the second?



    And, which properties do not exist or behave incorrectly in earlier versions of IE and NN?
    Copy linkTweet thisAlerts:
    @TageMar 31.2004 — Lavalamp says em depends on the font-size specified by the user... Perhaps if you had a definite way of figuring out what the font-size they set it as, you might be able to make a math function to integrate them together and come out with the proper em's. What exactly do you and don't you have control over that the user gets to specify. Is the user able to specify only CSS, HTML, or JavaScript? Or all of them? Knowing what definite information you have control over might help to extract the em's. And I don't know anything about scripting for the earlier browsers, I'm sorry... =( Hope I can help you in one way or another. Later
    Copy linkTweet thisAlerts:
    @VladdyMar 31.2004 — From the first reply this whole discussion got on a wrong track (which again proves my point that little knowledge is more dangerous than complete ignorance ? ? ?)

    While there are methods defined in DOM CSS Level 2 that allow to convert between font and pixel units, IE does not support them, and that makes their use hardly practical.

    I find the following code to work fairly well in both IE and Gecko.
    <i>
    </i>/* get number of pixels in 1 EM for a given element */
    function getPxInEm(el)
    { //Create a temporary block element
    tdiv = el.appendChild(document.createElement('div'));
    with(tdiv.style)
    { margin = '0px'; //Set its margin to 0
    padding = '0px'; //Set its padding to 0
    border = 'none'; //Set its border to none;
    height = '1em'; //Set its height to 1 em
    width = '1em';
    }
    // Now the element's offsetHeight in pixels should represent 1EM
    pxInEM=tdiv.offsetHeight;
    // Delete the temporary block element
    el.removeChild(tdiv);
    // Return the value
    return pxInEM;
    }


    Now [b]for that element[/b] you can convert sizes between EMs and pixels
    Copy linkTweet thisAlerts:
    @tonyhauthorMar 31.2004 — [i]Originally posted by Vladdy [/i]

    [B]From the first reply this whole discussion got on a wrong track (which again proves my point that little knowledge is more dangerous than complete ignorance ? ? ?)[/B][/QUOTE]

    Is that an insult? I ask because I DO have little knowledge ? .

    [B]While there are methods defined in DOM CSS Level 2 that allow to convert between font and pixel units, IE does not support them, and that makes their use hardly practical.[/B][/QUOTE]
    Great, another one of MS's "we will only support the standards that we believe our users will need or demand" gone awry.

    [B]I find the following code to work fairly well in both IE and Gecko. [....] Now [I]for that element[/I] you can convert sizes between EMs and pixels [/B][/QUOTE]
    I'm not exactly sure how this works. I'm assuming (el) is an element retrieved by either 'getElementById' or 'document.all'. The tdiv (temporary div) is given the same height and width as the parent element? Or must it be it be 1 unit? How does giving the child element a dimension of 1emx1em allow us to retreive the offset* of the parent element's dimensions that may be 30emx20em? Can we return more than one value? Or do we have to write two seperate functions for offsetHeight and offsetWidth?

    [i]Originally posted by tonyh [/i]

    [B]And, which properties do not exist or behave incorrectly in earlier versions of IE and NN? [/B][/QUOTE]

    Apparently no one wants to answer this question. But, quite frankly I don't think it matters anymore because I don't believe that IE4 or NN4 support CSS2 anyways. So here's another, will Vladdy's work around work in IE5+ and NS6+?
    Copy linkTweet thisAlerts:
    @TageMar 31.2004 — maybe I'll just stay out of this one and let the experts handle it >.> javascript is just a hobby for me anyway, hope his script DOES work for you, later
    Copy linkTweet thisAlerts:
    @VladdyMar 31.2004 — Tony, I never have a problem with people asking questions. I do have a problem with people providing an answer without sufficient knowledge on the subject.

    My understanding of the question was how to convert between PX and font units EM when this ratio differs from element to element, browser to browser and user to user.

    The function I provided attempts to do just that. You provide an element as an argument. Within this element a temporary block is created with dimensions 1emx1em and then it's offsetHeight is read in pixels. The returned value is a number of pixels in 1em for the element.

    For example if you want to find this number for a document body you call the function:

    getPxInEm(document.body) ;

    or for any element:

    getPxInEm(document.getElementById('myElement'));

    So if you want to know the height of an element in EM you take it's offsetHeight which is in pixels and divide by value returned by the function

    It should work with NS6+ and IE5.5+ (maybe even IE5.0+)
    Copy linkTweet thisAlerts:
    @tonyhauthorMar 31.2004 — [i]Originally posted by Vladdy [/i]

    [B]Tony, I never have a problem with people asking questions. I do have a problem with people providing an answer without sufficient knowledge on the subject.[/B][/QUOTE]

    It's all good, I was kidding around like you were.

    [B]My understanding of the question was how to convert between PX and font units EM when this ratio differs from element to element, browser to browser and user to user.[/B][/QUOTE]
    Yes, that simplifies the problem quite a bit. I tend to complicate things.

    [B]For example if you want to find this number for a document body you call the function:

    getPxInEm(document.body) ;

    or for any element:

    getPxInEm(document.getElementById('myElement'));



    So if you want to know the height of an element in EM you take it's offsetHeight which is in pixels and divide by value returned by the function.[/B]
    [/QUOTE]

    Something like this then:
    [CODE]el = document.getElementById('myElement');
    parHeight = parseFloat(el.offsetHeight/getPxInEm(el));
    parWidth = parseFloat(el.offsetWidth/getPxInEm(el));

    /* Or set getPxInEm to a variable */

    elPxInEm = getPxInEm(el);
    parHeight = parseFloat(el.offsetHeight/elPxInEm);
    parWidth = parseFloat(el.offsetWidth/elPxInEm);
    [/CODE]

    Did I get this right? Is parseFloat even necessary? When actually doing arithmetic should we just use lavalamp's function or just use JS's arithmetic operators? For example, will "parHeight = el.offsetHeight/elPxInEm;" return in ems? Or must we concatenate the unit (ie. + 'em') ?

    [B]It should work with NS6+ and IE5.5+ (maybe even IE5.0+) [/B][/QUOTE]
    Cool ? .
    Copy linkTweet thisAlerts:
    @VladdyMar 31.2004 — No need for parseFloat.

    When you have an arithmetical operation on two numbers the result is a number.

    You only add units to a number when setting CSS properties (and it becomes a string when you do so). In your example the result of the division will be in EMs.
    Copy linkTweet thisAlerts:
    @tonyhauthorMar 31.2004 — Thanx again Vladdy,

    This is tres awesome ? .

    Of course if I have problems applying it to what I need I'll bring (bump) it up again....
    ×

    Success!

    Help @tonyh spread the word by sharing this article on Twitter...

    Tweet This
    Sign in
    Forgot password?
    Sign in with TwitchSign in with GithubCreate Account
    about: ({
    version: 0.1.9 BETA 5.18,
    whats_new: community page,
    up_next: more Davinci•003 tasks,
    coming_soon: events calendar,
    social: @webDeveloperHQ
    });

    legal: ({
    terms: of use,
    privacy: policy
    });
    changelog: (
    version: 0.1.9,
    notes: added community page

    version: 0.1.8,
    notes: added Davinci•003

    version: 0.1.7,
    notes: upvote answers to bounties

    version: 0.1.6,
    notes: article editor refresh
    )...
    recent_tips: (
    tipper: @AriseFacilitySolutions09,
    tipped: article
    amount: 1000 SATS,

    tipper: @Yussuf4331,
    tipped: article
    amount: 1000 SATS,

    tipper: @darkwebsites540,
    tipped: article
    amount: 10 SATS,
    )...