'To merge window resizing and loading the page events into one function
I have a local html page that serves me a cheat sheet about how width
, max-width
and min-width
work. It dynamically reports you the width of the body
and of the inner div
, and changes the div
's background color accordingly.
const div = document.querySelector('div');
const body = document.querySelector('body');
const outputDivWidth = document.querySelector('#outputDivWidth');
const outputBodyWidth = document.querySelector('#outputBodyWidth');
function reportWidths() {
const divWidth = div.offsetWidth;
const bodyWidth = body.offsetWidth;
outputDivWidth.textContent = divWidth;
outputBodyWidth.textContent = bodyWidth;
if (divWidth >= 500) {
div.style.backgroundColor = 'rgb(0% 100% 0% / 10%)';
} else if (divWidth <= 300) {
div.style.backgroundColor = 'rgb(100% 0% 0% / 10%)';
} else {
div.style.backgroundColor = 'rgb(100% 100% 0% / 10%)';
}
}
reportWidths();
window.addEventListener('resize', () => {
reportWidths();
});
body {
outline: blue solid 1px;
}
div {
outline: red solid 1px;
/* 500 px if the width of the parent element is ≥ 999 px,
* 300 px if the width of the parent element is ≤ 600 px,
* 50% of the width of the parent element otherwise. */
max-width: 500px; min-width: 300px; width: 50%;
}
p#outputBodyWidth { color: blue; }
p#outputDivWidth { color: red; }
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p id="outputDivWidth"></p>
</div>
<p id="outputBodyWidth"></p>
Here is the part that I don't like:
reportWidths();
window.addEventListener('resize', () => {
reportWidths();
});
It looks silly and unprofessional to me (note, I'm not really a web developer) to use function call right before using event listener that uses the same function, and so I would prefer to change it to a one-step solution. But how?
Solution 1:[1]
It is normal to call a function and register it as an event handler as well. These are two different things.
Perhaps the way reportWidths
is being called inside an arrow function is making it look like a redundant call. We don’t have to wrap it in an arrow function. Following code achieves the same thing:
window.addEventListener('resize', reportWidths);
window.addEventListener('load', reportWidths);
This makes it clear why we need to use the function two times.
Here is another way to do it:
const div = document.querySelector('div');
const body = document.querySelector('body');
const outputDivWidth = document.querySelector('#outputDivWidth');
const outputBodyWidth = document.querySelector('#outputBodyWidth');
function reportWidths() {
const divWidth = div.offsetWidth;
const bodyWidth = body.offsetWidth;
outputDivWidth.textContent = divWidth;
outputBodyWidth.textContent = bodyWidth;
if (divWidth >= 500) {
div.style.backgroundColor = 'rgb(0% 100% 0% / 10%)';
} else if (divWidth <= 300) {
div.style.backgroundColor = 'rgb(100% 0% 0% / 10%)';
} else {
div.style.backgroundColor = 'rgb(100% 100% 0% / 10%)';
}
}
window.addEventListener('resize', reportWidths);
window.dispatchEvent(new Event('resize'));
body {
outline: blue solid 1px;
}
div {
outline: red solid 1px;
/* 500 px if the width of the parent element is ? 999 px,
* 300 px if the width of the parent element is ? 600 px,
* 50% of the width of the parent element otherwise. */
max-width: 500px; min-width: 300px; width: 50%;
}
p#outputBodyWidth { color: blue; }
p#outputDivWidth { color: red; }
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p id="outputDivWidth"></p>
</div>
<p id="outputBodyWidth"></p>
We are throwing resize
event ourselves because it doesn’t get raised when document loads.
One more way to do it is using ResizeObserver
:
const div = document.querySelector('div');
const body = document.querySelector('body');
const outputDivWidth = document.querySelector('#outputDivWidth');
const outputBodyWidth = document.querySelector('#outputBodyWidth');
function reportWidths() {
const divWidth = div.offsetWidth;
const bodyWidth = body.offsetWidth;
outputDivWidth.textContent = divWidth;
outputBodyWidth.textContent = bodyWidth;
if (divWidth >= 500) {
div.style.backgroundColor = 'rgb(0% 100% 0% / 10%)';
} else if (divWidth <= 300) {
div.style.backgroundColor = 'rgb(100% 0% 0% / 10%)';
} else {
div.style.backgroundColor = 'rgb(100% 100% 0% / 10%)';
}
}
new ResizeObserver(reportWidths).observe(body);
body {
outline: blue solid 1px;
}
div {
outline: red solid 1px;
/* 500 px if the width of the parent element is ? 999 px,
* 300 px if the width of the parent element is ? 600 px,
* 50% of the width of the parent element otherwise. */
max-width: 500px; min-width: 300px; width: 50%;
}
p#outputBodyWidth { color: blue; }
p#outputDivWidth { color: red; }
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p id="outputDivWidth"></p>
</div>
<p id="outputBodyWidth"></p>
With this we don't have use the handler at two places.
Solution 2:[2]
Slightly more elegant, would be to call it on document load event. There's nothing wrong with calling a function right before setting that in a listener, though.
const div = document.querySelector('div');
const body = document.querySelector('body');
const outputDivWidth = document.querySelector('#outputDivWidth');
const outputBodyWidth = document.querySelector('#outputBodyWidth');
function reportWidths() {
const divWidth = div.offsetWidth;
const bodyWidth = body.offsetWidth;
outputDivWidth.textContent = divWidth;
outputBodyWidth.textContent = bodyWidth;
if (divWidth >= 500) {
div.style.backgroundColor = 'rgb(0% 100% 0% / 10%)';
} else if (divWidth <= 300) {
div.style.backgroundColor = 'rgb(100% 0% 0% / 10%)';
} else {
div.style.backgroundColor = 'rgb(100% 100% 0% / 10%)';
}
}
// Calling it on document load instead.
// And since you care about params here, just pass a reference to the function
document.addEventListener("load", reportWidths);
// and also here
window.addEventListener('resize', reportWidths);
body {
outline: blue solid 1px;
}
div {
outline: red solid 1px;
/* 500 px if the width of the parent element is ? 999 px,
* 300 px if the width of the parent element is ? 600 px,
* 50% of the width of the parent element otherwise. */
max-width: 500px; min-width: 300px; width: 50%;
}
p#outputBodyWidth { color: blue; }
p#outputDivWidth { color: red; }
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p id="outputDivWidth"></p>
</div>
<p id="outputBodyWidth"></p>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | the Hutt |
Solution 2 | Tiago Nobrega |