How to update CSS variable within JavaScript matchMedia event

302 Views Asked by At

I'm using JavaScript together with a css column-width layout to calculate breakpoints at each new column in the browser window. With each new column I also increase the page margins for which I calculate a second breakpoints so they fit.

I have everything fully working using root.classList.add(myCss) and root.classList.remove(myCss) but for the page margins I would prefer to update a single css variable --page-margins instead of adding and removing css margin classes if that's possible.

In the following sample when I load the page and two columns fit in the browser window the correct --page-margin should be 16 but the Chrome inspector shows 24. It looks like when the page loads, the matchMedia event checks each media query and if it doesn't match it sets the css variable --page-margins to (cols - 1) which I only need it to do if that event previously matched.

After the page has loaded if I increase and decrease the browser width everything works correctly. One way I could achieve this is with some kind of conditional "If event unmatches..."?

document.addEventListener('DOMContentLoaded', function() {
  grid();
});

// The grid system
function grid() {

  const root = document.documentElement;
  const columnWidth = 239;
  const columnGap = 1;
  const columnMin = columnWidth + columnGap;
  const scrollbar = 20;
  let margins = parseInt(window.getComputedStyle(root).getPropertyValue('--page-margins'), 10);


  // Page margins
  const marginOne   =  8;
  const marginTwo   = 16;
  const marginThree = 24;
  const marginFour = 32;
  
  mediaQuery(2);
  mediaQuery(3);
  mediaQuery(4);
  
  // Media queries for columns
  function mediaQuery(cols) {

    let marginStyles = window.matchMedia('(min-width: ' + columns(cols)  + 'px)');
    marginStyles.addEventListener('change', addMargins);
    addMargins(marginStyles);

    function addMargins(e) {

      if (e.matches) {
        root.style.setProperty('--page-margins', setMargins(cols) + 'px');
        margins = parseInt(window.getComputedStyle(root).getPropertyValue('--page-margins'), 10);

      }
      else {
        root.style.setProperty('--page-margins', setMargins((cols - 1)) + 'px');
        margins = parseInt(window.getComputedStyle(root).getPropertyValue('--page-margins'), 10);

      }
    }

  }

  // Return the screen width (breakpoint) at num columns
  function columns(num) {
    setMargins(num);
    let breakpoint = (columnMin * num) - columnGap + (padding * 2) + scrollbar;
    return breakpoint;
  }

  // Set the margin for each column number
  function setMargins(num) {
    if (num == 4) {
      padding = marginFour;
    } else if (num == 3) {
      padding = marginThree;
    } else if (num == 2) {
      padding = marginTwo;
    } else {
      padding = marginOne;
    }
    return padding;
  }

}
1

There are 1 best solutions below

0
On

I figured it out shortly after posting. I needed to nest a second conditional inside the event's else statement that checks the value of the css variable --page-margins. The variable margins is referenced elsewhere in the script so I'm updating it when the event matches and unmatches.

Everything works.

function addMargins(e) {
    if (e.matches) {
        root.style.setProperty('--page-margins', setMargins(cols) + 'px');
        margins = parseInt(window.getComputedStyle(root).getPropertyValue('--page-margins'), 10);

    }
    else {
        if (margins == setMargins(cols)) {
            root.style.setProperty('--page-margins', setMargins((cols - 1)) + 'px');
            margins = parseInt(window.getComputedStyle(root).getPropertyValue('--page-margins'), 10);
        }
    }
}