インターポレーションの整理

2015年12月9日 Natalie Weizenbaum 投稿

インターポレーション(#{...} を使用して変数や他のスニペットを追加する機能)は、Sass の最も便利な汎用機能の 1 つです。変数、関数呼び出し、またはその他の式を挿入する必要があるほぼすべての場所で使用できます。ほとんどの場合、値は周囲のテキストにそのまま追加されます。これは簡単で理解しやすく、便利です。これは、まさに機能に求めるものです。 

残念ながら、これは*ほとんどの場所*でのみ当てはまります。複雑な歴史的理由により、インターポレーションが少しおかしくなる場所が1つあります。それは、式の中ですが、引用符の外です。ほとんどの場合、これは理にかなっています。display: -#{$prefix}-box と記述すると、期待どおりの結果が得られます。ただし、+ などの演算子がインターポレーションの隣で使用されていると、奇妙な出力が得られるようになります。たとえば、$name + #{$counter + 1} は、name + 3 というテキストを含む引用符で囲まれていない文字列を返す場合があります。

これは本当に奇妙な動作です。なぜ + は他の場所とは異なる動作をするのでしょうか? なぜ $name が正常に評価されるときに、プレーンテキストとして扱われるのでしょうか? この動作は紛らわしく、一貫性がなく、特に便利でもありません。これは、機能に求めるものでは*決して*ありません。では、なぜそもそも存在するのでしょうか? 

複雑な歴史的理由複雑な歴史的理由 パーマリンク

歴史の授業に興味がない場合は、素晴らしい新世界に進んでください。

昔々、インデント構文が唯一の構文であった時代、Sass には「静的」プロパティと「動的」プロパティの区別がありました。静的プロパティは基本的にプレーンな CSS でした。property: value を使用して宣言され、値はそれ以上処理されることなくそのまま使用されました。変数や関数を使用したい場合は、property= value を使用して宣言された動的プロパティを使用する必要がありました。次のようなスタイルシートを多く見かけたでしょう 

.border
  border-width: 4px
  border-style: solid
  border-color= !background_color

また、昔々、変数は $ の代わりに ! を使用し、ハイフンを含めることはできませんでした。昔々の時代は、ある意味最悪でした。しかし、この状況で初めてインターポレーションを追加しました。複数の値を持つ border のようなプロパティを部分的に動的にすることを許可したかったため、Ruby の先例に倣い、値をドロップインするために #{} を使用できるようにすることにしました。すぐに、スタイルシートは次のように見えるようになりました 

.border
  border: 4px solid #{!background_color}

これははるかに優れています!そしてしばらくの間、すべてが 穏やかでした。

SCSS の登場SCSS の登場 パーマリンク

最終的に、ユーザーがスタイルシートを CSS のように見せたいという強い要望を持っていることが明らかになったため、私たちは腰を据えて Sass 3 となるリリースで SCSS となる構文の開発を開始しました。この作業の一環として、静的プロパティと動的プロパティの区別を完全に取り除くことにしました。すべてのプロパティが同じように機能することはユーザーにとって明らかに素晴らしいことでしたが、2 つの構文を最小限の 苦痛で統合する方法を見つけ出す必要がありました。

古い式の構文がほとんど普遍的に無効な CSS であるか、いずれにしても CSS 値を出力するものであるため、これはほとんど簡単でした。しかし、インターポレーションは難しいことがわかりました。後方互換性は私たちにとって非常に重要であるため、Sass 2 でインターポレーションが使用された(または*理論的に使用できた*)すべての場所が、周囲のすべてが完全に 解析されたにもかかわらず、Sass 3 でも引き続き機能するようにしたかったのです。

私たちの解決策は、プレーンな CSS 式の一部ではない #{} の周りのほぼすべてのものを文字列に変えることでした。そうすることで、アップグレード時に、人々が抱えていたであろう奇妙なコーナーケースがすべて機能し続けることを期待しました。これにより、上記で説明した奇妙な動作が発生しましたが、当時、私たちの最優先事項は、ユーザーが Sass 3 にできる限り簡単に移行できるようにすることでした。私たちは、この奇妙さは価値があると判断し、リリースしました 

素晴らしい新世界素晴らしい新世界 パーマリンク

現在まで早送りしましょう。私たちは現在、次のメジャーリリースである Sass 4 の開発を開始しており、(心から願うように) 誰もが何年も Sass 2 のスタイルシートを書いていません。メジャーリリースは、この歴史的な不要物を整理する絶好の機会であり、issue tracker で徹底的に議論した結果、変更することにしました。 

このような後方互換性のない変更には、3 つの主要なステップがあります。1つ目は新しい構文を設計することです。これは、基本的に「誰もがすでにそうだと考えていたことを行う」だけなので、非常に簡単でした。私たちは、その一般的な概念を取り出し、 詳細を解明する必要がありました。

結局、#{} を構文的に識別子の一部として扱うことにしました。-#{$prefix}-box と記述すると、Sass はそれを "-"、それに続く $prefix の値、それに続く "-box" を含む単一の識別子として解析します。#{$font} を単独で記述した場合でも、$font の値のみを含む識別子として解析されます。このようにすると、インターポレーションは、識別子がこれまでに行ってきたよりも演算子の周りで奇妙な動作をしなくなります。 

設計が完了したら、2 番目のステップは古い動作を非推奨にすることでした。非推奨の本質は、警告をいつ出力するかを把握することであり、これはここでかなり難しいものでした。たとえば、演算子が含まれている場合でも、引き続き機能する状況に対して警告したくありませんでした。たとえば、12px/#{$line-height} は (わずかに異なる理由で) 古い世界と新しい世界で正しい結果を出力しますが、12px+#{$line-height} はそうではありません。

ここで非推奨を機能させる方法の詳しい説明はしません。それは GitHub issue の目的です。値をどのように*記述したか*ではなく、どのように*使用したか*に基づいて非推奨の警告を出力できる場合を含め、多くの特殊なケースが含まれていたと言っておけば十分でしょう。ただし、最終的にどうなったかには非常に満足しています。実際には、壊れるケースの 99% をキャッチすると思います。 

もう1つのエキサイティングなボーナスは、コードを自動的に更新する機能でした。後方互換性を導入するときにこれが常に機能するわけではありませんが、この場合、非推奨のインターポレーションの使用を Sass 4 互換のコードに変換するために sass-convert を使用することができました。いくつか偽陰性がありますが (互換性がないことを証明できるケースのみを変換します)、ユーザーをかなり先に進めるには十分です 

非推奨が導入された後の最後のステップは、main ブランチ (最終的には Sass 4 になります) に移行し、古い動作をすべて削除して、新しい動作を実装することでした。そして、それは*素晴らしい*ものでした。不快なコードを削除して、クリーンなものに置き換えるのは、暑い太陽の下で埃の中を一日中ハイキングした後でシャワーを浴びるような感覚です。そして、この機能を数週間開発した後、その終わりが見えて嬉しかったです。 

確認する確認する パーマリンク

本日リリースされた Sass 3.4.20 は、古い構文の非推奨警告を含む最初のリリースでした。スタイルシートに非推奨のインターポレーションが潜んでいないか確認したい場合は、gem install sass を実行してスタイルシートを再コンパイルしてください。もし見つかった場合は、sass-convert --recursive --in-place . を実行して、自動的に修正してみてください。 

新しい構文を試したい場合は、4.0.0.alpha.1 も本日リリースされました。gem install sass --prerelease で入手できます。ただし、注意してください。これはアルファソフトウェアであるため、将来変更される可能性があります。私たちは通常、プレリリース版でさえかなり安定した状態を保つように努めていますが、バグが発生する可能性もあります。 

バグを見つけた場合は、issue tracker に報告してください。それがタイプミスのような単純なものであっても、私たちは知りたいと思っています。有効であるはずのものを非推奨にした場合は、*特に*知りたいと思っています。質問がある場合は、@SassCSS にツイートするか、メーリング リストに投稿してください。