Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save liulinboyi/494f8ff4fffa593f3af4c82eecf3ad55 to your computer and use it in GitHub Desktop.
Save liulinboyi/494f8ff4fffa593f3af4c82eecf3ad55 to your computer and use it in GitHub Desktop.
horizontal single line all children height specified flex layout
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.flex-container {
background-color: blanchedalmond;
}
.flex-item {
color: #fff;
text-align: center;
padding: 15px;
}
.flex-item:nth-child(1n) {
background-color: coral;
}
.flex-item:nth-child(2n) {
background-color: cornflowerblue;
}
.flex-item:nth-child(3n) {
background-color: crimson;
}
</style>
</head>
<body>
<div class="flex-container" style="align-items: center; justify-content: space-between; padding: 20px;">
<div class="flex-item" style="height: 100px; width: 200px; align-self: flex-end;">1</div>
<div class="flex-item" style="height: 200px;">22</div>
<div class="flex-item" style="height: 150px;">333</div>
</div>
<script>
{
const flexContainers = document.querySelectorAll('.flex-container')
for (let flexContainer of flexContainers) {
flexInit(flexContainer)
}
// reimplement flex layout
function flexInit (flexContainer) {
const flexItems = [...flexContainer.children]
let styleMap = new WeakMap()
for (let flexItem of flexItems) {
flexItem.style.position = 'absolute'
}
let {position, alignItems, justifyContent, boxSizing, paddingTop, paddingBottom, paddingLeft, paddingRight, borderTopWidth, borderBottomWidth} = window.getComputedStyle(flexContainer)
let width = flexContainer.clientWidth - parseFloat(paddingLeft) - parseFloat(paddingRight)
let containerPaddingTop = paddingTop
let containerPaddingLeft = paddingLeft
for (let flexItem of flexItems) {
styleMap.set(flexItem, {
...window.getComputedStyle(flexItem),
width: flexItem.offsetWidth,
height: flexItem.offsetHeight
})
}
let containerHeight = flexItems.reduce((max, flexItem) => {
let {height} = styleMap.get(flexItem)
height = parseFloat(height)
return height > max ? height : max
}, 0)
if (!flexContainer.style.height) {
if (boxSizing === 'content-box') {
flexContainer.style.height = containerHeight + 'px'
} else if (boxSizing === 'padding-box') {
flexContainer.style.height = containerHeight + parseFloat(paddingTop) + parseFloat(paddingBottom) + 'px'
} else if (boxSizing === 'border-box') {
flexContainer.style.height = containerHeight + parseFloat(paddingTop) + parseFloat(paddingBottom) + parseFloat(borderTopWidth) + parseFloat(borderBottomWidth) + 'px'
}
}
if (!flexContainer.style.width) {
flexContainer.style.width = 'auto'
}
if (position === 'static') flexContainer.style.position = 'relative'
let spaceRemain = parseFloat(width) - flexItems.reduce((acc, flexItem) => acc + parseFloat(styleMap.get(flexItem).width), 0)
let flexGrowTotal = flexItems.reduce((acc, flexItem) => acc + parseInt(styleMap.get(flexItem).flexGrow), 0)
let flexShrinkTotal = flexItems.reduce((acc, flexItem) => acc + parseInt(styleMap.get(flexItem).flexShrink), 0)
for (let flexItem of flexItems) {
let {height, width, flexGrow, flexShrink, alignSelf, boxSizing, paddingTop, paddingBottom, borderTopWidth, borderBottomWidth} = styleMap.get(flexItem)
let align = alignSelf === 'auto' ? alignItems : alignSelf
if (align === 'stretch') {
if (boxSizing === 'content-box') {
flexItem.style.height = containerHeight - parseFloat(paddingTop) - parseFloat(paddingBottom) - parseFloat(borderTopWidth) - parseFloat(borderBottomWidth) + 'px'
} else if (boxSizing === 'padding-box') {
flexItem.style.height = containerHeight - parseFloat(borderTopWidth) - parseFloat(borderBottomWidth) + 'px'
} else if (boxSizing === 'border-box') {
flexItem.style.height = containerHeight + 'px'
}
flexItem.style.top = containerPaddingTop
} else if (align === 'flex-start') {
flexItem.style.top = containerPaddingTop
} else if (align === 'flex-end') {
flexItem.style.bottom = containerPaddingTop
} else if (align === 'center') {
flexItem.style.top = parseFloat(containerPaddingTop) + (containerHeight - parseFloat(height)) / 2 + 'px'
} else {
throw new Error('Note: "baseline" is not support😢')
}
}
for (let flexItem of flexItems) {
let {height, width, flexGrow, flexShrink, alignSelf, boxSizing, paddingLeft, paddingRight, borderLeftWidth, borderRightWidth} = styleMap.get(flexItem)
if (spaceRemain > 0) {
if (+flexGrow > 0) {
if (boxSizing === 'content-box') {
flexItem.style.width = parseFloat(styleMap.get(flexItem).width) + flexGrow / flexGrowTotal * spaceRemain - parseFloat(paddingLeft) - parseFloat(paddingRight) - parseFloat(borderLeftWidth) - parseFloat(borderRightWidth) + 'px'
} else if (boxSizing === 'padding-box') {
flexItem.style.width = parseFloat(styleMap.get(flexItem).width) + flexGrow / flexGrowTotal * spaceRemain - parseFloat(borderLeftWidth) - parseFloat(borderRightWidth) + 'px'
} else if (boxSizing === 'border-box') {
flexItem.style.width = parseFloat(styleMap.get(flexItem).width) + flexGrow / flexGrowTotal * spaceRemain + 'px'
}
}
} else if (spaceRemain < 0) {
if (+flexShrink > 0) {
if (boxSizing === 'content-box') {
flexItem.style.width = parseFloat(styleMap.get(flexItem).width) + flexShrink / flexShrinkTotal * spaceRemain - parseFloat(paddingLeft) - parseFloat(paddingRight) - parseFloat(borderLeftWidth) - parseFloat(borderRightWidth) + 'px'
} else if (boxSizing === 'padding-box') {
flexItem.style.width = parseFloat(styleMap.get(flexItem).width) + flexShrink / flexShrinkTotal * spaceRemain - parseFloat(borderLeftWidth) - parseFloat(borderRightWidth) + 'px'
} else if (boxSizing === 'border-box') {
flexItem.style.width = parseFloat(styleMap.get(flexItem).width) + flexShrink / flexShrinkTotal * spaceRemain + 'px'
}
}
}
}
for (let flexItem of flexItems) {
styleMap.set(flexItem, {
...window.getComputedStyle(flexItem),
width: flexItem.offsetWidth,
height: flexItem.offsetHeight
})
}
spaceRemain = parseFloat(width) - flexItems.reduce((acc, flexItem) => acc + parseFloat(styleMap.get(flexItem).width), 0)
let pos
let gutter
if (justifyContent === 'flex-start' || justifyContent === 'normal') {
pos = 0 + parseFloat(containerPaddingLeft)
gutter = 0
} else if (justifyContent === 'flex-end') {
pos = (spaceRemain > 0 && flexGrowTotal <= 0 ? spaceRemain : 0) + parseFloat(containerPaddingLeft)
gutter = 0
} else if (justifyContent === 'center') {
pos = spaceRemain / 2 + parseFloat(containerPaddingLeft)
gutter = 0
} else if (justifyContent === 'space-between') {
pos = 0 + parseFloat(containerPaddingLeft)
gutter = spaceRemain / (flexItems.length - 1)
} else if (justifyContent === 'space-around') {
gutter = spaceRemain / flexItems.length
pos = gutter / 2 + parseFloat(containerPaddingLeft)
} else {
throw new Error(`unknown value for "justifyContent": ${justifyContent}`)
}
for (let flexItem of flexItems) {
flexItem.style.left = pos + 'px'
pos += parseFloat(styleMap.get(flexItem).width) + gutter
}
}
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment