Tutorial

How To Implement Responsive Design in Vue.js with vue-mq

Vue.js

Introduction

Responsive design is a frequently desired feature for web applications. As developers, we have to support a variety of devices and screen sizes. CSS is a great tool for simple use-cases and very efficient performance-wise. However, managing complex media queries may become burdensome even with the use of preprocessors (SASS, PostCSS, LESS, etc.).

Thanks to the MatchMedia API, Vue.js can greatly reduce the complexity of handling media queries and responsive design. It provides seamless integration with a component-based architecture, keeping a clean declarative and semantic approach.

In this article, you will explore features available to the vue-mq plugin for media queries.

Prerequisites

If you would like to follow along with this article, you will need:

Warning: This plugin relies on the matchMedia API to detect screen size changes. So, for older browsers and Internet Explorer, you should utilize Paul Irish’s matchMedia polyfill

This tutorial was verified with Node v15.8.0, npm v7.5.4, Vue v12.6.11, and vue-mq v1.0.1.

Using vue-mq

First, to use vue-mq, open your terminal and navigate to your existing Vue project directory. Then, run the following command:

  • npm install vue-mq@1.0.1

Next, with your code editor, edit your Vue project and import the library:

import VueMq from 'vue-mq'

Define your custom breakpoints when registering the plugin. Keys are breakpoints and values are in pixels:

Vue.use(VueMq, {
  breakpoints: {
    sm: 450,
    md: 1250,
    lg: Infinity,
  }
})

In this example, three breakpoints are defined. sm for “small screens”. md for “medium screens”. lg for “large screens”.

You can also name your breakpoints after devices or anything that make sense to you:

Vue.use(VueMq, {
  breakpoints: {
    mobile: 450,
    tablet: 900,
    laptop: 1250,
    desktop: Infinity,
  }
})

In this example, four breakpoints are defined. A mobile, tablet, laptop, and desktop screen size.

Using vue-mq with Conditional Rendering

Very often when dealing with responsive design you will want to render elements conditionally.

For instance, display a specific menu for mobile devices only.

In order to accomplish that functionality, you can use the reactive $mq property which is accessible inside each instance of a component. Its value will always be the current breakpoint.

<template>
  <mobile-menu v-if="$mq === 'mobile'"></mobile-menu>
</template>

This component will render when the current screen size satisfies the conditional. If you defined the breakpoint for “mobile” to be 450 pixels, this component will render for screen sizes up to 450px.

vue-mq also provides a shorthand for this syntax with a global mq-layout component that acts as a conditional slot:

<template>
  <mq-layout mq="mobile">
    <mobile-menu></mobile-menu>
  </mq-layout>
  <mq-layout mq="tablet+">
    <desktop-menu></desktop-menu>
  </mq-layout>
</template>

Notice the plus sign (+) after the “tablet” breakpoint name. This instructs vue-mq to target the breakpoint and all the larger breakpoints as well.

Using vue-mq with Prop Values

Another very common use-case is the computation of different values based on screen size.

For example, let’s say you want to display a responsive grid of items:

  • on mobile you want 2 columns
  • on tablets you want 3 columns
  • on laptops you want 4 columns

In other words, you just have to pass down a prop with different values according to screen size to the exact same grid component. It will have the responsibility to display the right number of columns.

vue-mq provides a global filter for mapping breakpoints to values, using declarative rules:

<template>
  <grid-component :column="$mq | mq({
    phone: 2,
    tablet: 3,
    laptop: 4
  })">
  </grid-component>
</template>

Keep in mind that this plugin is enforcing a mobile-first approach. Values will default to the closest smaller breakpoints value if not defined explicitly.

If you omitted the “tablet” rule (tablet: 3), it will fall back to the “phone” rule for “tablet” screen sizes and display 2 columns.

In the same way, if you need values that are more complex, move it in a computed prop:

<template>
  <responsive-title>{{ displayText }}</responsive-title>
</template>

<script>
export default {
  computed: {
    displayText() {
      return this.$mq === 'mobile'
      ? 'You are on a mobile device'
      : 'You are on a larger device'
    }
  }
}
</script>

This code will display "You are on mobile device" or "You are on a larger device" depending on your screen size.

Using vue-mq with Responsive Classes

Sometimes, you also want to change style quickly via CSS. The trick is to use a breakpoint name as a computed class on the element you want to style.

Here is an example with a Single-File Component:

<template>
  <h1 class="responsive-title" :class="$mq">
    Responsive Title
  </h1>
</template>

<style>
  .responsive-title.mobile { font-size: 1em; }
  .responsive-title.desktop { font-size: 3em; }
</style>

This code will add a “mobile” or “desktop” class to the element depending on your screen size.

Applying Other Libraries

Here are some ideas for advanced usage in combination with other libraries:

Conclusion

In this article, you explored features available to the vue-mq plugin for media queries.

vue-mq offers shorthands for common use-cases while its flexibility lets you compose with media queries as you like.

If you’d like to learn more about Vue.js, check out our Vue.js topic page for exercises and programming projects.

Creative Commons License