How to Write a Container Queries Plugin
This document describes the parts required to create a JavaScript function for evaluating container queries, and this document itself is also executable JavaScript code for such a plugin. By the time you are finished reading this document you should not only understand how container queries work, but have read the source code to a usable, testable container queries function.
/* To define a */ function /* for */ containerQueries /* we will need to supply a */ (selectorList, /* of CSS selectors to match elements in the document, a JavaScript function to serve as a */ test, /* to determine which elements our styles should apply to, and a */ stylesheet) /* with the CSS we wish to apply to all elements passing the test. */ {
/* Inside of our function we need to define a */ var /* for all */ matchingTags /* that is */ = /* to taking the */ document /* and running a */ .querySelectorAll /* for the */ (selectorList); /* supplied to the function. */
/* Next we can create a */ var /* to keep track of our */ generatedCSS /* that is */ = /* to a */ new String;
/* The last piece of setup we require is a */ var /* to keep track of our current element */ count /* that is */ = /* to */ 0;
/* Now we are ready to take all */ matchingTags /* and run the following logic */ .forEach( tag => {
/* The first thing we need to create for each tag is a new */ var /* called */ uniqueAttribute /* that is */ = /* to the text of our */ (selectorList + test) /* added together, with all non-Word characters removed. We can do this with a */ .replace /* using the regular expression */ (/\W+/g, /* and swapping every non-Word character you find with */ '' /* , the empty string */ );
/* Now we're ready to test each of our tags! */ if /* we */ (test /* the current */ (tag) /* and the result is */ == /* to */ true) /* then we can go ahead with the following three actions: */ {
/* First we will take the */ tag /* that passes our test and */ .setAttribute /* equal to */ ('data-' + /* our */ uniqueAttribute, /* and set this attribute to the current */ count);
/* Second we will take our */ generatedCSS /* and make sure it is */ = /* to the existing */ generatedCSS + /* the supplied */ stylesheet /* with all instances of "$this" replaced with a selector using our unique attribute. We can do this with a a */ .replace /* using the following regular expression */ (/\$this/g, /* and swapping each instance with */ '[data-' + /* our */ uniqueAttribute + '="' + /* our current matching tag */ count + '"]');
/* Third, we will increment the */ count++; /* of matching tags by 1. */
} /* This ends the three things we do to each tag passing the test. */
if /* we */ (test /* the current */ (tag) /* and the result is */ == /* to */ false) /* then we need to take the */ tag /* failing our test and */ .setAttribute /* equal to */ ('data-' + /* our */ uniqueAttribute, /* and remove any pre-existing value with */ '');
}) /* This ends the logic we run for each matching tag. */
/* The last thing we need to do is */ return /* all of our */ generatedCSS
} /* And this ends our container queries function */
The above code, run through uglifyjs and then prettier outputs the following JS code:
function containerQueries(selectorList, test, stylesheet) {
var matchingTags = document.querySelectorAll(selectorList);
var generatedCSS = new String();
var count = 0;
matchingTags.forEach(tag => {
var uniqueAttribute = (selectorList + test).replace(/\W+/g, "");
if (test(tag) == true) {
tag.setAttribute("data-" + uniqueAttribute, count);
generatedCSS =
generatedCSS +
stylesheet.replace(
/\$this/g,
"[data-" + uniqueAttribute + '="' + count + '"]'
);
count++;
}
if (test(tag) == false) tag.setAttribute("data-" + uniqueAttribute, "");
});
return generatedCSS;
}
And a short test of the plugin:
Click here for a slightly cleaner version of this plugin written in ES5 and ES6
And here's a flowchart of the logic:
Leave a Comment Markdown supported. Click @usernames to add to comment.