媒体查询 scss 断点最佳实践

Media Query scss breakpoints best practice

我和我的团队负责人就媒体查询的使用问题发生了争吵。 关于使用媒体查询有 2 种方法(据我所知)。

方法一:

@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%;
  }
}

方法二:

.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%;
  }
}

我是一名初级开发人员,我发现第二种方法更容易使用和理解。但是我的老板告诉我使用第一种方法。老实说,我到处寻找使用我喜欢的第二种方法的示例项目,但找不到!

所以我的问题是为什么?

在我看来,如果我想在这个例子中添加一些class来包装容器,在方法1中我需要在每个断点中添加它,而在方法2中我只需要添加它一度! 那么第一种方法怎样才是正确的做法呢?我错过了什么?

我认为这是一个很好的问题,我经常觉得这种鸿沟是由那些习惯了 SASS 之前的生活并拒绝进入 SASS 的新时代的老派编码人员造成的并嵌套 CSS.

方法一

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.

方法二

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.

结论

视情况而定。我不认为这是我的方式或高速公路类型的场景,它是两者的混合。

构建组件时,您通常希望将 CSS 保留在一个块中,就像在 方法 1 中一样。但是,当您诊断整个站点并为特定元素插入单个断点时,使用 方法 2.

开始变得更有意义

我发现我们创建的网站越多,我就越善于找出最适合这种情况的方法,而上述规则往往会引导我朝着正确的方向前进。

非常好的问题,我认为这值得一个完整的话题,这个答案对@Unbranded 分享的所有内容都有帮助。

我认为在决定哪个更好或最佳实践之间没有对错之分。坚持一个并不意味着它就是正确的,这完全取决于造型师习惯的方法,最重要的部分是如何使用它,成败就在这里。

我想你已经知道并熟悉了这两种方法的最终编译CSS,当然最终的包大小也会是优化方面的一个考虑因素。

这就是方法 2 似乎失去意义的地方。

方法二CSS:

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

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

这就是上面的 CSS 的编译方式,您可能会清楚地看到重复的字符串。扩展到一个真正的项目,这可能是一个需要考虑的问题。

方法二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 你大多会在旧项目中看到,可能会回到 2015 年之前,并且可能每个响应式查询都在一个单独的文件中。例如:

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
}

在过去,我处理过一个项目,当你有 4 个响应式查询(加上视网膜或纵向/横向它自己的位置)时,像这样的响应式的事情变成了一场噩梦。您拥有维护这样一个项目的大人物,您不会知道一个更改可能会影响其他更改,并且由于某种原因您的客户改变了主意。像他还想要手机造型申请人像平板的场景,相信你知道这是怎么回事。

所以,M2 挽救了这一天。

在 Web 应用程序的现代时代,事情变得“组件化”,我认为 M1 不再有帮助,出于某种原因你会看到很多FE教程拿出M2,道理很简单。它很干净,开门见山。忘记在响应式上下文之间切换,这种方法证明了 FE 人员适应他的风格的方式很有用。

方法 2 与 newbie/junior 人

并且因为它的简单,M2 变得熟悉,直到它的目的出错。

实际上,M1是关于多places/files中的风格。每个响应式样式都位于其自己的文件中,M2 是关于组件的样式,其中所有样式都位于一个位置。

想到这个场景,这也成了维护的噩梦:

方法 2 与响应式查询的错误混合

.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%;
  }
}

方法 2 与响应式查询的良好混合


.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%;
    }
  }
}

第一个块是一些新手在第一次尝试时会尝试 M2,不认识最终结果。该示例仅带有一个媒体查询,请考虑多个查询。

当然第二个是用过M2样式的人,清晰易维护

就个人而言,我是以前用M1工作的人,现在我的作品完全切换到M2。我的大部分项目样式都是 7:3 的比例,其中 70% M2 用于特定组件,30% M1全局应用/通用样式。我发现这最有效。更不用说现在我们也有 JCSS 或 styled-components 进入游戏。

如前所述,您的组长可能是一个曾经在方法 1 中看到 CSS 的人,他有自己的观点。这完全取决于您的特定项目范围,哪种方法可能比另一种更好。

我专门为此制作了一个有用的帮助程序 mixin。

$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; }
}

以及用法:

.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)
    */
  }
}

第一种方法优于第二种方法有 1 个原因,也有 1 个单独的原因。向后兼容性。

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

在这一点上,除非你必须回到 2015 年之前的支持,否则这是不值得的,因为第二种方式确实更容易编写/理解。这就是为什么他们首先在官方规范中提供支持。

然而,以第二种方式编写它还有另一个好处。

在你的例子中,注意第二种方法.container class不必重复。

虽然在这个例子中看起来微不足道,但可以推断。假设 2 个样式表有数百甚至数千个 classes,一个只使用方法 1,另一个使用方法 2。

问题:给定一种方法使用明显更少的字符来实现相同的结果,哪种方法的文件大小更小?因此可能更快的加载时间?因此更好的用户体验?