6
\$\begingroup\$

This script looks for a data attribute applied to elements within a specified wrapper. It then sets all elements with the attribute to the same height (height of tallest div). I needed to add a wait time as the script would sometimes get the heights of the divs before the page had fully rendered. Even though the await is set to 0, it works.

There is also an event listener to listen for resize, and adjust the elements as they change size.

I have only been coding JS for a few weeks so I am not great at it.

HTML

<div id="div1">
  <div data-equalize>
    <p>Some content</p>
  </div>
  <div data-equalize>
    <p>Some content</p>
  </div>
  <div data-equalize>
    <p>Some content</p>
  </div>
  <div data-equalize>
    <p>Some content</p>
  </div>
</div>

Script

function equalizer(wrap) {
  const equalizeEls = Array.from(wrap.querySelectorAll(`[data-equalize]`));
  const wait = (ms = 0) => new Promise(resolve => setTimeout(resolve, ms));

  //get the largest height in the array
  function getLargestNumber(arr) {
    return Math.max(...arr);
  }

  //get an array of heights
  function getTallest(arr) {
    const allheights = arr.map(x => x.clientHeight);
    return getLargestNumber(allheights)  
  }

  function equalizeHeights(els) {
    const largest = getTallest(els);
    return els.forEach(el => {
       el.style.minHeight = `${largest}px`
    });
  }

  async function handleResize() {
    await wait(0); //needs a await to ensure page is fully loaded 
    equalizeHeights(equalizeEls)
  }

  window.addEventListener('DOMContentLoaded', handleResize);
  window.addEventListener('resize', handleResize);
}

Running the script

new equalizer(document.querySelector(`#div1`))
\$\endgroup\$
2
  • \$\begingroup\$ Are the divs positioned side by side? Then this can be done with CSS alone using flex or grid layout. \$\endgroup\$
    – RoToRa
    Jun 6 '20 at 16:58
  • 1
    \$\begingroup\$ Not always, I use flexbox when I can though. \$\endgroup\$
    – Nick
    Jun 6 '20 at 17:50
3
\$\begingroup\$

data attribute

It's a bit unconventional to use a data attribute to select the affected elements. A class would be the more conventional approach.

Use of template strings

You have two places where you unnecessarily use template strings with backticks (`).

Code

I like the code overall very much. Nice break down into functions. Nice use of modern JS features.

Only one small thing: The return in equalizeHeights is unnecessary.

Timing

The problem with the need for the wait may be due to contents of the divs. If they contain images or use external fonts, then they may lead to resizing of the divs while these are loading. Some points to look out for:

  • Use the load event instead or additionally to DOMContentLoaded.
  • Make sure images have a size assigned to them, either in the HTML (height and width attributes) or the CSS.
  • There a ways to make sure that the text content isn't rendered until the fonts are loaded, but this is not really my area of expertise.

Possible bug/misfeature

There is one problem with the script: It never allows the divs to shrink if the content becomes shorter, for example due to a window resize.

I can think of two possible solutions:

  • Before checking the size of the divs, remove the min-heights and wait() to allow a re-render.

Or

  • add a second, inner div inside the equalize divs and use the inner divs client height to determine the largest div.
\$\endgroup\$
1
  • \$\begingroup\$ This is awesome, thanks so much for the feedback! \$\endgroup\$
    – Nick
    Jun 15 '20 at 13:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.