CSS Media queries in Magento 2

It’s highly unlikely that there are some frontend developers involved in a responsive website development who are not familiar with the concept of CSS Media queries. In this post, I’ll be looking at Magento 2 way of implementing this functionality in its default theme development workflow.

How do Magento 2 media queries work?

In the heart of Magento 2 media queries mechanism, defined in Magento UI library, is a .media-width() mixin.

.media-width(<@extremum>, <@break>);

@extremum: max|min – sets whether to use min-width or max-width in media query condition

@break: value – sets the value of breakpoint to compare with in media query condition

We can see the practical use of it in the following example:

// In .less file
.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) {
your styles
}
 
// After compilation, in .css file
@media only screen and (max-width: 640px) {
your styles
}

This mixin, which is used for grouping style rules in certain media queries, can be used whenever you need it, in any .less file in your theme. In the end, it will be invoked only once – in lib/web/css/source/lib/_responsive.less file.

If you check the end product of .less files compilation, styles.css file, you’ll see there each media query with all its rules only once, so there are no a multiple calls for the same query.

Default settings

By default, media queries are outputting styles in two different files:

1. styles-m.less – which generates basic and mobile-specific styles

2. styles-l.less – generates desktop-specific styles (for 768px width screen and higher)

This means that, when the website is opened on a mobile device, it will load only styles compiled from the styles-m.less file. Extra styles from the second file (styles-l.less) are compiling and loading only if the screen width is 768px or higher.

For this style groups separation, special variables @media-target and @media-common are used:

// For targetting device for styles output
@media-target: all|desktop|mobile
 
// In practice
& when (@media-target = 'mobile'), (@media-target = 'all') {
@media only screen and (max-width: (@screen__xs - 1)) {
.media-width('max', @screen__xs);
}
}
 
// For deciding whether to output common styles.
@media-common: true|false
 
// Adding common styles
& when (@media-common = true) {
your styles
}

Out of the box, Magento UI library has a set of predefined variables for breakpoints. We can use them in any case we need them and they can be changed or extended them with a new ones:

  • 320px
  • 480px
  • 640px
  • 768px (breakpoint for switching between mobile and desktop views)
  • 1024px
  • 1440px

Custom breakpoints

Quite often, we’ll find ourselves in a situation where we’ll need to add an additional breakpoint (apart from default ones) in which we can apply a different styling. There are three things which need to be done in order to add a custom breakpoint in our theme.

1. Define a variable for the new breakpoint.

First, we’ll have to create a /web/css/source/variables.less file. If we would use a standalone theme, this file would be new and empty. But, since we’re following the best practice (inheriting from Magento Blank theme), we’ll have to copy this file from our parent theme.

Here we can define our custom breakpoint:

@custom__breakpoint: 1280px;

2. Implement our new breakpoint

To do so, we’ll override _responsive.less file from Magento UI library by copying it to our theme in /web/css/source/lib/. Now, in our theme’s _responsive.less file we have to edit .media-width() mixin by adding the appropriate rule for the new custom breakpoint.

& when (@media-target = 'desktop'), (@media-target = 'all') {
@media all and (min-width: @custom__breakpoint) {
.media-width('min', @custom__breakpoint);
}
}

3. Implement the screen changes for the new breakpoint.

If everything is set properly, we should be able call our new .media-width() mixin whenever we need it in our theme .less files.

.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @custom__breakpoint) {
// Stlying applied at @custom__breakpoint breakpoint
}

A small helper

In the end, to wrap things up, I’ll give you some quick jump-start piece of code; media queries which you can quickly apply, depending on which screen size you’d like to target.

// Common
// (for styles used in both mobile and desktop views)
& when (@media-common = true) {}
 
// Mobile
// (for all mobile styles.)
.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {}
 
// Tablet
.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
 
// Desktop
.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__l) {}

Thank you for reading!