<main>
  <div class="cqw"><div class="cq cq1"></div></div>
  <div class="cqw"><div class="cq cq2"></div></div>
  <div class="cqw"><div class="cq cq3"></div></div>
  <div class="cqw"><div class="cq cq4"></div></div>
</main>
body {
  margin: unset;
}
main { 
  display: flex;
  flex-wrap: wrap;
}

.cq {
  aspect-ratio: var(--asr, 1);
  background-color: var(--bgc,silver);
  height: 120px;
  width: var(--w, 25vw);
}
.cqw {
  contain: layout inline-size;
}

.cq1 { --bgc: tomato }
.cq2 { --bgc: orange }
.cq3 { --bgc: skyblue }
.cq4 { --bgc: tan; }

@container (min-width: 300px) { .cq { --asr: 2/1; } }
@container (min-width: 300px) { .cq1 { --bgc: indianred; } }
@container (min-width: 300px) { .cq2 { --bgc: darkorange; } }
@container (min-width: 300px) { .cq3 { --bgc: steelblue; } }
@container (min-width: 300px) { .cq4 { --bgc: lavender; } }

@media (min-width: 600px) { .cq { --w: 50vw; } }
@media (min-width: 900px) { .cq { --w: 25vw } }
/*
Article about this polyfill here:
https://dev.to/madsstoumann/container-queries-another-polyfill-2488
*/
if (!('CSSContainerRule' in window)) {
  const cq = (rules) => {
    let match;
        let observe = new Set();
        const re = /@container\s?\(min-width:\s?(?<breakpoint>.*)px\)\s?\{\s?(?<selector>.*)\s?\{\s?(?<css>.*;)\s?\}/gm
        while (match = re.exec(rules)) {
          [...document.querySelectorAll(match.groups.selector)].forEach(elm => {
            elm.__cq = elm.__cq || { bp: [], css: [], index: -1 }
            const bp = match.groups.breakpoint-0;
            const css = match.groups.css;
            const index = elm.__cq.bp.findIndex(item => item === bp);
            if (index < 0) {
              elm.__cq.bp.push(bp);
              elm.__cq.css.push(css);
            }
            else {
              elm.__cq.css[index] = elm.__cq.css[index].concat(css);
            }
            observe.add(elm);
          })
        }
    for (let item of observe) RO.observe(item);
  }
  const findLastIndex = (items, callback) => items.reduce((acc, curr, index) => callback(curr) ? index : acc, -1);
  const RO = new ResizeObserver(entries => {
    for (let entry of entries) {
      const elm = entry.target;
      const cq = elm.__cq;
      const lastIndex = findLastIndex(cq.bp, item => item <= entry.contentRect.width);
      if (lastIndex !== elm.index) {
        elm.style.cssText = cq.css.filter((item, index) => index <= lastIndex).join('');
        cq.index = lastIndex;
      }
      else if (lastIndex === -1) elm.removeAttribute('style');
    }
  });

  /* Process <style>-tags */
  document.querySelectorAll('style').forEach(style => cq(style.innerHTML));
  /* Process external style-sheets */
  [...document.styleSheets].map(sheet => {
    fetch(sheet.href)
      .then(css => css.text())
      .then(rules => {
        cq(rules);
      }
    )
  })
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.