Sass MixinとMedia Merging


Sassにあまり詳しくない場合は、メディアクエリー(@media)機能(メディアマージとしてよく使われる)など、Sassが非常に興味深い機能を追加していることを知らないかもしれません.
Media Mergingとは何かを説明する前に、Media Query(メディアクエリ)のcss仕様がネストされたメディアクエリを許可しているかどうかを理解する必要があります.一部のブラウザでは、Firefox、Chrome、Operaなどのネストされたメディアクエリーがサポートされています.しかし、SafariとInternet Explorerは現在、ネストされたメディアクエリーをサポートしていません.
ブラウザのサポートが理想的ではないため、Sassはネストされたメディアクエリーをメディア条件にマージします.たとえば、次のコードがあります.
    @media (min-width: 42em) {
      @media (max-width: 1337px) {
        .foo {
          color: red;
        }
      }
    }

次のようにコンパイルされます.
    @media (min-width: 42em) and (max-width: 1337px) {
      .foo {
        color: red;
      }
    }

これは便利ですが、ありますか.ネストされたメディアクエリーを単一の文にマージする場合、これがいわゆるメディアマージです.
何が欲しいの?Media queries(メディアクエリー)!
上記では簡単に紹介しましたが、基本的には、クエリーのマッピングを入力として、@meidaコマンドの単一条件に結合して出力する非常に簡単なmixinを構築したいと思います.
前の例に戻って、こう書きたいと思います.
    @mixin media($queries) { .. }
    
    .foo {
      @include media((min-width: 42em, max-width: 1337px)) {
        color: red;
      }
    }

コンパイルでは、上記のCSSコードセグメントで見た結果と同じように、私の考えでは、少なくとも2つの方法で作成することができます.まず、醜いように見える1つを解決しましょう.
醜いバージョン
最も直接的な送信は文字列を構築し、新しいキー値ペアごとに反復します.
    /// Media query merger (the ugly version)
    /// Create a single media condition out of a map of queries
    /// @param {Map} $queries - Map of media queries
    
    
    @mixin media($queries) {
      $media-condition: ';
      
    
      // Loop over the key/value pairs in $queries
      
      
      @each $key, $value in $queries {
      
        // Create the current media query
        
        
        $media-query: '(' + $key + ': ' + $value + ')';
        
        
    
        // Append it to the media condition
        
        
        $media-condition: $media-condition + $media-query;
    
        // If pair is not the last in $queries, add a `and` keyword
        
        
        @if index(map-keys($queries), $key) != length($queries) {
          $media-condition: $media-condition + ' and ';
        }
      }
      
    
      // Output the content in the media condition
      
      @media #{$media} {
        @content;
      }
    }

その機能はよく実現されていますが、このようなコードは優雅ではないことを認めなければなりません.
エレガントな方法
Sassがメディアクエリーを処理する優雅な方法を提供したとき、文字列を操作するのが気持ちがいいとは思わなかった.もっと良い方法があるに違いない.そして彼は私を奮い立たせた:再帰.辞書によると、再帰的な意味は:
式、関数、または集合などのオブジェクトのシーケンスを定義する方法で、初期オブジェクトの数がいくつか与えられ、各連続オブジェクトは以前のオブジェクトに基づいて定義されます.
このように単純に理解すれば,再帰はある点まで関数が異なるパラメータで自分のメカニズムを何度も呼び出すことである.では、ちょっと大変ですね.JavaScriptで再帰的な関数を使用する実際の例:
    function factorial(num) {
      if (num < 0) return -1;
      else if (num == 0) return 1;
      else return (num * factorial(num - 1));
    }

ご覧のように、num変数が1未満になるまで関数は自分を呼び出し、実行するたびに1を減らします.
どうして私はあなたにこれを教えますか?再帰を使用してメディア条件を構築し、Sassを使用してメディア統合を行うことができると思います.mixinをmapの最初のクエリーメディアとして出力し、mapにクエリーがないまでmapを呼び出すとします.彼は少し複雑なので、私たちは一歩一歩歩きます.
まず、mapにこれ以上クエリーがなければ、コンテンツを出力するだけです.
    @mixin media($queries) {
      @if length($queries) == 0 {
        @content;
      } @else {
        // ...
      }
    }

次に、最初のメディアクエリのメディアブロックを地図に出力します.mapの最初のキーを取得するにはnth(.)を使用します.とmap-keys(.)で行ないます.
    $first-key: nth(map-keys($queries), 1);
    
    @media ($first-key: map-get($queries, $first-key)) {
      // ...
    }

今まではまあまあでしたが、mixinを使って自分を呼び出すだけで、同じ$queriesに渡さないでください.そうしないと、無限のループに直面します.最初のキー/値ペアを削除した後に$queryを渡す必要があります.幸いなことに、ここにはもう一つmap-remove(.)で行ないます.
    $queries: map-remove($queries, $first-key);
    
    @include media($queries) {
      @content;
    }

mixin全体がこうなっています
    /// Media query merger
    /// Create a single media condition out of a map of queries
    /// @param {Map} $queries - Map of media queries
    
    
    @mixin media($queries) {
      @if length($queries) == 0 {
        @content;
      } @else {
        $first-key: nth(map-keys($queries), 1);
    
        @media ($first-key: map-get($queries, $first-key)) {
          $queries: map-remove($queries, $first-key);
    
          @include media($queries) {
            @content;
          }
        }
      }
    }

さらに進む
前の記事では,Sassにおける応答ブレークポイントを管理するためのいくつかの異なる方法を見た.mixinで使用された最後のバージョンは、次のようになります.
    /// Breakpoints map
    /// @type Map
    
    $breakpoints: (
      'small': (min-width: 767px),
      'medium': (min-width: 992px),
      'large': (min-width: 1200px),
    );
    
    
    /// Responsive breakpoint manager
    /// @param {String} $breakpoint - Breakpoint
    /// @requires $breakpoints
    
    
    @mixin respond-to($breakpoint) {
      $media: map-get($breakpoints, $breakpoint);
    
      @if not $media {
        @error "No query could be retrieved from `#{$breakpoint}`. "
        + "Please make sure it is defined in `$breakpoints` map.";
      }
    
      @media #{inspect($media)} {
        @content;
      }
    }

このmixinはcharmのようですが、inspect(..)に依存するため、(min-width:42 em)や(max-width:1337 px)などの多条件クエリーはサポートされていません.を選択します.
したがって、一方では、ブレークポイントマネージャがブレークポイントのグローバルmapからエラーメッセージを選択して処理する一方で、マルチクエリー条件を使用できるブレークポイントマネージャがあります.選択は難しい.
respond-toを少し調整します(.)mixin、私たちは彼にmediaを含めることができます(..)@mediaコマンド自体を印刷するのではなくmixinです.
    @mixin respond-to($breakpoint) {
      // Get the query map for $breakpoints map
      $queries: map-get($breakpoints, $breakpoint);
    
      // If there is no query called $breakpoint in map, throw an error
      @if not $queries {
        @error "No value could be retrieved from `#{$breakpoint}`. "
        + "Please make sure it is defined in `$breakpoints` map.";
      }
    
      // Include the media mixin with $queries
      @include media($queries) {
        @content;
      }
    }

最善の方法は、このmixinを使用している場合はrespond-toを調整することができます(.)およびmediaの追加(.)APIがまったく変更されていないため、複数のクエリー機能を含むことを完了します:respond-to(.)以前と同じように、ブレークポイント名が必要です.
最後の考え
ネストされたメディアクエリーとmixin再帰のサンプルを見つけたのは初めてなので、これはとても興奮していると言わなければなりません.最後の例:
    // _variables.scss
    
    $breakpoints: (
      'small': (min-width: 767px),
      'small-portrait': (min-width: 767px, orientation: portrait),
      'medium': (min-width: 992px),
      'large': (min-width: 1200px),
    );
    
    
    // _mixins.scss
    
    @mixin media($queries) { .. }
    @mixin respond-to($breakpoint) { .. }
    
    
    // _component.scss
    
    .foo {
      @include respond-to('small-portrait') {
        color: red;
      }
    }

以下のCSSが生成されます.
    @media (min-width: 767px) and (orientation: portrait) {
      .foo {
        color: red;
      }
    }


作成者情報
原文作者:Hugo Giraudel原文リンク:https://www.sitepoint.com/sas...MaxLeapチームから翻訳先端研究開発者:Ammie Bai訳者紹介:新晋先端一枚、現在MaxLeapサイトの展示性コンテンツの実現を担当している.自分でjs特効小Demoを書いてみるのが好きです.
関連記事はFlashで画像の切り抜きを実現する必要はありません——HTML 5中級進級
作者往期佳作简介jCanvas:jQueryがHTML 5 Canvasに出会ったらどうやってGulpと結びつけてPostCssを使うか
アプリの作成、開発について知りたいですか?技術交流QQ群へようこそ:480843919