0
1

More than 3 years have passed since last update.

Grid LayoutのIE向けベンダープレフィックスをAutoprefixerに任せるなら「自動配置」に注意する

Last updated at Posted at 2021-03-23

はじめに

CSSベンダープレフィックスは手打ちでやろうとすると割と厄介ですが、Autoprefixerは自動でこのベンダープレフィックスを付与してくれるため、コーディング量を少なくしメンテナンス性も高めることができるとても便利なものです。

しかし、Autoprefixerの挙動を理解していないと、IEと従来版Edge対応時に「自動配置」に振り回されるかもしれないので備忘録を残します。
決して、Autoprefixerが悪いという話ではなく、使うときはここに気をつけようという趣旨になります。

なお、Autoprefixerの導入やCSS Grid Layoutの詳しい使い方等については、本記事では扱いません。

CSS Grid Layoutについては以下の記事がとても参考になると思います。
CSS Grid Layout を極める!(基礎編)
本記事でもこの記事の例として出ているレイアウトを元に進めていきます。

(Autoprefixer version: 10.2.5)

結論

  • Grid Layoutでグリッドを手動配置し、Autoprefixerで-ms-ベンダープレフィックスをつけるときは、エリア名をつけて配置する
  • 本当にGridでないといけないのか再考する

CSS Grid LayoutのIEベンダープレフィックス

CSS Grid Layoutは縦横の2次元レイアウトを簡単に作成できる便利なCSSの機能です。

Can I Useによると、IEでのサポートはこんな感じ。
スクリーンショット 2021-03-22 11.20.08.png

Partial support with prefix: -ms-

-ms-というベンダープレフィックスを使えば、一部使用できます。
Partial supportとは古いバージョンのgridには対応してるよーという意味とのこと。

Autoprefixerでgridに自動で-ms-プレフィックスを付与する

Autoprefixerのgridのプレフィックスオプションを有効にする

※筆者の環境ではgulpを導入しているため、gulpでの説明となります。

Autoprefixerでは、gridのIE向けベンダープレフィックスはデフォルトで無効になっています。
まず、それを有効にする必要があるので、grid: 'autoplace'を指定します。

公式Readmeに付け足し
gulp.task('autoprefixer', () => {
  const autoprefixer = require('autoprefixer')
  const sourcemaps = require('gulp-sourcemaps')
  const postcss = require('gulp-postcss')

  return gulp.src('./src/*.css')
    .pipe(sourcemaps.init())
    .pipe(postcss([ autoprefixer({ grid: 'autoplace' }) ]))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('./dest'))
})

なぜデフォルト無効なのかについてはReadmeで言及されており、

Autoprefixer can be used to translate modern CSS Grid syntax into IE 10 and IE 11 syntax, but this polyfill will not work in 100% of cases. This is why it is disabled by default.

今のCSS Gridの記法をIE用に変換するpolyfillが完璧ではないため、とのことです。

そもそもIE対応が必要な上、Grid Layoutを使用する時は、明確な目的がある場合に絞るべきでしょう。

CSS Grid Layoutを適用する

ここでは、例えば以下のようなレイアウトを実現したいとします。

sample.jpg

以下のHTMLにGrid Layoutを当てていきます。

grid_sample.html
<div class="bl_grid">
  <div class="bl_grid_item">A</div>
  <div class="bl_grid_item">B</div>
  <div class="bl_grid_item">C</div>
</div>

必ず指定するのはもちろんdisplay: grid;です。
また、幅と高さも指定してしまいます。

style.css
.bl_grid {
  display: grid;
  grid-template-rows: 100px 50px;
  grid-template-columns: 100px 1fr;
}

問題はここからです。

今回は自動配置ではなく、以下のように配置を指定する必要があります。

A|B
A|C

方法は2つあります。

  1. grid-rowgrid-columnで行列番号を指定する
  2. エリアに名前をつけて指定する

配置指定:行列番号指定

では、まず1つ目の方法でやってみます。

style.css
.bl_grid {
  display: grid;
  grid-template-rows: 100px 50px;
  grid-template-columns: 100px 1fr;
}

.bl_grid_item:first-child {
  grid-row: 1 / 3;
  grid-column: 1 / 2;
}

.bl_grid_item:nth-child(2) {
  grid-row: 1 / 2;
  grid-column: 2 / 3;
}

.bl_grid_item:nth-child(3) {
  grid-row: 2 / 3;
  grid-column: 2 / 3;
}

いよいよ、Autoprefixerの出番です。
これでAutoprefixerを走らせてみると、以下のように出力されます。

dest/style.css
.bl_grid {
  display: -ms-grid;
  display: grid;

  -ms-grid-rows: 100px 50px;
  grid-template-rows: 100px 50px;
  -ms-grid-columns: 100px 1fr;
  grid-template-columns: 100px 1fr;
}

.bl_grid > *:nth-child(1) {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
}

.bl_grid > *:nth-child(2) {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
}

.bl_grid > *:nth-child(3) {
  -ms-grid-row: 2;
  -ms-grid-column: 1;
}

.bl_grid > *:nth-child(4) {
  -ms-grid-row: 2;
  -ms-grid-column: 2;
}

.bl_grid_item:first-child {
  -ms-grid-row: 1; 
  -ms-grid-row-span: 2; 
  grid-row: 1 / 3;

  -ms-grid-column: 1;
  -ms-grid-column-span: 1;
  grid-column: 1 / 2;
}

.bl_grid_item:nth-child(2) {
  -ms-grid-row: 1; 
  -ms-grid-row-span: 1; 
  grid-row: 1 / 2;

  -ms-grid-column: 2;
  -ms-grid-column-span: 1;
  grid-column: 2 / 3;
}

.bl_grid_item:nth-child(3) {
  -ms-grid-row: 2; 
  -ms-grid-row-span: 1; 
  grid-row: 2 / 3;

  -ms-grid-column: 2;
  -ms-grid-column-span: 1;
  grid-column: 2 / 3;
}

全体的に-ms-が付与されました。

.bl_grid_item:first-childの部分を見てみます。

.bl_grid_item:first-child {
  -ms-grid-row: 1; 
  -ms-grid-row-span: 2; 
  grid-row: 1 / 3;

  -ms-grid-column: 1;
  -ms-grid-column-span: 1;
  grid-column: 1 / 2;
}

-ms-grid-row-spanが指定していなかったオプションですが、そのグリッドエリアをどれくらい引き伸ばすかを指定することが出来ます。
-ms-grid-row-span-ms-grid-column-spanはIEと従来版Edgeにのみ存在するオプションで、他のブラウザではgrid-row: 1 span 2;のように指定することで同じ効果が得られます。

さて、いい感じに指定できたように見えますが、実はこれ、うまく機能しませず、↓こうなります。(AとCが重なっている)

Untitled Diagram.jpg

なぜならば、以下の記述が追加されているためです。

自動追加された部分
.bl_grid > *:nth-child(1) {
  -ms-grid-row: 1;
  -ms-grid-column: 1;
}

.bl_grid > *:nth-child(2) {
  -ms-grid-row: 1;
  -ms-grid-column: 2;
}

.bl_grid > *:nth-child(3) {
  -ms-grid-row: 2;
  -ms-grid-column: 1;
}

.bl_grid > *:nth-child(4) {
  -ms-grid-row: 2;
  -ms-grid-column: 2;
}

なんぞこれ。

コードを読むと、.bl_gridの子要素を左上から順番に4つ並べているようです。
これはAutoprefixerのIEのグリッド自動配置機能によるものです。

これは、先程指定したオプションのgrid: 'autoplace'によって有効になり、grid-template-rowsgrid-template-columnsが指定されているときに自動配置を行うという機能になります。

