The EQCSS plugin is designed to re-evaluate the responsive conditions and recalculate the CSS contained within EQCSS styles as often as the page needs it. In order to do this automatically EQCSS adds event listeners to watch a number of events.

Currently EQCSS listens to the following events:

  • domReady (via polyfill)
  • resize
  • input
  • click
  • mousemove (if mouse is down)
  • mouseup
  • scroll (if a min/max scroll x/y condition is set on that element)
  // Call load (and apply, indirectly) on page load
EQCSS.domReady(function(){
  EQCSS.load();
  EQCSS.throttle();
});

// On resize, scroll, input, click, mousedown + mousemove, call EQCSS.throttle.
window.addEventListener("resize", EQCSS.throttle);
window.addEventListener("input", EQCSS.throttle);
window.addEventListener("click", EQCSS.throttle);
window.addEventListener("mousedown", function(){
  EQCSS_mouse_down = true;
});
window.addEventListener("mouseup", function(){
  EQCSS_mouse_down = false;
  EQCSS.throttle();
});
window.addEventListener("mousemove", function(){
  if(EQCSS_mouse_down){
    EQCSS.throttle();
  }
});

On any of these events EQCSS will re-evaluate the responsive conditions it's watching, and if an element meets a condition, it will calculate the CSS contained within that @element query and apply it to the page.

Because EQCSS is listening to these events, it is unlikely for most web pages that we will need to trigger a re-evaluation and recalculation manually, but if we need to inform EQCSS to listen to more events, or we need to trigger an EQCSS recalcuation there are two options available:

Manually Triggering EQCSS

There are two functions inside EQCSS that can trigger a recalculation:

  • EQCSS.apply()
  • EQCSS.throttle()

Originally when EQCSS was built it would recalculate immediately using EQCSS.apply() when these events happened - but in early 2016 changes to Firefox created sluggish pages (due to over-enthusiastic recalculation). A new function called EQCSS.throttle() was created to throttle the recalculation of the styles if requests were being made too fast. The threshold for the debounce is set to 200ms.

  /* EQCSS.throttle
Ensures EQCSS.apply() is not called more than once every (EQCSS_timeout)ms
*/

var EQCSS_throttle_available = true;
var EQCSS_throttle_queued = false;
var EQCSS_mouse_down = false;
var EQCSS_timeout = 200;

EQCSS.throttle = function(){
  if(EQCSS_throttle_available){
    EQCSS.apply();
    EQCSS_throttle_available = false;
    setTimeout(function(){
      EQCSS_throttle_available = true;
      if(EQCSS_throttle_queued){
        EQCSS_throttle_queued = false;
        EQCSS.apply();
      }
    }, EQCSS_timeout);
  }
  else{
    EQCSS_throttle_queued = true;
  }
}

What this means is that if you send EQCSS.apply() to JavaScript it will trigger an instant recalculation, but if you send EQCSS.throttle() it will wait 200ms and then apply EQCSS. If you sent triggered EQCSS.throttle() hundreds of times within 200ms it would only execute 1 time, and then reset the counter and be ready to begin counting down to execute in another 200ms after that.

Adding Your own Triggers

Suppose you need to add your own event listener to recalculate EQCSS when an event happens, here are two ways you could do that - one to recalculate EQCSS immediately with EQCSS.apply(), and a second to trigger a lazy recalculation with EQCSS.throttle()

Suppose we have a website where there's a hashchange event that happens totally independent from any of the other events the EQCSS plugin is watching (like click or input). In that case you could write a new event listener like one of these:

  // recalculate EQCSS immediately
window.addEventListener('hashchange',EQCSS.apply)

// throttled request to recalculate EQCSS
window.addEventListener('hashchange',EQCSS.throttle)

Triggering EQCSS's Global Functions from Inside JavaScript Modules

As of version 1.4.0 of the plugin, the entire thing is built like a polyfill, or a shim - something intended to be very small, run in the global scope, almost like a browser plugin, instead of a javascript plugin. Think of it like the Typekit javascript, or something you need to add to your website one time and you're set.

For this reason, most EQCSS users include a link to a CDN-hosted copy of EQCSS in their HTML and are done. However many users also work with JavaScript module systems and desire a way to include EQCSS inside their frontend workflow (using webpack, other builders, and calling EQCSS.apply() and EQCSS.throttle() from their own components and modules).

For some worflows this can provide a challenge as EQCSS is not formatted as a module (UMD, Common JS, etc), and many of these tools and workflows ensure that the JavaScript you write is quarantined away from the global scope.

What are the problems with this? Well first is that if you're trying to import EQCSS's code (intended for the browser) through your server-side JavaScript workflow, some tools will break or refuse to work with EQCSS's code because it uses with() to power the $it meta-selector, and that's a JavaScript feature that exists only in browsers and not in the server environment.

The second is that in some frameworks users find that referencing EQCSS.apply or EQCSS.throttle returns undefined. It may be possible that the framework or tool you are using has a way to allow you to access functions running in the global scope (React will let you prepend it with window to access them at window.EQCSS.apply() and window.EQCSS.throttle()) but how this works may be different for each framework and workflow.

In the future we are looking to package up the EQCSS plugin in a way that allows it to be loaded by module loaders like Node or webpack, without losing the ability to run independently as a plugin if loaded directly in the browser.

Animating EQCSS recalculations

Here's another example of something you might need to do. In this example we have a button that adds an .active class to an element, and the width is animated over 2s using a CSS transition. We also have a height powered by an EQCSS style. By default, the animation won't be very smooth:

  <input type=button value=toggle onclick="
  var div = document.querySelector('div')
  div.classList.toggle('active')
">
<div></div>
<style>
  div {
    width: 50px;
    background: lime;
    transition: width 2s ease-in-out;
  }
  .active {
    width: 200px;
  }
  @element 'div' {
    $this {
      height: 100ew;
    }
  }
</style>
<script src=http://elementqueries.com/EQCSS.js></script>

For a smoother transition you would need to continuously recalculate EQCSS for a specified duration of time. You could make a helper function in JavaScript that takes a given duration (in ms) during which you want to recalculate EQCSS, and run EQCSS.apply() continuously for the duration you need.

Here I've added requestAnimationFrame(animation.go) that runs at the same time our class gets added and is uses the function in the animation object down below.

  <input type=button value=toggle onclick="
  var div = document.querySelector('div')
  div.classList.toggle('active')
  requestAnimationFrame(animation.go)
">
<div></div>
<style>
  div {
    width: 50px;
    background: lime;
    transition: width 2s ease-in-out;
  }
  .active {
    width: 200px;
  }
  @element 'div' {
    $this {
      height: 100ew;
    }
  }
</style>
<script>
  var animation = {
    start: 0,
    duration: 2000,
    active: false,
    go: function(){
      if (animation.active == false){
        animation.start = performance.now()
        animation.active = true
      }
      var elapsed = Math.floor(performance.now() - animation.start)
      if (elapsed < animation.duration) {
        EQCSS.apply()
        console.log(1)
        requestAnimationFrame(animation.go)
      } else {
        animation.active = false
      }
    }
  }
</script>
<script src=http://elementqueries.com/EQCSS.js></script>

Here we have a function, animation.go() that will continuously run EQCSS.apply() for 2000ms by default, or whatever duration we give it.

Here's a demo with a choppy and smooth toggle buttons:

Further questions

If you have any further questions please feel free to join the EQCSS chat on Gitter


666 0 0