Media Query scss breakpoints best practice
Asked Answered
G

5

20

I have a bit of a brawl with my team leader about the usage of media queries. There are 2 methods (from what i can tell) about using media queries.

Method 1:

@media only screen and (max-width: 600px) {
  .container {
    width: 100%;
  }
}

@media only screen and (min-width: 600px) {
  .container {
    width: 90%;
  }
}

@media only screen and (min-width: 768px) {
  .container {
    width: 80%;
  }
}

Method 2:

.container {
  @media only screen and (max-width: 600px) {
    width: 100%;
  }

  @media only screen and (min-width: 600px) {
    width: 90%;
  }

  @media only screen and (min-width: 768px) {
    width: 80%;
  }
}

I'm a junior developer and I find it easier to use and understand the second method. Yet my Boss tells me to use the first method. To be honest, I've looked everywhere for an example project that use the second method that I like, but couldn't find!

So my question is why?

In my opinion if I want to add some class to wrap the container in this example, in method 1 I need to add it in every single breakpoint, while in method 2 I just need to add it one time! So how is the first method is the right practice? what am I missing?

Gt answered 23/6, 2020 at 6:52 Comment(2)
Method 2 is not valid CSS, so it won't work anywhere.Nonstriated
@Nonstriated - incorrect. That is valid CSS : caniuse.com/mdn-css_at-rules_media_nested-queriesBoldfaced
R
14

I think this is a great question and I often feel like the divide is caused by old school coders who are used to life before SASS and refuse to move into the new age of SASS and nested CSS.

Method 1

Pros

You can put every media query for a break point into a single place so it's easier to find an diagnose when you want to make multiple changes to a page template.

Cons

It's messy and you end up with multiple class declarations all over the place, so when it comes to editing one element or adding a new element into the HTML you end up having to edit CSS across multiple areas which is harder to track.

It involves a hell of a lot of scrolling up and down to find the media query in question and then edit that single class element.

Method 2 — Jamie Murphy calls this paradigm Media Query Bubbling analogous to Modular CSS techniques like Block__Element--Modifier (BEM)

Pros

Everything is kept together in one place, it's easy to see to find a class and edit all of the breakpoints that are used in it.

It's also possible to quickly add new breakpoints to apply quick fixes

It's also easier to read and understand at a quick glance.

Cons

Old school developers may not like it!!

Sometimes it's not good. If you have a fixed template and you know it's not going to change. Putting the entire CSS for the whole page or area makes it a lot easier to work with. You can edit multiple classes for a single breakpoint all in one place.

Conclusion

It depends on the situation. I don't think that it's a my way or the highway type of scenario, its a mixture of both.

When building components you often want to keep the CSS in one block like in Method 1. But when you're diagnosing a whole site that's been put together and are inserting single breakpoints for specific elements, it starts to make more sense using Method 2.

I've found that the more sites we create the more I've become adept at figuring out what method is best for that situation and the rules above tend to guide me in the right direction.

Roseline answered 23/6, 2020 at 8:52 Comment(2)
Great writeup of the pros/cons of the methods per se and also for stating the scenarios where which method shines.Karleen
Method 2 is called Media Query Bubbling by Jamie Murphy. Analogous to Modular CSS techniques like Block__Element--Modifier (BEM).Karleen
I
7

very nice question, and I think this deserves a whole topic, and this answer contributes to all things @Unbranded has shared.

I don't think there's a right or wrong here when it comes to the decision between which one is better or best practice. Sticking to one doesn't mean it's all correct, it's all about the approach the Styling guy get used to, and the most important part is how it was used, make or break is all laying here.

I guess you've already known and familiar with the final compiled CSS of those 2 methods, of course the final bundle size will also be a consideration factor in term of optimizing.

This is where Method 2 seems to lose its point.

Method 2 SCSS:

.container {
  width: 100%;
  
  @media screen and (min-width: 768px) {
    width: 50%;
  }

  &.red {
    @media screen and (min-width: 768px) {
      background: red;
      width: 75%;
    }
  }
}

and this is how the above CSS will be compiled, you clearly might see the duplicated string. Scaling up to a real project, this will likely be a thing to consider.

Method 2 CSS:

.container { width: 100%; }

@media screen and (min-width: 768px) {
  .container {
    width: 50%;
  }
}
@media screen and (min-width: 768px) {
  .container.red {
    background: red;
    width: 75%;
  }
}

M1 you will mostly see in old projects, might be back to before 2015, and probably each responsive query will be in a separate file. For example:

responsive.mobile.scss

@media screen and (max-width: 768px) {
  // All the stuff
}

responsive.tablet.scss

@media screen and (min-width: 768px) and (max-width: 1024px) {
  // All the stuff
}

In the past, I've dealt with a project where responsive thing like this becomes a nightmare, when you have like 4 responsive queries (plus, with retina or portrait / landscape it its own place). You've got big balls maintaining a project like this, where you won't know one change might affect the others, and for some reason your client changes his mind. In a scenario like he also wants the styling for mobile applying for portrait tablet, I believe you know where this leads to.

So, M2 saves the day.

In the modern era of web application, where things get "component-ed", I think M1 was no longer helpful, and for some reason you will see a lot of FE tutorials coming up with M2, the reason is simple. It's clean, and straight to the point. Forget about switching between responsive context, this method proves it helpfulness where FE guys adapt the way he styles.

