Search code examples
javascriptmedia-queriesvue.jsenquire.js

Enquire.js does not match initially, only on resize


I'm doing media queries with Enquire.js and Vue.js. It all pretty much works when I resize the browser's window manually. However, I get no match on document load, an odd behavior that is most obvious when switching Chrome's toggle device mode on or when accessing the site on a mobile phone. I checked with the "Match & Unmatch Example", and it works as expected in said mode or when accessing it with a mobile phone. I wonder if there's some sort of incompatibility between Vue.js and Enquire.js or am I doing something wrong?

The logic for the media queries is on my vue instance's ready hook:

ready:
    function () {
        var self = this;
        enquire.register("screen and (max-width: 400px)", {
            match: function () {
                self.displayIsLarge = false;
                self.displayIsSmall = true;
            },
            unmatch: function () {
                self.displayIsLarge = true;
                self.displayIsSmall = false;
            }
        })
    );

On my vue instance, I've the following data properties:

var menu = new Vue({
el: '#app',
data: {
    displayIsLarge: true,
    displayIsSmall: false,

On my html file, I'm using v-if="displayIsSmall" and v-if="displayIsLarge" to hide/display elements according to the browser's size. JsdFiddle here.

It came to my mind in the meanwhile, that I might be able to solve this issue with the Setup callback, perhaps with a conditional, something like this:

enquire.register("screen and (max-width: 400px)", {
    setup: function() {
        if (this.match) {
            self.displayIsSmall = true;
        }
        else {
            self.displayIsSmall = false;
        }
    },
    match: function () {
        self.displayIsLarge = false;
        self.displayIsSmall = true;
    },
    unmatch: function () {
        self.displayIsLarge = true;
        self.displayIsSmall = false;
    }
})

This is not working as expected. What am I missing? JsdFiddle here.


UPDATE

No luck either with Vue's beforeCompile or created hooks (instead of ready).


Solution

  • The unmatch only happens if you go from match to unmatch. Therefore it won't happen till you go under 400px then back over it. I recommend you take a mobile first approach and do something like this instead.

    new Vue({
      el: '#app',
      data: {
        displayIsLarge: false,
        displayIsSmall: true
      },
      ready: function () {
        var self = this;
        enquire.register("screen and (min-width: 400px)", {
            match: function () {
                self.displayIsLarge = true;
                self.displayIsSmall = false;
            },
            unmatch: function () {
                self.displayIsLarge = false;
                self.displayIsSmall = true;
            }
        })
      }
    })
    

    Here's a small demo: https://jsfiddle.net/crswll/uc7gaec0/

    Though, depending on what these elements are actually containing and/or doing it probably makes more sense to just toggle them visually with CSS. You know what's going on better than me, though.