解决Sass媒体查询的重复问题


原文链接: 解决Sass媒体查询的重复问题

在Sass中有很多方法可以解决媒体查询这个问题,但是其中一些方法存在相同的问题。一开始我会还原这个问题,然后提供我的解决方案,最后列出这个方案对工作流程的好处。

问题

假如我们把网站的Sass样式分离成多个像header.scss,hero.scss,cards.scss等等这样的组件。为他们添加各自的响应式样式最简洁的做法是,在各自的组件文件中添加相应的响应式样式。为了实现这样的效果,最简单的做法就是,定义一系列针对不同尺寸屏幕的mixin然后使用@content

    @mixin tablet {
        @media (min-width: 768px) and (max-width: 1024px) {
            @content;
        }
    } 
    @mixin desktop {
        @media (min-width: 1024px) {
            @content;
        }
    }

这些mixins会将外部传进来的样式片段,放置在@content出现的地方。
就像这样使用:

    p {
        font-size: 16px;
        @include tablet {
            font-size: 18px;
        }
        @include desktop {
            font-size: 20px;
        }
    }

这样很好,很整齐。它告诉我们,一个p元素里对两个不同的设备有不同的响应式设计。但是这样带来的问题是,在编译后CSS文件中,每个mixin中的媒体查询会重复地出现,就像这样:

    p {
        font-style: 18px;
    }
    @media (min-width: 768px) and (max-width: 1023px) {
        p {
            font-style: 20px;
        }
    } 
    @media (min­width: 1024px) {
        p {
            font-style: 25px;
        }
    }

上面是Write Better Media Queries with
Sass
一文中提供的例子,只是为了举例说明这个问题。

这个例子仅仅涵盖了一个p标签,当存在很多需要响应式设计的元素的时候,这里将存在大量的重复。

对于小型网站,这样简单地将媒体查询mixin放在元素中可能并没有什么不妥,但是如果是大型网站,这样做会使CSS文件很快臃肿起来。如果Sass团队能解决这个问题,那再好不过了,但是我确定,这对编译速度来说是个很大的挑战。

简单的解决方案

在这个解决方案中,你可以将响应式样式放在每个组件中相应位置,并且没有重复的媒体查询,一切看起来都很完美,整齐,且易于维护。

步骤 1. 创建一个 media-queries.scss 文件

为了避免重复的媒体查询,并且让代码看起来更整齐,我们在一个单独的Sass文件中定义媒体查询,然后调用这个文件。比如media-queries.scss

    // small screen size (sm)
    @media (min-width: 801px) {
        ...
    }

    // medium screen size (md)
    @media (min-width: 992px) {
        ...
    }

为了看起来简单一点,在这里仅仅为小尺寸和中等尺寸屏幕定义了两个主要的断点。

步骤 2. 为每个元素创建一个响应式mixin

就拿banner.scss来说,利用移动优先原则,在文件的底部定义一系列响应式mixin。这些mixin将会在media-queries.scss中相应的断点处调用。

确保为mixin添加一个能反映出相应断点的后缀,像前面的例子中的,small(sm)medium(md)。比如说,如果一段样式处于小尺寸屏幕的断点,这个mixin名字就可以取为,元素的名称+sm后缀。

mixin中为你准备适配的屏幕尺寸添加所有相应的样式。如:

    .banner {
        text-align: center;
        font-size: 14px;
    }
    // called in media-queries.scss
    @mixin banner--sm() {
        .banner {
            font-size: 20px;
        }
    }
    @mixin banner--md() {
        .banner {
            text-align: left;
            font-size: 25px;
        }
    }

步骤 3. 在media-queries.scss中调用这些mixin

回到media-queries.scss文件,我们可以在指定的媒体查询中,调用相应的mixin

    // small screen size (sm)
    @media (min-width: 801px) {
        @include banner--sm();
    }

    // medium screen size (md)
    @media (min-width: 992px) {
        @include banner--md()
    }

好了,现在所有的响应式样式片段都定义在相应在的组件文件当中,然后被调用在媒体查询中相应断点处。整个编译后的CSS文件中没有重复的,冗余的媒体查询语句。

media-queries.scss输出的CSS文件:

    @media (min-width: 801px) {
        .banner {
            font-size: 20px;
        }
    }

    @media (min-width: 992px) {
        .banner {
            text-align: left;
            font-size: 25px;
        }
    }

最后,在每个断点处会调用很多个mixin,这样编译后的CSS文件就不会变得臃肿,同时你也很清楚所有的响应式样式片段在什么地方:

    @media (min-width: 801px) {
        @include home-cta--sm();
        @include twitter-testimonials--sm();
        @include site-footer--sm();
        @include feature-section--sm();
        @include feature-item--sm();
        @include post-meta--sm();
        @include social-share--sm();
        @include hero--sm();
        @include feature-page--sm();
    }

优点

想东想西在压缩文件体积方面,效果并不是很明显,但是对我来说,能减则减。另外一方面,重复的媒体查询并不会太大地影响性能。

优点主要还是体现在优化工作流程方面。

团队易读性 和 标准实践

回到最初嵌套的媒体查询方法,我也喜欢这个方法,但是如果在一个非常庞大的组件文件中的不同层级使用这种嵌套,会使代码非常不整齐。当然,也可以结合BEM,使得嵌套的层数不超过2层。这种搭配BEM的解决方案其实还不错。

尽管如此,你和你的同事还是要上下滚动来查找哪些元素存在响应式设计。因为你必须弄清那些存在响应式设计的元素,这样,组件文件又不应该过长。使用我的解决方案,你和你的团队会很清楚在任意一个文件中元素媒体查询语句的位置。而且你可以在媒体查询区域寻找元素,如果没有,那么这个元素不会对任何的断点作出响应。

组件文件的布局

也可以在media-queries.scss文件中,查找那些存在响应式设计的元素。我们已经在一个组件数量超过30个的网站运用了这种方法,它的可伸缩性很好。

可以很好地利用移动优先原则

最后,如果使用了移动优先原则,在组件文件中你将会从上到下依次看到小屏幕到大屏幕对应的样式。这样就会减少对不同屏幕尺寸所在位置的额外关注。

使用移动优先原则,从上到下将会看到屏幕尺寸的依次递增

一些缺点

这个方案也有一些缺点。比如,当我们删除了一个元素,就必须回到media.scss文件中删除相应的调用,不然就会抛出一个编译错误,不过也有一点好处是,你不用太过注意它,反正都会抛出错误提醒你。还有就是,可能会忘记在media-queries.scss添加mixin

重构的时候也会比嵌套的媒体查询更麻烦。

在实际开发当中,特别是在回顾的时候,拥有一个结构良好的,有组织的媒体查询方法可以简化工作并且让我们更迅速地debug。

本文根据@Dominique
Briggs
《Solving
Sass's media query duplication problem and enhancing your
workflow》
所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://medium.com/front-end-developers/the-solution-to-media-queries-in-sass-5493ebe16844#.vakrbmst8

`