LoginSignup
24
25

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-08-12

一部の公共性の高い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対応が要件としてあるのかは謎である。 

24
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
25