Edited at

IE8互換のレスポンシブデザインを、ワンソース、モバイルファーストで作れるSassミックスイン

More than 3 years have passed since last update.

一部の公共性の高いWebサイトでは、今だにIE8への対応を行いつつ、同時にレスポンシブデザインも要求されるケースがある。当然IE8はCSSのメディアクエリに対応していない為、メディアクエリ抜きでコーディングをする必要がある。


設定する要件


  • モダンブラウザに対応し、あるブレークポイントを境にPC版とスマートフォン版のスタイルが切り替わる。レスポンシブデザインとすること

  • モダンブラウザのPC版とほぼ同等の外観でIE8にも対応すること。ただし、ブレークポイントを越えてもレイアウトが変わる必要はない


実装方針

もしPCファーストの設計であれば、IE8のことを気にせずに実装できる。

1.サイズ共通のスタイルを書く

2.PC専用スタイルを記述する

2.SP専用のスタイルをメディアクエリの内側で上書きする

しかし、PC用スタイルのオーバーライドは無駄が多くて分かり辛い為、できればモバイルファーストで実装したい。


たいていの場合、「PC(広い画面)用のデザイン」よりも「モバイル(狭い画面)用のデザイン」の方がシンプルな構成になるでしょう。その場合には、まず、「モバイル(狭い画面)用のデザイン」を全て記述しておき、そこに追加する形で「PC(広い画面)用のデザイン」を作っていくと、記述量を減らせる上に、更新の手間も少なくて済むCSSソースになります。

モバイルファーストでデザインする際のCSSの書き方 [ホームページ作成] All About


ところが、モバイルファーストで実装しようとすると、どうしてもIE8用の記述をメディアクエリの外側に記述する必要があり、どこかで2回同じことを書かなければならない。

1.サイズ共通のスタイルを書く

2.SP専用スタイルをメディアクエリの内側に書く1

3.PC専用のスタイルをメディアクエリの内側に書く(IE8からは認識されない)

4.IE8専用のスタイルを書く

↑ 4は3と同じ内容

3、4の重複を失くすことは原理的に不可能だと思われる。このことを受け入れた上で、1〜4のコードをスッキリと記述できるSCSSのミックスインを作成した。


HTML

まずは、下準備としてIE8を識別するためのコンディショナルコメント2をHTMLへ仕込む。


sample.html

<!DOCTYPE html>

<!--[if lt IE 7]> <html class="no-js ie6 oldie"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<title>demo</title>
</head>
<body>
<div class="my-container">
<h1 class="my-container__head">IE8互換のレスポンシブデザインを、ワンソースかつモバイルファーストで作れる@mixin</h1>
<p class="my-container__body">一部の公共性の高いWebサイトでは、今だにIE8への対応を行いつつ、同時にレスポンシブデザインも要求されるケースがあります。当然IE8はCSSのメディアクエリに対応していない為、メディアクエリ抜きでコーディングしてあげる必要があります。</p>
</div>
<div class="my-container">
<h1 class="my-container__head">もしPCファーストの設計であれば、IE8のことを気にせずに実装できる</h1>
<p class="my-container__body">しかし、PC用スタイルのオーバーライドは無駄が多くて分かり辛い為、できればモバイルファーストで実装したい。ところが、モバイルファーストで実装しようとすると、どうしてもIE8用の記述をメディアクエリの外側に記述する必要があり、どこかで2回同じことを書かなければならない。</p>
</div>
</body>
</html>


SCSS


_mixins.scss


$break-point: 600px !default;
$ie-selector: '.oldie' !default;

// 全サイズへの出力
@mixin for-all ($selector) {
@at-root {
/* ====================
#{$selector}
*/

#{$selector} {
@content;
}
}
}

// モバイル専用出力
@mixin for-mobile-only ($selector) {
@media only screen and (max-width: $break-point - 1) {
@content;
}
}

// モダンブラウザ+IE8用出力
@mixin for-pc-only ($selector) {
@media only screen and (min-width: $break-point) {
@content;
}
@include for-ie-only($selector) {
@content;
}
}

// IE8専用出力
@mixin for-ie-only ($selector) {
@at-root {
#{$ie-selector} #{$selector} {
@content;
}
}
}


for-allミックスインが不要に見えるかもしれないが、次のようなメリットがあるのであえて入れている。


  • コンパイル後もコメントを挿入してBEMのコンポーネントやエレメントの区切りが分かりやすくなるようにしている

  • インデントが揃うので、補完のないエディタ上でもコピペが楽


  • for-以降を書きかえるだけで、対象となる画面サイズを変更できる

このミックスインを以下のように使用する。なお、CSSの構造化にBEMとSMACSSの考え方を取り入れている。


style.scss

@import 'mixins';

body {
background: #eee;
}

$break-point: 694px;

// my-containerコンポーネント
.my-container {
// 共通
@include for-all(&) {
font-size: 0.85em;
font-family: sans-serif;
margin: 0;
padding: 0;
padding: 1em;
background: white;
}
// モバイル
@include for-mobile-only(&) {
border-top: 2px solid pink;
}
// PC
@include for-pc-only(&) {
text-align: center;
float: left;
position: relative;
width: 300px;
min-height: 23em;
margin-right: 10px;
margin-bottom: 10px;
border-radius: 16px;
}

// 見出しエレメント
&__head {
// 共通
@include for-all(&) {
margin-top: 0.3em;
margin-bottom: 0.3em;
line-height: 1.1;
}
// PC
@include for-pc-only(&) {
padding-top: 0.5em;
}
}

// 本文エレメント
&__body {
// 共通
@include for-all(&) {
color: #666;
}
&:before {
// 共通
@include for-all(&){};
// PC
@include for-pc-only(&) {
content: '*';
font-family: 'Times New Roman';
font-size: 3em;
color: pink;
position: absolute;
display: block;
text-align: center;
top: 0.1em;
left: 0;
right: 0;
}
}
}
}


SMACSSでは、メディアクエリは断片的に記述することが推奨されている。


メディアクエリの宣言はおそらく(ほとんどの場合)何度も記述することになる。しかしこうすることでモジュールについてのすべての情報を1カ所で管理できる。モジュールについての情報を集中管理できる(特に1つのCSSファイル内で)ことはモジュールのテストを分離することを可能にし、(アプリケーションの制作の方法によっては)モジュラー化されたテンプレートとCSSを初期のページ読み込みの後でも呼び出すことができるようになる。

Scalable and Modular Architecture for CSS 日本語


メディアクエリの宣言が連続する分冗長だが、大きな単位のメディアクエリで区切るよりも管理がしやすく、デメリットよりメリットの方が勝っていると思われる。


CSS

上記のSCSSをビルドすると次のようなCSSが生成される。IE8での動作確認まではできないが、実際のスタイルはJSFiddleで参照できる。


style.css

body {

background: #eee;
}

/* ====================
.my-container
*/

.my-container {
font-size: 0.85em;
font-family: sans-serif;
margin: 0;
padding: 0;
padding: 1em;
background: white;
}
@media only screen and (max-width: 693px) {
.my-container {
border-top: 2px solid pink;
}
}
@media only screen and (min-width: 694px) {
.my-container {
text-align: center;
float: left;
position: relative;
width: 300px;
min-height: 23em;
margin-right: 10px;
margin-bottom: 10px;
border-radius: 16px;
}
}
.oldie .my-container {
text-align: center;
float: left;
position: relative;
width: 300px;
min-height: 23em;
margin-right: 10px;
margin-bottom: 10px;
border-radius: 16px;
}
/* ====================
.my-container__head
*/

.my-container__head {
margin-top: 0.3em;
margin-bottom: 0.3em;
line-height: 1.1;
}
@media only screen and (min-width: 694px) {
.my-container__head {
padding-top: 0.5em;
}
}
.oldie .my-container__head {
padding-top: 0.5em;
}
/* ====================
.my-container__body
*/

.my-container__body {
color: #666;
}
/* ====================
.my-container__body:before
*/

@media only screen and (min-width: 694px) {
.my-container__body:before {
content: '*';
font-family: 'Times New Roman';
font-size: 3em;
color: pink;
position: absolute;
display: block;
text-align: center;
top: 0.1em;
left: 0;
right: 0;
}
}
.oldie .my-container__body:before {
content: '*';
font-family: 'Times New Roman';
font-size: 3em;
color: pink;
position: absolute;
display: block;
text-align: center;
top: 0.1em;
left: 0;
right: 0;
}


素のCSSでSMACSSを意識して書いた場合とほぼ同じ、理想的な内容で出力できているのではないだろうか。これなら、納品後に第三者が内容を修正するのも比較的簡単になるだろう。


Live Template

ミックスインは{}の内側が空でも構わないので、例えばJetBrainのIDEに次のようなLive Templateを登録しておけば、サクサクコーディングが進められる。


abbreviation'@rwd'で呼び出し

// 共通

@include for-all(&){$END$};
// SP
@include for-mobile-only(&){};
// PC
@include for-pc-only(&){};


こちらもどうぞ!

Sassで調子に乗って@extendしまくった過去を反省し、良い継承の仕方を模索する - Qiita






  1. 必ずしもメディアクエリ内に書く必要はないが、SP, PCでデザインの差が大きい場合は分けた方が管理しやすい。 



  2. 最近のHTML5 Boilerplateでは、もうこのようなコンディショナルコメントは採用されていない。なぜ今だにIE8対応が要件としてあるのかは謎である。