Search code examples
javascriptjquerymobilejquery-mobile

How do I get the new dimensions of an element *after* it resizes due to a screen orientation change?


I'm working on a mobile web app, and in my page I have a div element with its width set to 100%.

I need to set the height of this div so that the height is correct for a set aspect ratio. So for example, if the screen was sized to 300 pixels wide and the ratio was 3:2, my script should grab the width of the div (which at this point should be 300px) and set the height to 200px.

On first load, this works perfectly. However, if I rotate the screen of my phone to landscape, the width of the div obviously changes, so I need to reset its height in order to keep the correct ratio.

My problem is that I can't find an event which fires after the elements are resized. There is an orientationchange event built into jQuery Mobile, which helpfully fires when the screen is rotated from portrait to landscape and vice-versa:

$(window).bind('orientationchange', function (e) {

    // Correctly alerts 'landscape' or 'portrait' when orientation is changed
    alert(e.orientation); 

    // Set height of div
    var div = $('#div');
    var width = div.width();

    // Shows the *old* width, i.e the div's width before the rotation
    alert(width);

    // Set the height of the div (wrongly, because width is incorrect at this stage)
    div.css({ height: Math.ceil(width / ratio) });

});

But this event seems to fire before any of the elements in the page have resized to fit the new layout, which means (as mentioned in the comments) I can only get the pre-rotation width of the div, which is not what I need.

Does anyone know how I can get the div's new width, after things have resized themselves?


Solution

  • A few methods for you to try:

    (1) Set a timeout inside your orientationchange event handler so the DOM can update itself and the browser can draw all the changes before you poll for the new dimension:

    $(window).bind('orientationchange', function (e) { 
        setTimeout(function () {
            // Get height of div
            var div   = $('#div'),
                width = div.width();
    
            // Set the height of the div
            div.css({ height: Math.ceil(width / ratio) });
        }, 500);
    });
    

    It won't make too big of a difference but note that Math.ceil takes a lot longer to complete (relatively) than Math.floor since the latter only has to drop everything after the decimal point. I generally just pass the browser the un-touched float number and let it round where it wants to.

    (2) Use the window.resize event instead to see if that updated fast enough for you:

    $(window).bind('resize', function (e) { 
        // Get height of div
        var div   = $('#div'),
            width = div.width();
    
        // Set the height of the div
        div.css({ height: Math.ceil(width / ratio) });
    });
    

    On a mobile device this will fire when the orientation changes since the size of the browser view-port will also change.

    (3) If you are updating the size of this <div> element because it holds an image, just apply some CSS to the image to make it always be full-width and the correct aspect ratio:

    .my-image-class {
        width  : 100%;
        height : auto;
    }