METHOD 2 with the newbie/junior guy

And because of its simple, M2 becomes something familiar until its purpose gets wrong.

Actually, M1 is about having the style in multi places/files. Each responsive styling lies in its own file, and M2 is about styling for a component, where all the styling lies in one single place.

Think of this scenario, this also becomes a nightmare for maintaining:

Method 2 with Bad mixing of Responsive Query

.container {
  width: 100%;

  .button {
    background: red;

    @media screen and (min-width: 768px) {
      background: green;
    }
  }

  &.red {
    background: red;
    
    @media screen and (min-width: 768px) {
      background: darken(red, .15);
      width: 75%;
    }
  }
  
  @media screen and (min-width: 768px) {
    width: 50%;
  }
}

Method 2 with Good mixing of Responsive Query

.container {
  width: 100%;

  .button {
    background: red;
  }

  &.red {
    background: red;
  }
  
  @media screen and (min-width: 768px) {
    width: 50%;

    .button {
      background: green;
    }

    &.red {
      background: darken(red, .15);
      width: 75%;
    }
  }
}

The first block is what someone new would try M2 at first attempts, not recognizing the final result. The example just comes with one single media query, think of multi queries.

Of course the second one is someone who has experienced styling with M2 , it's clear and easier to maintain.

Personally, I'm the guy who used to work with M1, now completely switching to M2 in my works. Most of my project styling comes at a ratio of 7:3, where 70% M2 is applied for specific components, and 30% M1 is applied globally / generic styling. I found this works for the best. Not mentioning that now we've also had JCSS or styled-components come into the game.

As mentioned, your team leader might be a guy who used to seeing CSS in Method 1, and he had his points. And this totally depends on your particular project scope, which method might works better than the other.

Iridis answered 23/6, 2020 at 11:17 Comment(0)
S
2

I've made a useful helper mixin just for that.

$break-points: (
  mobile:     480px,
  tablet:     720px,
  desktopS:   960px,
  desktop:   1240px,
  desktopHD: 1920px
);

/** Helper to build @media query. Use named arguments only! */
@mixin breakpoint-range($mode: screen, $from: false, $to: false, $extra: ()) {
  /** Checking arguments consistency */
  @each $key in ($from, $to) {
    @if $key and not map.has-key($break-points, $key) {
      @error "Available values for ($from, $to) args are: #{map.keys($break-points)}";
    };
  };

  /** Accumulator */
  $conditions: $mode;

  /** Combining breakpoints dependencies */
  @each $key, $value in (
    min-width: $from,
    max-width: $to,
  ) {
    @if $value {
      $modifier: if($key == 'max-width', -1px, 0px);
      $condition: " and (#{$key}: #{map.get($break-points, $value) - $modifier})";
      $conditions: string.insert($conditions, $condition, -1);
    }
  }

  /** Combining rest dependencies */
  @each $key, $value in $extra {
    $condition: " and (#{$key}: #{$value})"
  }
  
  /** Building final media query */
  @media #{$conditions} { @content; }
}

And the usage:

.element {
  /** Both bp arguments */
  @include breakpoint-range($from: mobile, $to: desktop) {
    /* Result: @media screen and (min-width: 480px) and (max-width: 1240px) */
  }
  /** One bp argument */
  @include breakpoint-range($to: desktop) {
    /* Result: @media screen and (max-width: 1240px) */
  }
  /** Just changing view mode */
  @include breakpoint-range($mode: print) {
    /* Result: @media print */
  }
  /** Or add anything else */
  @include breakpoint-range(
    $from: mobile, 
    $to: desktop, 
    $extra: (orientation: landscape)
  ) {
    /* Result: @media screen 
                  and (min-width: 480px) 
                  and (max-width: 1240px)
                  and (orientation: landscape)
    */
  }
}
Synaesthesia answered 2/5, 2021 at 7:23 Comment(2)
It's better to use $mode parmeter to the third because is less usable than $from and $to parameters, by default.Choice
From online documentation of sass, following functions needs to change to work like a charm. map.has-key to map-has-key, map.keys to map-keys, map.get to map-get and finally, string.insert to str-insert.Choice
M
1

i like to use it as a mixin

@mixin handset-portrait() {
  @media screen and (max-width: 599.98px) and (orientation: portrait) {
    @content;
  }
}

// usage

.responsive {
  width: 100vw;
  @include handset-landscape() {
    width: 50vw;
  }
}

breakpoint is curtesy of @angular/cdk
content block sass-lang

Mullock answered 8/9, 2022 at 19:50 Comment(0)
B
0

There is 1 reason and 1 reason alone to preference the first method over the second. Backwards compatibility.

https://caniuse.com/mdn-css_at-rules_media_nested-queries

And on that point, unless you have to go back pre-2015 support, it's not worth it because the second way is indeed easier to write / understand. Which is why they put support in the official spec in the first place.

However there is also another benefit to writing it the second way.

In your example, notice in the second method .container class does not have to be repeated.

While it may seem trivial in this example, extrapolate. Imagine 2 stylesheets with hundreds or even thousands of classes, one uses exclusively method 1 and the other method 2.

Question: Given one way uses demonstrably less characters to achieve the same result, which one has the smaller file size? Thus potentially faster load time? Thus better UX?

Boldfaced answered 13/5, 2021 at 7:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.