Oztaco
Oztaco

Reputation: 3459

Onresize for div elements?

Visual Studio highlighted my onresize attribute of my div tag, and says that it isn't a valid attribute for HTML5. Is this true? What should I use instead? It seems kind of silly that this would be the case.

Upvotes: 39

Views: 74498

Answers (8)

Wojciech Stańczewski
Wojciech Stańczewski

Reputation: 833

You can use ResizeObserver. Here is PoC I've created:

<!DOCTYPE html>
<html>
<body>

<div id="my-test-div" style="height:100px;background-color:red;max-width:800px;border:5px solid black"></div>

<script>
    // https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
    // https://drafts.csswg.org/resize-observer-1/

    const resizeObserver = new ResizeObserver((entries) => {
        for (const entry of entries) {
          console.log(entry.target.id + " size changed");
        }
    });

    const myDiv = document.getElementById("my-test-div");
    resizeObserver.observe(myDiv);
    // resizeObserver.unobserve(myDiv);
</script>

</body>
</html>

Upvotes: 0

nhaggen
nhaggen

Reputation: 443

Based on Paul H.'s answer, I created a very similar solution that is easier to understand (at least for me).

The advantage of this modified solution, is that the code is more readable, especially if you want to perform some lines of code within the EventListener.

The advantage of the original solution, is of course that it is a one-liner.

let myDiv = document.getElementById("myDiv");
    myDiv.addEventListener("mousemove", () => {
        if ((myDiv.w && myDiv.w !== myDiv.offsetWidth) || (myDiv.h && myDiv.h !== myDiv.offsetHeight)) {
            // Put your payload-code within this IF-Statement. e.g.
            myDiv.innerText = "New dimensions are W: " + myDiv.w + "  , H: " + myDiv.h;
        }
        myDiv.w = myDiv.offsetWidth;
        myDiv.h = myDiv.offsetHeight;
    });

Upvotes: 1

Paul
Paul

Reputation: 467

A pure and simple JavaScript implementation.

.resizable {
  resize: both;
  overflow: auto;
  width: 200px;
  border: 1px solid black;
  padding: 20px;
  margin-bottom: 120px;
}
<div class='resizable' onresize="this.innerText = this.w + ',' + this.h" onmousemove="if ((this.w && this.w !== this.offsetWidth) || (this.h && this.h !== this.offsetHeight)) { eval(this.getAttribute('onresize')) } this.w = this.offsetWidth; this.h = this.offsetHeight;">
test
</div>



Upvotes: 6

Nate Scarlet
Nate Scarlet

Reputation: 601

We now have ResizeObserver, browser support is 89.6% today (2021-01-21).

And there is polyfill for old browsers, like juggle/resize-observer

Upvotes: 8

Martin Wantke
Martin Wantke

Reputation: 4571

Currently all major browser doesn't support a resize event for html-element's, just for the window object.

What you can to is to intercept the user interaction to build your own listener, like this:

function detectResize(_element)
{
    let promise = {};
    let _listener = [];

    promise.addResizeListener = function(listener)
    {
        if(typeof(listener) != "function") { return; }
        if(_listener.includes(listener)) { return; };

        _listener.push(listener);
    };

    promise.removeResizeListener = function(listener)
    {
        let index = _listener.indexOf(listener);
        if(index >= 0) { _listener.splice(index, 1); }
    };

    let _size = { width: _element.clientWidth, height: _element.clientHeight };

    function checkDimensionChanged()
    {
        let _currentSize = { width: _element.clientWidth, height: _element.clientHeight };
        if(_currentSize.width != _size.width || _currentSize.height != _size.height)
        {
            let previousSize = _size;
            _size = _currentSize;

            let diff = { width: _size.width - previousSize.width, height: _size.height - previousSize.height };

            fire({ width: _size.width, height: _size.height, previousWidth: previousSize.width, previousHeight: previousSize.height, _element: _element, diff: diff });
        }

        _size = _currentSize;
    }

    function fire(info)
    {
        if(!_element.parentNode) { return; }
        _listener.forEach(listener => { listener(info); });
    }


    let mouseDownListener = event =>
    {

        let mouseUpListener = event => 
        {
            window.removeEventListener("mouseup", mouseUpListener);
            window.removeEventListener("mousemove", mouseMoveListener);
        };

        let mouseMoveListener = event =>
        {
            checkDimensionChanged();
        };

        window.addEventListener("mouseup", mouseUpListener);
        window.addEventListener("mousemove", mouseMoveListener);
    };

    _element.addEventListener("mousedown", mouseDownListener);

    window.addEventListener("resize", event =>
    {
        checkDimensionChanged();
    });

    return promise;
}

How to use it:

document.addEventListener("DOMContentLoaded", event =>
{
    let textarea = document.querySelector("textarea");
    let detector = detectResize(textarea);

    let listener = info => { console.log("new width: ", info.width, "  new height: ", info.height); };
    detector.addResizeListener(listener);
});

