Created
April 15, 2019 03:30
-
-
Save a1mersnow/e26193440fa38ebbb9a54847540c29c7 to your computer and use it in GitHub Desktop.
horizontal single line all children height specified flex layout
This file contains hidden or 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
好棒☆( ̄▽ ̄)/$:*!!!