Skip to content

Instantly share code, notes, and snippets.

@literallylara
Created April 27, 2022 18:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save literallylara/b790b9e573dbc5f26c83df78a01eb792 to your computer and use it in GitHub Desktop.
Save literallylara/b790b9e573dbc5f26c83df78a01eb792 to your computer and use it in GitHub Desktop.
/**
* Calculates an element's bounds to any given
* layer/skin (content, padding, border margin).
*
* @author Lara Sophie Schütt (@literallylara)
* @license MIT
*
* @param {HTMLElement} el
* @param {object} [options]
* Available options:
* - `skin` - An index representing the layers to include in the calculation:
* - 0 = content bounds
* - 1 = previous + padding
* - 2 = previous + border
* - 3 = previous + margin
* - `onlyHeight` - Whether or not to only calculate and return the height
* - `onlyWidth` - Whether or not to only calculate and return the width
* - `relativeTo` - The element of which to calculate
* the `left` and `right` values relative to
* - relativeToSkin The skin index to consider for
* the Element defined in `relativeTo`
* @param {Number} [options.skin=0]
* @param {Boolean} [options.onlyHeight=false]
* @param {Boolean} [options.onlyWidth=false]
* @param {HTMLElement} [options.relativeTo=null]
* @param {Number} [options.relativeToSkin=0]
* @returns {{
* width: Number,
* height: Number,
* top: Number,
* left: Number,
* right: Number,
* bottom: Number
* }|Number} The element's bounds.
*/
export default function(el,
{
skin = 0,
onlyHeight = false,
onlyWidth = false,
relativeTo = null,
relativeToSkin = 0
} = {})
{
if (!el) return
const parseFloat = window.parseFloat
const style = window.getComputedStyle(el)
const rect = el.getBoundingClientRect()
const relative = relativeTo && getBounds(relativeTo, {
skin: relativeToSkin,
onlyWidth,
onlyHeight
})
let width = null
let height = null
let top = null
let left = null
let right = null
let bottom = null
if (onlyHeight || !(onlyHeight || onlyWidth))
{
height = rect.height
top = rect.top
if (skin < 1)
{
const pt = parseFloat(style.paddingTop)
const pb = parseFloat(style.paddingBottom)
height -= pt
height -= pb
top += pt
}
if (skin < 2)
{
const bt = parseFloat(style.borderTopWidth)
const bb = parseFloat(style.borderBottomWidth)
height -= bt
height -= bb
top += bt
}
if (skin > 2)
{
const mt = parseFloat(style.marginTop)
const mb = parseFloat(style.marginBottom)
height += mt
height += mb
top -= mt
}
if (onlyHeight) return height
bottom = top + height
if (relative)
{
top -= relative.top
bottom -= relative.bottom
}
}
if (onlyWidth || !(onlyHeight || onlyWidth))
{
width = rect.width
left = rect.left
if (skin < 1)
{
const pl = parseFloat(style.paddingLeft)
const pr = parseFloat(style.paddingRight)
width -= pl
width -= pr
left += pl
}
if (skin < 2)
{
const bl = parseFloat(style.borderLeftWidth)
const br = parseFloat(style.borderRightWidth)
width -= bl
width -= br
left += bl
}
if (skin > 2)
{
const ml = parseFloat(style.marginLeft)
const mr = parseFloat(style.marginRight)
width += ml
width += mr
left -= ml
}
if (onlyWidth) return width
right = left + width
if (relative)
{
left -= relative.left
right -= relative.right
}
}
return { width, height, top, left, right, bottom }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment