Follow me on GitHub Follow me on Twitter

借助sass的Maps功能使得响应式代码更有条理

原文来自这里
本文综合了原文(by Jonathan Suh)以及笔者自己的理解。

Introduction

众所周知,写代码与写维护性高的代码是两回事.而涉及到响应式,代码又特别容易变的杂乱.借助sass maps所提供的拓扑功能,我们可以尝试减轻这一痛点.
以下的代码还是很常见的:

p { font-size: 15px; }

@media screen and (min-width: 480px) {
  p { font-size: 16px; }
}
@media screen and (min-width: 640px) {
  p { font-size: 17px; }
}
@media screen and (min-width: 1024px) {
  p { font-size: 19px; }
}

两个问题点:1.DRY, 2.Magic Number.
也许sass的变量可以解决问题2。

$p-font-size-mobile : 15px;
$p-font-size-small  : 16px;
$p-font-size-medium : 17px;
$p-font-size-large  : 19px;

但是变量多了之后,代码会变成这样:

$p-font-size-mobile : 15px;
$p-font-size-small  : 16px;
$p-font-size-medium : 17px;
$p-font-size-large  : 19px;

$h1-font-size-mobile: 28px;
$h1-font-size-small : 31px;
$h1-font-size-medium: 33px;
$h1-font-size-large : 36px;

..............

超多的变量显得毫无章法。

Sass maps初试

声明如下的sass变量:

$p-font-sizes: (
  null  : 15px,
  480px : 16px,
  640px : 17px,
  1024px: 19px
);

接下来,创建mixin,遍历属性,生成对应的media queries

@mixin font-size($fs-map) {
  @each $fs-breakpoint, $fs-font-size in $fs-map {
    @if $fs-breakpoint == null {
      font-size: $fs-font-size;
    }
    @else {
      @media screen and (min-width: $fs-breakpoint) {
        font-size: $fs-font-size;
      }
    }
  }
}

Sass 还提供了一些其它的语法糖,可以参考这里

这时我们可以在任意的地方引入mixin

p {
  @include font-size($p-font-sizes);
}

结果和文章开头是一样的.

Solving Breakpoint Fragmentation

上面的代码似乎还是有一点脆弱,如果我们希望引入更多的Breakpoint,或着说p tag 与h1 tag 希望引入不同的Breakpoint.事情就会变的很麻烦.考虑到这一点,我们可以将代码进行重构.

$breakpoints: (
  small : 480px,
  medium: 700px, // Previously 640px
  large : 1024px
);

$p-font-sizes: (
  null  : 15px,
  small : 16px,
  medium: 17px,
  large : 19px
);

$h1-font-sizes: (
  null  : 28px,
  small : 31px,
  medium: 33px,
  large : 36px
);

@mixin font-size($fs-map, $fs-breakpoints: $breakpoints) {
  @each $fs-breakpoint, $fs-font-size in $fs-map {
    @if $fs-breakpoint == null {
      font-size: $fs-font-size;
    }
    @else {
      // If $fs-font-size is a key that exists in
      // $fs-breakpoints, use the value
      @if map-has-key($fs-breakpoints, $fs-breakpoint) {
        $fs-breakpoint: map-get($fs-breakpoints, $fs-breakpoint);
      }
      @media screen and (min-width: $fs-breakpoint) {
        font-size: $fs-font-size;
      }
    }
  }
}

现在,我们可以随意的添加Breakpoint

$p-font-sizes: (
  null  : 15px,
  small : 16px,
  medium: 17px,
  900px : 18px,
  large : 19px,
  1440px: 20px,
);

p {
  @include font-size($p-font-sizes);
}

Improving Vertical Rhythm With Line Height

来,更进一步,我们可以font-size mixin中增加一个lineheight的配置,(line-height和font-size常常是同时出现的)

$breakpoints: (
  small : 480px,
  medium: 700px,
  large : 1024px
);

$p-font-sizes: (
  null  : (15px, 1.3),
  small : 16px,
  medium: (17px, 1.4),
  900px : 18px,
  large : (19px, 1.45),
  1440px: 20px,
);

@mixin font-size($fs-map, $fs-breakpoints: $breakpoints) {
  @each $fs-breakpoint, $fs-font-size in $fs-map {
    @if $fs-breakpoint == null {
      @include make-font-size($fs-font-size);
    }
    @else {
      // If $fs-font-size is a key that exists in
      // $fs-breakpoints, use the value
      @if map-has-key($fs-breakpoints, $fs-breakpoint) {
        $fs-breakpoint: map-get($fs-breakpoints, $fs-breakpoint);
      }
      @media screen and (min-width: $fs-breakpoint) {
        @include make-font-size($fs-font-size);
      }
    }
  }
}

// Utility function for mixin font-size
@mixin make-font-size($fs-font-size) {
  // If $fs-font-size is a list, include
  // both font-size and line-height
  @if type-of($fs-font-size) == "list" {
    font-size: nth($fs-font-size, 1);
    @if (length($fs-font-size) > 1) {
      line-height: nth($fs-font-size, 2);
    }
  }
  @else {
    font-size: $fs-font-size;
  }
}

nth 是sass提供的语法,nth(list, n)从list中拿第n个数据.

Conclusion

上文所提供的代码还是有很多不健壮的地方,欢迎大家提意见,共同研究.

RESOURCES

一个响应式布局分析可以用到的工具Modular Scale
另外一篇很棒的博文

如果觉得文章不错,欢迎来我的github看看,右上角图标即为传送门。

posted @ 2015-10-09 21:48  官文祥  阅读(1148)  评论(3编辑  收藏  举报