この機能によって自分で書いた記述ではなく自動追加された方が参照されるので、意図した配置になりません。(下に自分が記述したほうが優先されない理由は、CSSの優先順位によるものです。)

Autoprefixerのオプション/* autoprefixer grid: no-autoplace */をグリッドで指定して、自動配置を無効にすることで回避できます。

.bl_grid {
  /* autoprefixer grid: no-autoplace */
  display: grid;
  grid-template-rows: 100px 50px;
  grid-template-columns: 100px 1fr;
}

しかし、CSS内にAutoprefixerのオプションを記述するのはあまりスマートではない気がしてしまいます。

配置指定: 【推奨】 エリア名指定

Readmeにも以下のように書いてあります。

If manual cell placement is required, we recommend using grid-template or grid-template-areas
訳:手動でセルを配置する場合は、grid-templateもしくはgrid-template-areasの使用を推奨します。

また、

If grid-template or grid-template-areas has been set, Autoprefixer will use area based cell placement instead.
訳:grid-templategrid-template-areasが設定されている場合、エリアに基づくセル配置を行います。

ということで、手動で配置したい場合は大人しくエリアに名前をつけて指定するほうがベターでしょう。

幅と高さは指定していましたので、grid-template-areasを使用してみます。

エリア名指定
.bl_grid {
  display: grid;
  grid-template-rows: 100px 50px;
  grid-template-columns: 100px 1fr;
  grid-template-areas:
  'gridA gridB'
  'gridA gridC';
}

.bl_grid_item:first-child {
  grid-area: gridA;
}

.bl_grid_item:nth-child(2) {
  grid-area: gridB;
}

.bl_grid_item:nth-child(3) {
  grid-area: gridC;
}

もしくは、短縮プロパティgrid-templateを用いると少し短く記述することが出来ます。

エリア名指定(短縮プロパティ)
.bl_grid {
  display: grid;
  grid-template: 
    'gridA gridB' 100px
    'gridA gridC' 50px
    / 100px 1fr;
}

.bl_grid_item:first-child {
  grid-area: gridA;
}

.bl_grid_item:nth-child(2) {
  grid-area: gridB;
}

.bl_grid_item:nth-child(3) {
  grid-area: gridC;
}

さて、Autoprefixerくんを走らせると、、、

dest/style.css
.bl_grid {
  display: -ms-grid;
  display: grid;

  -ms-grid-rows: 100px 50px;
  grid-template-rows: 100px 50px;
  -ms-grid-columns: 100px 1fr;
  grid-template-columns: 100px 1fr;
  grid-template-areas:
    "gridA gridB"
    "gridA gridC";
}

.bl_grid_item:first-child {
  -ms-grid-row: 1;
  -ms-grid-row-span: 2;
  -ms-grid-column: 1;

  grid-area: gridA;
}

.bl_grid_item:nth-child(2) {
  -ms-grid-row: 1;
  -ms-grid-column: 2;

  grid-area: gridB;
}

.bl_grid_item:nth-child(3) {
  -ms-grid-row: 2;
  -ms-grid-column: 2;

  grid-area: gridC;
}

自動配置の部分がまるっとなくなりました。

grid-template-areasgrid-areaにプレフィックスがありませんが、IEと従来版Edgeにはないので正常な動きです。
代わりに-ms-grid-row-ms-grid-column-ms-grid-row-span-ms-grid-column-spanで実現しています。
ここを自動でやってくれるのはやっぱり便利ですね。

まとめ

Grid Layoutを使うときは、今後はエリアに名前をつける方で実装しようと思います。

grid内のアイテムもclassのnth-childで指定していたので今回問題に気づきましたが、idで指定していればそちらが優先されて気付かなかったということもあり得たかもしれません。(実証していませんが)

このようなプラグインは便利ですが、ちゃんとReadmeを読んで挙動を確認して、過信しすぎず出力されたものをちゃんと確認しようという学びになりました。

0
1
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
0
1