Skip to content

Instantly share code, notes, and snippets.

@bmcminn
Last active April 9, 2018 19:51
Show Gist options
  • Save bmcminn/7c371f669502f1580848f1d252f99c36 to your computer and use it in GitHub Desktop.
Save bmcminn/7c371f669502f1580848f1d252f99c36 to your computer and use it in GitHub Desktop.
Basic container query implementation in vanilla JS
<!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