响应式设计和断点

优质
小牛编辑
134浏览
2023-12-01

无需在此对响应式网页设计多做介绍,它已经无所不在了。但是你可能会疑惑:为什么在 Sass 样式指南中会有关于响应式网页设计的章节?正因为有诸多降低断点使用难度的方式,所以我认为在这里列出来会是个不错的主意。

命名断点

我认为使用媒体查询而不针对特定设备是安全可靠的做法。特别要指出的是,不应该赞成专门针对 iPad 或黑莓手机设计媒体查询。媒体查询应该关注屏幕尺寸,直到当前设计遇到阻断而将所有工作过继给下一个媒体查询。

与之相同的观点是,断点不应该用设备来命名,而应使用更通用的方式。特别是,现在有一些手机比平板更大,而有一些平板比电脑更大……

// Yep
$breakpoints: (
  'medium': (min-width: 800px),
  'large': (min-width: 1000px),
  'huge': (min-width: 1200px),
);

// Nope
$breakpoints: (
  'tablet': (min-width: 800px),
  'computer': (min-width: 1000px),
  'tv': (min-width: 1200px),
);
// Yep
$breakpoints: ('medium': (min-width: 800px), 'large': (min-width: 1000px), 'huge': (min-width: 1200px))

// Nope
$breakpoints: ('tablet': (min-width: 800px), 'computer': (min-width: 1000px), 'tv': (min-width: 1200px))

就此来说,任何不与特定设备关联而表达清晰的命名约定,都会因其广泛的通用性获得认可。

$breakpoints: (
  'seed': (min-width: 800px),
  'sprout': (min-width: 1000px),
  'plant': (min-width: 1200px),
);
$breakpoints: ('seed': (min-width: 800px), 'sprout': (min-width: 1000px), 'plant': (min-width: 1200px))

上面的示例使用了嵌套的 map,但这并不是强制或绝对的,你完全可以使用字符串来代替(比如 '(min-width: 800px)')。

断点管理器

一旦用自己钟意的方式命名完断点,就需要有一种方式在实际的媒体查询中使用它。有太多方法可以做这件事,我自己非常乐意使用 map-get() 函数读取断点地图的方法。这套系统简洁而高效。

/// Responsive breakpoint manager
/// @access public
/// @param {String} $breakpoint - Breakpoint
/// @requires $breakpoints
@mixin respond-to($breakpoint) {
  $raw-query: map-get($breakpoints, $breakpoint);

  @if $raw-query {
    $query: if(
      type-of($raw-query) == 'string',
      unquote($raw-query),
      inspect($raw-query)
    );

    @media #{$query} {
      @content;
    }
  } @else {
    @error 'No value found for `#{$breakpoint}`. '
         + 'Please make sure it is defined in `$breakpoints` map.';
  }
}
/// Responsive breakpoint manager
/// @access public
/// @param {String} $breakpoint - Breakpoint
/// @requires $breakpoints
=respond-to($breakpoint)
  $raw-query: map-get($breakpoints, $breakpoint)

  @if $raw-query
    $query: if(type-of($raw-query) == 'string', unquote($raw-query), inspect($raw-query))

    @media #{$query}
      @content

  @else
    @error 'No value found for `#{$breakpoint}`. '
         + 'Please make sure it is defined in `$breakpoints` map.'

更多有关 Sass 中媒体查询的信息,请参考 SitePointCSS-Tricks 中优秀的实践文章。

媒体查询用法

就在不久之前,有一个关于应该在哪里书写媒体查询的热门讨论:媒体查询是应该与选择器写在一起(Sass 允许这种方式),还是要彻底地分离开?我想说我是媒体查询紧贴选择器方式的狂热捍卫者,并且认为这会和组件一样表现得很棒。

.foo {
  color: red;

  @include respond-to('medium') {
    color: blue;
  }
}
.foo
  color: red

  +respond-to('medium')
    color: blue

生成结果:

.foo {
  color: red;
}

@media (min-width: 800px) {
  .foo {
    color: blue;
  }
}

可能你已经了解到,这种习惯会导致 CSS 输出文件中出现重复的媒体查询语句。不过测试了和下面的话认为一旦 Gzip(或者其他相同软件)完成压缩就不会有什么问题:

……我们反复测试了贴合与分离两种媒体查询方式对性能的影响,结论是即使在最差情况下也没有明显差异,而在最好情况下差异更是少之又少。
— Sam Richards 关于Breakpoint 的看法

如果现在你仍担心媒体查询的副本问题,你可以使用工具来合并它们,比如这个 gem,但是我有必要警告你移动相关 CSS 代码可能会有副作用。 是否了解资源顺序是非常重要的。