Forked from a1mersnow/horizontal-single-line-all-children-height-specified-flex.html
Created
April 25, 2021 05:05
-
-
Save liulinboyi/494f8ff4fffa593f3af4c82eecf3ad55 to your computer and use it in GitHub Desktop.
horizontal single line all children height specified flex layout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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