Last active
April 9, 2018 19:51
-
-
Save bmcminn/7c371f669502f1580848f1d252f99c36 to your computer and use it in GitHub Desktop.
Basic container query implementation in vanilla JS
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 http-equiv="x-ua-compatible" content="ie=edge"> | |
<title>Container Queries in Vanilla JS</title> | |
<meta name="description" content=""> | |
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/5.0.0/sanitize.min.css"> | |
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css"> --> | |
<style type="text/css"> | |
body { | |
font-family: sans-serif; | |
} | |
main { | |
background: #f90; | |
} | |
aside { | |
background: #f1357a; | |
} | |
.color-bada55 { | |
background: #bada55; | |
} | |
.color-55adab { | |
background: #55adab; | |
} | |
[container] { | |
width: 100%; | |
} | |
.row { | |
font-size: 0; | |
} | |
.row > * { | |
font-size: initial; | |
} | |
.col { | |
width: 100%; | |
padding: 1rem; | |
display: inline-block; | |
vertical-align: top; | |
} | |
.col .row { | |
margin-top: 1rem; | |
margin-bottom: -1rem; | |
margin-left: -1rem; | |
width: calc(100% + 2rem); | |
} | |
.col .row .col { | |
width: calc(100% + 1rem); | |
} | |
/* COL XS */ | |
[container="xs"] .col[xs="1-1"] { width: 100%; } | |
[container="xs"] .col[xs="1-2"] { width: 50%; } | |
[container="xs"] .col[xs="1-3"] { width: calc(100%/3); } | |
[container="xs"] .col[xs="2-3"] { width: calc(2 * (100%/3)); } | |
[container="xs"] .col[xs="1-4"] { width: 25%; } | |
[container="xs"] .col[xs="3-4"] { width: 75%; } | |
[container="xs"] .col[xs="1-5"] { width: 20%; } | |
[container="xs"] .col[xs="2-5"] { width: 40%; } | |
[container="xs"] .col[xs="3-5"] { width: 60%; } | |
[container="xs"] .col[xs="4-5"] { width: 80%; } | |
[container="xs"] .col[xs="1-6"] { width: calc(100%/6); } | |
[container="xs"] .col[xs="5-6"] { width: calc(5 * (100%/6)); } | |
/* COL SM */ | |
[container="sm"] .col[sm="1-1"] { width: 100%; } | |
[container="sm"] .col[sm="1-2"] { width: 50%; } | |
[container="sm"] .col[sm="1-3"] { width: calc(100%/3); } | |
[container="sm"] .col[sm="2-3"] { width: calc(2 * (100%/3)); } | |
[container="sm"] .col[sm="1-4"] { width: 25%; } | |
[container="sm"] .col[sm="3-4"] { width: 75%; } | |
[container="sm"] .col[sm="1-5"] { width: 20%; } | |
[container="sm"] .col[sm="2-5"] { width: 40%; } | |
[container="sm"] .col[sm="3-5"] { width: 60%; } | |
[container="sm"] .col[sm="4-5"] { width: 80%; } | |
[container="sm"] .col[sm="1-6"] { width: calc(100%/6); } | |
[container="sm"] .col[sm="5-6"] { width: calc(5 * (100%/6)); } | |
/* COL MD */ | |
[container="md"] .col[md="1-1"] { width: 100%; } | |
[container="md"] .col[md="1-2"] { width: 50%; } | |
[container="md"] .col[md="1-3"] { width: calc(100%/3); } | |
[container="md"] .col[md="2-3"] { width: calc(2 * (100%/3)); } | |
[container="md"] .col[md="1-4"] { width: 25%; } | |
[container="md"] .col[md="3-4"] { width: 75%; } | |
[container="md"] .col[md="1-5"] { width: 20%; } | |
[container="md"] .col[md="2-5"] { width: 40%; } | |
[container="md"] .col[md="3-5"] { width: 60%; } | |
[container="md"] .col[md="4-5"] { width: 80%; } | |
[container="md"] .col[md="1-6"] { width: calc(100%/6); } | |
[container="md"] .col[md="5-6"] { width: calc(5 * (100%/6)); } | |
/* COL LG */ | |
[container="lg"] .col[lg="1-1"] { width: 100%; } | |
[container="lg"] .col[lg="1-2"] { width: 50%; } | |
[container="lg"] .col[lg="1-3"] { width: calc(100%/3); } | |
[container="lg"] .col[lg="2-3"] { width: calc(2 * (100%/3)); } | |
[container="lg"] .col[lg="1-4"] { width: 25%; } | |
[container="lg"] .col[lg="3-4"] { width: 75%; } | |
[container="lg"] .col[lg="1-5"] { width: 20%; } | |
[container="lg"] .col[lg="2-5"] { width: 40%; } | |
[container="lg"] .col[lg="3-5"] { width: 60%; } | |
[container="lg"] .col[lg="4-5"] { width: 80%; } | |
[container="lg"] .col[lg="1-6"] { width: calc(100%/6); } | |
[container="lg"] .col[lg="5-6"] { width: calc(5 * (100%/6)); } | |
/* COL XL */ | |
[container="xl"] .col[xl="1-1"] { width: 100%; } | |
[container="xl"] .col[xl="1-2"] { width: 50%; } | |
[container="xl"] .col[xl="1-3"] { width: calc(100%/3); } | |
[container="xl"] .col[xl="2-3"] { width: calc(2 * (100%/3)); } | |
[container="xl"] .col[xl="1-4"] { width: 25%; } | |
[container="xl"] .col[xl="3-4"] { width: 75%; } | |
[container="xl"] .col[xl="1-5"] { width: 20%; } | |
[container="xl"] .col[xl="2-5"] { width: 40%; } | |
[container="xl"] .col[xl="3-5"] { width: 60%; } | |
[container="xl"] .col[xl="4-5"] { width: 80%; } | |
[container="xl"] .col[xl="1-6"] { width: calc(100%/6); } | |
[container="xl"] .col[xl="5-6"] { width: calc(5 * (100%/6)); } | |
</style> | |
</head> | |
<body> | |
<div class="container-fluid" container> | |
<div class="row"> | |
<main class="col" sm="3-4"> | |
sm-6 column | |
</main> | |
<aside class="col" sm="1-4" container> | |
sm-6 column | |
<div class="row"> | |
<div class="col color-bada55" xs="1-2" >bada55</div> | |
<div class="col color-55adab" xs="1-2" >55adab</div> | |
<div class="col color-bada55" xs="1-2" >bada55</div> | |
<div class="col color-55adab" xs="1-2" >55adab</div> | |
</div> | |
</aside> | |
</div> | |
</div> | |
<script type="text/javascript"> | |
/** | |
* A debounced method for running container query checks at-will that assign container size parameters based on container width | |
* @return void | |
*/ | |
let containerQueries = debounce(function () { | |
let attrName = 'container'; | |
window.___containerSizes = window.___containerSizes || | |
[ | |
{ label: 'xs', size: 0 } | |
, { label: 'sm', size: 576 } | |
, { label: 'md', size: 768 } | |
, { label: 'lg', size: 992 } | |
, { label: 'xl', size: 1200 } | |
] | |
// // ensure we have all sizes sorted smallest to largest | |
// .sort((a, b) => { | |
// if (a.size < b.size) return -1; | |
// if (a.size > b.size) return 1; | |
// return 0; | |
// }) | |
; | |
document | |
.querySelectorAll('[' + attrName + ']') | |
.forEach((container) => { | |
for (var i = window.___containerSizes.length - 1; i >= 0; i--) { | |
let size = window.___containerSizes[i]; | |
if (container.offsetWidth > size.size && | |
container.container !== size.size | |
) { | |
container.setAttribute(attrName, size.label); | |
break; | |
} | |
} | |
}); | |
}, 250, true); | |
/** | |
* Debounce, throttle all the things more for performance and profit | |
* @sauce: https://davidwalsh.name/javascript-debounce-function | |
* @sauce: http://underscorejs.org/#debounce | |
* @param {function} func The function to be debounced | |
* @param {integer} wait The time in milliseconds to delay execution before checking the event | |
* @param {boolean} immediate Boolean flag to trigger the callback before timeout is checked instead of after | |
* @return {function} Returns a new version of the original function to be called on the next timeout cycle | |
*/ | |
function debounce(func, wait, immediate) { | |
let timeout; | |
return function() { | |
let context = this, args = arguments; | |
let later = function() { | |
timeout = null; | |
if (!immediate) func.apply(context, args); | |
}; | |
let callNow = immediate && !timeout; | |
clearTimeout(timeout); | |
timeout = setTimeout(later, wait); | |
if (callNow) func.apply(context, args); | |
}; | |
}; | |
containerQueries(); | |
window.addEventListener('resize', containerQueries); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment