Search code examples
javascriptcssdomwindow-resize

Get the same result with ResizeObserver and media query


I have globally defined breakpoints:

breakpoints: {
  xs: "0px",
  sm: "320px",
  md: "672px",
  lg: "1056px",
  xl: "1312px",
},

I also have media queries to define the padding-top and padding-bottom, based on previous breakpoints:

@media (min-width: 672px) {
    padding-top: 2rem;
    padding-bottom: 2rem;
}
@media (min-width: 0px) {
    padding-top: 1rem;
    padding-bottom: 1rem;
}

And finally, I am using ResizeObserver to observer document.body and set the paddingLeft, for example:

const observer = new ResizeObserver(([entry]) => {
  if (entry.contentRect.width >= Number.parseInt(breakpoints.xl)) {
    document.body.style.paddingLeft = "10em"
  } else if (entry.contentRect.width >= Number.parseInt(breakpoints.lg)) {
    document.body.style.paddingLeft = "10em"
  } else if (entry.contentRect.width >= Number.parseInt(breakpoints.md)) {
    document.body.style.paddingLeft = "10em"
  } else if (entry.contentRect.width >= Number.parseInt(breakpoints.xs)) {
    document.body.style.paddingLeft = "5em"
  }
})

observer.observe(document.body)

The trouble is that the padding-top or padding-bottom (media queries) don't change at same time that the paddingLeft (ResizeObserver) and I don't know why and how to solve.

--- EDITED ---

I hope it is better understood now:

Please see jsfiddle and resize the result to see how the div change the padding-top and the paddingLeft at a different time.


Solution

  • The contentRect is the element's content box, without paddings, border, and margins. Due to the body elements's default margin: 8px; and scrollbar width, the entry.contentRect.width will be 33px less than the window width.

    16px (body margin) + 17px (scollbar width) = 33px
    

    References

    https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentRect

    https://xebia.com/blog/resize-observer-api-detecting-element-size-change/

    Alternatively, you can use MediaQueryList.onchange

    A MediaQueryList object stores information on a media query applied to a document, with support for both immediate and event-driven matching against the state of the document.

    Example with one breakpoint

    const element = document.getElementById("test");
    
    var mql = window.matchMedia('(min-width: 672px)');
    
    mql.addEventListener("change", (e) => {
      if (e.matches) {
        element.style.paddingLeft = "10em"
      } else {
        element.style.paddingLeft = "unset"
      }
    })
    

    Demo