html:

<textarea></textarea>

css:

html, body
{
    height: 100%;
    box-sizing: border-box;
    overflow: hidden;
    margin: 0px;
}

textarea
{
    resize: both;

    width: 96px;
    height: 112px;

    width: 100%;
    height: 100%;

    border: 1px solid black;
}

Upvotes: 2

csuwldcat
csuwldcat

Reputation: 8249

Add the following CSS and JavaScript to your page, and use the addResizeListener and removeResizeListener methods to listen for element size changes (blog post for further details: http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/):

Resize Sensor CSS

.resize-triggers {
    visibility: hidden;
}

.resize-triggers, .resize-triggers > div, .contract-trigger:before {
  content: " ";
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  overflow: hidden;
}

.resize-triggers > div {
  background: #eee;
  overflow: auto;
}

.contract-trigger:before {
  width: 200%;
  height: 200%;
}

Resize Event Methods

The following is the JavaScript you’ll need to enable resize event listening. The first two functions are prerequisites that are used in the main addResizeListener and removeResizeListener methods.

(function(){

var attachEvent = document.attachEvent;

if (!attachEvent) {
    var requestFrame = (function(){
      var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
                function(fn){ return window.setTimeout(fn, 20); };
      return function(fn){ return raf(fn); };
    })();

    var cancelFrame = (function(){
      var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
                   window.clearTimeout;
      return function(id){ return cancel(id); };
    })();

    function resetTriggers(element){
        var triggers = element.__resizeTriggers__,
            expand = triggers.firstElementChild,
            contract = triggers.lastElementChild,
            expandChild = expand.firstElementChild;
        contract.scrollLeft = contract.scrollWidth;
        contract.scrollTop = contract.scrollHeight;
        expandChild.style.width = expand.offsetWidth + 1 + 'px';
        expandChild.style.height = expand.offsetHeight + 1 + 'px';
        expand.scrollLeft = expand.scrollWidth;
        expand.scrollTop = expand.scrollHeight;
    };

    function checkTriggers(element){
      return element.offsetWidth != element.__resizeLast__.width ||
             element.offsetHeight != element.__resizeLast__.height;
    }

    function scrollListener(e){
        var element = this;
        resetTriggers(this);
        if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
        this.__resizeRAF__ = requestFrame(function(){
            if (checkTriggers(element)) {
                element.__resizeLast__.width = element.offsetWidth;
                element.__resizeLast__.height = element.offsetHeight;
                element.__resizeListeners__.forEach(function(fn){
                    fn.call(element, e);
                });
            }
        });
    };
}

window.addResizeListener = function(element, fn){
    if (attachEvent) element.attachEvent('resize', fn);
    else {
        if (!element.__resizeTriggers__) {
            if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
            element.__resizeLast__ = {};
            element.__resizeListeners__ = [];
            (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
            element.__resizeTriggers__.innerHTML = '<div class="expand-trigger"><div></div></div>' +
                                                   '<div class="contract-trigger"></div>';
            element.appendChild(element.__resizeTriggers__);
            resetTriggers(element);
            element.addEventListener('scroll', scrollListener, true);
        }
        element.__resizeListeners__.push(fn);
    }
};

window.removeResizeListener = function(element, fn){
    if (attachEvent) element.detachEvent('resize', fn);
    else {
        element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
        if (!element.__resizeListeners__.length) {
            element.removeEventListener('scroll', scrollListener);
            element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
        }
    }
}

})();

Demo-licious!

Here’s a pseudo code usage of the method.

var myElement = document.getElementById('my_element'),
    myResizeFn = function(){
        /* do something on resize */
    };
addResizeListener(myElement, myResizeFn);
removeResizeListener(myElement, myResizeFn);

Upvotes: 8

rbtbar
rbtbar

Reputation: 87

Only Window.onResize exists in the specification. Please remember that every IFrame element creates new Window object which supports onResize. Therefore IMO the most reliable method to detect changes to the element's size is to append hidden iframes to the element.

If you are interested in a neat and portable solution, please check this plugin. It takes 1 line of code to listen the event of changing width or height of your div.

<!-- (1) include plugin script in a page -->
<script src="/src/jquery-element-onresize.js"></script>

// (2) use the detectResizing plugin to monitor changes to the element's size:
$monitoredElement.detectResizing({ onResize: monitoredElement_onResize });

// (3) write a function to react on changes:
function monitoredElement_onResize() {    
    // logic here...
}

Upvotes: 8

Marc J. Schmidt
Marc J. Schmidt

Reputation: 8469

Microsoft's Internet Explorer supports onresize on all HTML elements. In all other Browsers the onresize is only available at the window object. https://developer.mozilla.org/en-US/docs/Web/API/Window.onresize

If you wanna have onresize at a div in all browsers check this:

http://marcj.github.io/css-element-queries/

This library has a class ResizeSensor which can be used for resize detection.

Upvotes: 15

Related Questions