Nicolas Bouvrette
Nicolas Bouvrette

Reputation: 4767

How to use EMs in CSS Media Queries aligned with JavaScript events?

I have been working on a project for a while and I thought that using em was the de facto unit when it came to expressing length.

The way I usually proceed is to set the body and html elements to the desired px size and all the other elements to 1em. After that the rest is all in em. Until this morning this seemed like a good plan, until I found out that media queries don't seem to take in account the base body and html px value. They seem in fact to take the browser's default font-size which seems to be a very odd behavior. I also found this article which seems to confirm this.

I have done a small JsFiddle example which shows exactly this behavior:

https://jsfiddle.net/5dq3kq2t/2/

html, body {
    font-size: 20px;
}

* {
  font-size: 1em;
}

#divOf50Em {
  width: 50em;
  border: solid 1px red;
}

#cell2 {
  display: none;
}

@media screen and (min-width: 50em) { /* 1000px, in theory (50 * 20px) */
  #cell1 {
    display: none;
  }

  #cell2 {
    display: table-cell;
  }

}

The experiment is simple, the table by default show the value "1" until the 50em min-width media size has been met. the the value "2" should display. I also placed a div which size is 50em to show when the behavior should be triggered and also to confirm that the CSS works outside of media queries.

If you resize the output of this experiment, you would expect that the shift between the two values would happen at a 1000px value which is 50em * 20px, but it does not, it happens at 800px which is 50em * 16px (the default browsers font-size - if this is your default size of course).

I'm clearly unsure of why this happens but I have two questions:

  1. Is there a way around this (e.g. overwrite default browser font-size from a CSS perspective)
  2. If not, is there a way in JavaScript to access the browser's default font size? I was unable to find this information.

Otherwise it looks like having a script which would be aligned with media queries for some behaviors is impossible when using media width and ems since we cannot rely that the browser's font size will always be 16px.

Then if this is the case, my last question would be, is there a way to align media queries and JavaScript without going back to pixels? I prefer relative units over static pixels, they usually make styling much simpler.

Upvotes: 3

Views: 362

Answers (2)

guest271314
guest271314

Reputation: 1

A possible workaround is to set the media query at load event of window by getting the font-size of a child node of body using getComputedStyle

:root, body {
    --size: 20px;
    --opt: 50rem;
    --def: 1rem;
    font-size: var(--size);
}

* {
  font-size: var(--def);
}

#divOf50Em {
  width: var(--opt);
  border: solid 1px red;
}

#cell2 {
  display: none;
}

window.onload = function() {
  document.getElementById('documentWidth').innerHTML = 'Window width: ' 
    + document.documentElement.clientWidth + 'px';

  var n = 50;

  var fontSize = parseInt(getComputedStyle(document.getElementById("divOf50Em"))
                 .getPropertyValue("font-size"));

  var css = `@media screen and (min-width:${fontSize * n}px) { 
               /* 1000px, in theory (50 * 20px) */
               #cell1 {
                 display: none;
               }

               #cell2 {
                 display: table-cell;
               }
             }`;

  var style = document.createElement("style");
  style.textContent = css;
  document.head.appendChild(style);

  window.addEventListener('resize', function() {
    document.getElementById('documentWidth').innerHTML = 'Window width: ' +
      document.documentElement.clientWidth + 'px';
  });
}

plnkr http://plnkr.co/edit/lncvWwBWc18C76UYhPnf?p=preview

Upvotes: 0

Nicolas Bouvrette
Nicolas Bouvrette

Reputation: 4767

After more research,

  1. It looks like there is no way around overwriting the 1em value = browser default font-size in pixel either in CSS or JavaScript.
  2. Media queries are referring to the browser, not HTML elements which seems to be the normal/expected behavior.
  3. It is possible to get the browser's default font-size in pixel by using JavaScript which I will not attempt considering it would only be a stop gap.
  4. A true solution would require all media queries to be overwritten by JavaScript which would become quite heavy and hard to scale.
  5. Using other units might solve some challenge but would cause cross-browsers compatibility problems to this day.

Upvotes: 1

Related Questions