Skip to content

Instantly share code, notes, and snippets.

@ImKubass
Last active October 9, 2023 03:50
Show Gist options
  • Save ImKubass/2a1a5ae716f6adb7bb9b0cdae7fd9bd0 to your computer and use it in GitHub Desktop.
Save ImKubass/2a1a5ae716f6adb7bb9b0cdae7fd9bd0 to your computer and use it in GitHub Desktop.
Same height of elements
export const sameHeight = (group: Element, elements: string | NodeListOf<HTMLElement>, byRow = false) => {
const targets = elements instanceof NodeList ? Array.from(elements) : Array.from(group.querySelectorAll<HTMLElement>(elements))
const getHighestElement = (elements: HTMLElement[] = targets): number => {
const heights = elements.map((box) => box.clientHeight)
return Math.max(...heights)
}
const resetHeight = (elements: HTMLElement[] = targets) => {
elements.forEach((element) => element.style.removeProperty("height"))
}
const updateHeight = (elements: HTMLElement[] = targets) => {
const theHighest = `${getHighestElement(elements)}px`
elements.forEach((element) => element.style.setProperty("height", theHighest))
}
const updateByRow = () => {
const rows = Array.from(new Set(targets.map((target) => target.offsetTop)))
const elementsCollection: HTMLElement[][] = []
let targetsToFilter = targets
rows.forEach((row) => {
const elementsInSameRow = targets.filter((target) => target.offsetTop === row)
elementsCollection.push(elementsInSameRow)
targetsToFilter = targetsToFilter.filter((item) => !elementsInSameRow.includes(item))
})
elementsCollection.forEach((elements) => updateHeight(elements))
}
const resizeObserver = new ResizeObserver(() => {
resetHeight()
byRow ? updateByRow() : updateHeight()
})
resizeObserver.observe(group)
}
const init = () => {
const groups = document.querySelectorAll(`[data-same-height]`)
groups.forEach((group) => {
const byRow = group.hasAttribute("data-same-height-by-row")
const targets = Array.from(group.querySelectorAll<HTMLElement>(`[data-same-height-target]`))
const collections = Array.from(new Set(targets.map((target) => target.getAttribute("data-same-height-target"))))
collections.forEach((collection) => {
const collectionElements = group.querySelectorAll<HTMLElement>(`[data-same-height-target="${collection}"]`)
sameHeight(group, collectionElements, byRow)
})
})
}
// call after rerender -> document.dispatchEvent(new Event("sameHeight")) -> reinitialize
document.addEventListener("sameHeight", () => init())
init()
@ImKubass
Copy link
Author

Usage example:

import { sameHeight } from "./../../../js/same-height/same-height"

const productsGroups = document.querySelectorAll(".s-products-slider, .s-products")

productsGroups.forEach(group => {
  sameHeight(group, ".i-product__header")
})

@ImKubass
Copy link
Author

ImKubass commented Oct 9, 2023

HTML data atributes usage examples:

{# example 1 #}

<div class="group" data-same-height>

  <article class="item">
    <div class="item__header" data-same-height-target></div>
    <div class="item__content"></div>
  </article>

  <article class="item">
    <div class="item__header" data-same-height-target></div>
    <div class="item__content"></div>
  </article>

  <article class="item">
    <div class="item__header" data-same-height-target></div>
    <div class="item__content"></div>
  </article>

</div>

{# example 2 - for grid items, if items are not in one line #}

<div class="group" data-same-height data-same-height-by-row>

  <article class="item">
    <div class="item__header" data-same-height-target></div>
    <div class="item__content"></div>
  </article>

  <article class="item">
    <div class="item__header" data-same-height-target></div>
    <div class="item__content"></div>
  </article>

  <article class="item">
    <div class="item__header" data-same-height-target></div>
    <div class="item__content"></div>
  </article>

</div>

{# example 3 - Multiple targets collections #}

<div class="group" data-same-height>

  <article class="item">
    <div class="item__header" data-same-height-target="header"></div>
    <div class="item__content" data-same-height-target="content"></div>
  </article>

  <article class="item">
    <div class="item__header" data-same-height-target="header"></div>
    <div class="item__content" data-same-height-target="content"></div>
  </article>

  <article class="item">
    <div class="item__header" data-same-height-target="header"></div>
    <div class="item__content" data-same-height-target="content"></div>
  </article>

</div>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment