SASS优化响应式断点管理

原文:《Managing Responsive Breakpoints with Sass

链接:https://www.sitepoint.com/managing-responsive-breakpoints-sass/

作者:Hugo Giraudel,来自法国,著名SASS大牛,在SassWay等多个网站撰文推广sass,是SassyJSON、SassyMatrix等多个开源项目的开发者

1.使用变量(With variables)

BootstrapFoundation采用这种方式,首先定义变量,然后在媒体查询中使用变量。换句话说,你可以在配置文件或者其他地方定义变量以备使用。我们来看看Bootstrap怎么干的。
// Defining values  
$screen-sm-min: 768px;  
$screen-xs-max: ($screen-sm-min - 1);  
$screen-md-min: 992px;  
$screen-sm-max: ($screen-md-min - 1);  
$screen-lg-min: 1200px;  
$screen-md-max: ($screen-lg-min - 1);  
   
// Usage  
@media (max-width: $screen-xs-max) { ... }  
@media (min-width: $screen-sm-min) { ... }  
@media (max-width: $screen-sm-max) { ... }  
@media (min-width: $screen-md-min) { ... }  
@media (max-width: $screen-md-max) { ... }  
@media (min-width: $screen-lg-min) { ... }  

Foudation更进一步,使用跨范围的媒体查询,避免使用过多的max-width和min-width。

// Defining values  
$small-range:   (0em, 40em);       /* 0, 640px */  
$medium-range:  (40.063em, 64em);  /* 641px, 1024px */  
$large-range:   (64.063em, 90em);  /* 1025px, 1440px */  
$xlarge-range:  (90.063em, 120em); /* 1441px, 1920px */  
$xxlarge-range: (120.063em);       /* 1921px */  
   
// Defining media queries  
$screen:       "only screen" !default;  
$landscape:    "#{$screen} and (orientation: landscape)" !default;  
$portrait:     "#{$screen} and (orientation: portrait)" !default;  
$small-up:     $screen !default;  
$small-only:   "#{$screen} and (max-width: #{upper-bound($small-range)})" !default;  
$medium-up:    "#{$screen} and (min-width:#{lower-bound($medium-range)})" !default;  
$medium-only:  "#{$screen} and (min-width:#{lower-bound($medium-range)}) and (max-width:#{upper-bound($medium-range)})" !default;  
$large-up:     "#{$screen} and (min-width:#{lower-bound($large-range)})" !default;  
$large-only:   "#{$screen} and (min-width:#{lower-bound($large-range)}) and (max-width:#{upper-bound($large-range)})" !default;  
$xlarge-up:    "#{$screen} and (min-width:#{lower-bound($xlarge-range)})" !default;  
$xlarge-only:  "#{$screen} and (min-width:#{lower-bound($xlarge-range)}) and (max-width:#{upper-bound($xlarge-range)})" !default;  
$xxlarge-up:   "#{$screen} and (min-width:#{lower-bound($xxlarge-range)})" !default;  
$xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (max-width:#{upper-bound($xxlarge-range)})" !default;  
   
// Usage  
@media #{$small-up}     { ... }  
@media #{$small-only}   { ... }  
@media #{$medium-up}    { ... }  
@media #{$medium-only}  { ... }  
@media #{$large-up}     { ... }  
@media #{$large-only}   { ... }  
@media #{$xlarge-up}    { ... }  
@media #{$xlarge-only}  { ... }  
@media #{$xxlarge-up}   { ... }  
@media #{$xxlarge-only} { ... }  

 两种方法各有一个不爽的地方,在Bootstrap里每次都要使用max-width,在Foundation里我们需要使用插值变量这种又丑又烦的方式。显示我们需要想办法解决这些问题。

2.使用独立Mixin(With a standalone mixin)

media queries in Sass 3.2》是CSS-Tricks里最火的文章之一,在这篇文章里Chris Coyier在借鉴a former idea by Mason Wendella former idea by Jeff Croft两文的基础上,如何使用sass实现响应式布局的断点管理。
命名断点是非常重要的,因为可以为抽象的数字赋予意义(你知道767px是什么意思吗,我不知道,直到我去使用小屏幕的时候才知道)。为什么BootstrapFoundation要使用变量呢,不也是为了给抽象的数字起个名字吗?
所以我们定义个mixin,接收断点名作唯一的参数,返回媒体查询的内容。准备好了吗?走起。
@mixin respond-to($breakpoint) {  
  @if $breakpoint == "small" {  
    @media (min-width: 767px) {  
      @content;  
    }  
  }  
   
  @else if $breakpoint == "medium" {  
    @media (min-width: 992px) {  
      @content;  
    }  
  }  
   
  @else if $breakpoint == "large" {  
    @media (min-width: 1200px) {  
      @content;  
    }  
  }  
}  

然后,我们这样使用mixin。

@include respond-to(small) { ... }  
@include respond-to(medium) { ... }  
@include respond-to(large) { ... }  

 这个方法是极好的(甄嬛体,老外也看?),原因有二:抽象数据有意义,大量断点集中管理。如果你想把“992px”改成“970px”,你不需要爬过每一个css文件,而只需更新mixin,然后全部更新。

但是也还有两个问题:
a.断点不容易从mixin里拿出来,放到配置文件里去。
b.冗余太多。

3. 可配置的mixin(With a configurable mixin  )

<为了解决上面的两个问题,我们需要从断点mixin中抽出一个列表,只剩下mixin核心,然后这个列表就可以随便移动,或者扔到配置文件中。
然后,使用sass 3.3+中的maps,我们可以方便的使用关联的属性和属性值。
@mixin respond-to($breakpoint) {  
  // Retrieves the value from the key  
  $value: map-get($breakpoints, $breakpoint);  
   
  // If the key exists in the map  
  @if $value != null {  
    // Prints a media query based on the value  
    @media (min-width: $value) {  
      @content;  
    }  
  }  
   
  // If the key doesn't exist in the map  
  @else {  
    @warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "  
        + "Please make sure it is defined in `$breakpoints` map.";  
  }  
}  

我们在修改mixin的同时也进行了一些提高,不要小看这些提高,我们加上了错误处理,如果在maps中没有找到断点值,将会弹出一个错误提示,这将便于我们开发过程中的调试。

我们让mixin变得更加精简,能很好的处理错误,同时我们去掉了一个功能——判断属性是否是你想要的(min-width,max-width,min-height等),这在移动优先的网页中没问题,因为我们仅仅需要min-width。但是,如果需要查询其他属性,我们需要把这个功能加回来。为了达到这个目的,我想到了一个非常优雅的解决方案,同时并不增加复杂性。
$breakpoints: (  
  'small'  : ( min-width:  767px ),  
  'medium' : ( min-width:  992px ),  
  'large'  : ( min-width: 1200px )  
);  
    
@mixin respond-to($name) {  
  // If the key exists in the map  
  @if map-has-key($breakpoints, $name) {  
    // Prints a media query based on the value  
    @media #{inspect(map-get($breakpoints, $name))} {  
      @content;  
    }  
  }  
   
  // If the key doesn't exist in the map  
  @else {  
    @warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "  
        + "Please make sure it is defined in `$breakpoints` map.";  
  }  
}  

在这里,我们主要做了三个事情

a. 检查查询的断点在map中存在不存在
b.如果存在,打印对应的媒体查询。
c.如果不在,进行错误提示。
简单吧,如果我们回顾前面的两个缺陷,已经不再有WET(Write Everything Twice))问题,也不再有不灵活的媒体查询。但是还有一个问题,不支持复杂的媒体查询。复杂指的是涉及多个组件的查询(e.g. screen and (min-width: 767px))。我们上面这些方案除了第一种变量之外都不能很好的解决这个问题。

4. 使用外部工具(With an external tool)

最后一个同样重要的是,如果不想创建自己的mixin,你可以使用外部的工具处理响应式布局的断点,有很多sass的扩展在这个方面做得很好。
SassMQ by Kaelig
Breakpoint by Mason Wendell and Sam Richard
Breakup by Ben Scott
 SassMQBreakpointBreakup
MQ type *-width any any
No Query fallback yep yep yep
API complexity simple very simple medium
Code complexity very simple complexe simple
Extra Debug mode Singularity.gs
基本上是这样,如果发现有没有涉及的,记得一定告诉我。

SassMQ

// Configuration  
$mq-responsive: true;  
$mq-static-breakpoint: desktop;  
$mq-breakpoints: (  
  mobile:  320px,  
  tablet:  740px,  
  desktop: 980px,  
  wide:    1300px  
);  
   
// Example  
selector {  
  @include mq($from: mobile) {  
    property: value;  
  }  
}  

 BreakPoints

$high-tide: 500px;  
$ex-presidents: 600px 800px;  
$surfboard-width: max-width 1000px;  
$surfboard-height: (min-height 1000px) (orientation portrait);  
   
selector {  
  @include breakpoint($high-tide) {  
    property: value;  
  }  
}  

 Breakup

$breakup-breakpoints: (  
  'thin' '(max-width: 35.999em)',  
  'wide' '(min-width: 36em)',  
  'full' '(min-width: 61em)'  
);  
   
selector {  
  @include breakup-block('thin') {  
    property: value;  
  }  
}  

 

 

posted @ 2017-05-17 11:39  karila  阅读(370)  评论(0编辑  收藏  举报