Container Queries Mixin

This JavaScript function lets you define a ‘container’ using a CSS selector, run a JavaScript test against matching tags that match the container’s selector, and to apply a CSS rule to that container or its children.

Syntax

container(selector, test, childSelector, rule)

Example

Input:

container('div', 'this.offsetWidth > 500', 'span', 'background: lime;')

Output:

/* div(this.offsetWidth > 500) span */
[data-container-unique="0"] span {
  background: lime;
}

Code

Rule version:


function container(selector, test, childSelector, rule) {

  var tag = document.querySelectorAll(selector)
  var style = ''
  var count = 0

  for (var i=0; i < tag.length; i++) {

    var attr = (selector+test).replace(/\W+/g, '')

    var func = new Function('return ' + test)

    if (func.call(tag[i])) {

      tag[i].setAttribute('data-container-' + attr, count)

      var container = '[data-container-' + attr + '="' + count + '"]'

      style += '\n/* ' + selector + '(' + test + ') ' + childSelector + ' */\n'
               + container + ' ' + childSelector + ' {\n'
               + '  ' + rule + '\n'
               + '}\n'

      count++

    } else {

      tag[i].setAttribute('data-container-' + attr, '')

    }

  }

  return style

}

Stylesheet version (using $this as a keyword for matching tags):

function container(selector, test, stylesheet) {

  var tag = document.querySelectorAll(selector)
  var style = ''
  var count = 0

  for (var i=0; i<tag.length; i++) {

    var func = new Function(`return ${test}`)
    var attr = (selector+test).replace(/\W+/g, '')

    if (func.call(tag[i])) {

      tag[i].setAttribute(`data-${attr}`, count)

      var css = stylesheet.replace(/\$this/g, `[data-${attr}="${count}"]`)

      style += css

      count++

    } else {

      tag[i].setAttribute(`data-${attr}`, '')

    }

  }

  return style

}

Techniques Capable