I\'ve the following sample html, there is a DIV which has 100% width. It contains some elements. While performing windows re-sizing, the inner elements may be re-positioned,
Here is a simplified version of the solution by @nkron, applicable to a single element (instead of an array of elements in @nkron's answer, complexity I did not need).
function onResizeElem(element, callback) {
// Save the element we are watching
onResizeElem.watchedElementData = {
element: element,
offsetWidth: element.offsetWidth,
offsetHeight: element.offsetHeight,
callback: callback
};
onResizeElem.checkForChanges = function() {
const data = onResizeElem.watchedElementData;
if (data.element.offsetWidth !== data.offsetWidth || data.element.offsetHeight !== data.offsetHeight) {
data.offsetWidth = data.element.offsetWidth;
data.offsetHeight = data.element.offsetHeight;
data.callback();
}
};
// Listen to the window resize event
window.addEventListener('resize', onResizeElem.checkForChanges);
// Listen to the element being checked for width and height changes
onResizeElem.observer = new MutationObserver(onResizeElem.checkForChanges);
onResizeElem.observer.observe(document.body, {
attributes: true,
childList: true,
characterData: true,
subtree: true
});
}
The event listener and observer can be removed by:
window.removeEventListener('resize', onResizeElem.checkForChanges);
onResizeElem.observer.disconnect();
The best solution would be to use the so-called Element Queries. However, they are not standard, no specification exists - and the only option is to use one of the polyfills/libraries available, if you want to go this way.
The idea behind element queries is to allow a certain container on the page to respond to the space that's provided to it. This will allow to write a component once and then drop it anywhere on the page, while it will adjust its contents to its current size. No matter what the Window size is. This is the first difference that we see between element queries and media queries. Everyone hopes that at some point a specification will be created that will standardize element queries (or something that achieves the same goal) and make them native, clean, simple and robust. Most people agree that Media queries are quite limited and don't help for modular design and true responsiveness.
There are a few polyfills/libraries that solve the problem in different ways (could be called workarounds instead of solutions though):
I have seen other solutions to similar problems proposed. Usually they use timers or the Window/viewport size under the hood, which is not a real solution. Furthermore, I think ideally this should be solved mainly in CSS, and not in javascript or html.
Long term, you will be able to use the ResizeObserver.
new ResizeObserver(callback).observe(element);
Unfortunately it is not currently supported by default in many browsers.
In the mean time, you can use function like the following. Since, the majority of element size changes will come from the window resizing or from changing something in the DOM. You can listen to window resizing with the window's resize event and you can listen to DOM changes using MutationObserver.
Here's an example of a function that will call you back when the size of the provided element changes as a result of either of those events:
var onResize = function(element, callback) {
if (!onResize.watchedElementData) {
// First time we are called, create a list of watched elements
// and hook up the event listeners.
onResize.watchedElementData = [];
var checkForChanges = function() {
onResize.watchedElementData.forEach(function(data) {
if (data.element.offsetWidth !== data.offsetWidth ||
data.element.offsetHeight !== data.offsetHeight) {
data.offsetWidth = data.element.offsetWidth;
data.offsetHeight = data.element.offsetHeight;
data.callback();
}
});
};
// Listen to the window's size changes
window.addEventListener('resize', checkForChanges);
// Listen to changes on the elements in the page that affect layout
var observer = new MutationObserver(checkForChanges);
observer.observe(document.body, {
attributes: true,
childList: true,
characterData: true,
subtree: true
});
}
// Save the element we are watching
onResize.watchedElementData.push({
element: element,
offsetWidth: element.offsetWidth,
offsetHeight: element.offsetHeight,
callback: callback
});
};
A new standard for this is the Resize Observer api, available in Chrome 64.
function outputsize() {
width.value = textbox.offsetWidth
height.value = textbox.offsetHeight
}
outputsize()
new ResizeObserver(outputsize).observe(textbox)
Width: <output id="width">0</output><br>
Height: <output id="height">0</output><br>
<textarea id="textbox">Resize me</textarea><br>
Spec: https://wicg.github.io/ResizeObserver
Polyfills: https://github.com/WICG/ResizeObserver/issues/3
Firefox Issue: https://bugzil.la/1272409
Safari Issue: http://wkb.ug/157743
Current Support: http://caniuse.com/#feat=resizeobserver
Take a look at this http://benalman.com/code/projects/jquery-resize/examples/resize/
It has various examples. Try resizing your window and see how elements inside container elements adjusted.
Example with js fiddle to explain how to get it work.
Take a look at this fiddle http://jsfiddle.net/sgsqJ/4/
In that resize() event is bound to an elements having class "test" and also to the window object and in resize callback of window object $('.test').resize() is called.
e.g.
$('#test_div').bind('resize', function(){
console.log('resized');
});
$(window).resize(function(){
$('#test_div').resize();
});
var div = document.getElementById('div');
div.addEventListener('resize', (event) => console.log(event.detail));
function checkResize (mutations) {
var el = mutations[0].target;
var w = el.clientWidth;
var h = el.clientHeight;
var isChange = mutations
.map((m) => m.oldValue + '')
.some((prev) => prev.indexOf('width: ' + w + 'px') == -1 || prev.indexOf('height: ' + h + 'px') == -1);
if (!isChange)
return;
var event = new CustomEvent('resize', {detail: {width: w, height: h}});
el.dispatchEvent(event);
}
var observer = new MutationObserver(checkResize);
observer.observe(div, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
#div {width: 100px; border: 1px solid #bbb; resize: both; overflow: hidden;}
<div id = "div">DIV</div>