SassでBEM記法を使っていると、綺麗にコーディングできない場面が出てきていました。
どんな場面か。それはBlockよりも親要素のクラスでElementとの子孫セレクタを作りたいときです。これにはSassの@at-root
を使うのですが、ネットで調べても中々思い通りの手法にたどり着けず、なんとか自分で使い方を理解し解決できた次第です。(コードにするとなんてことない内容なのですが…)
例えばどんな実装か
実装として、メインビジュアルの中身を以下2種類のどちらかに切り替える機能があるとします。
- 画像(<img>)
- 動画(<iframe>など)
これらをレスポンシブ対応する場合、img
とiframe
のCSS内容を変える必要があるとします。
JavaScirptで「img
or iframe
」を判別して動的にModifierクラスを付与する解決方法もありますが、今回はサーバーサイドでbody
タグに以下クラスが予め付与されている前提とします。
- 画像なら
has-image
- 動画なら
has-video
予めbody
に付与されるクラス名を元に、BlockやElementのCSSプロパティを複合セレクタで変更します。
コードやクラス付与状況の例
実際にコードの実装例です。以下のHTML(PHP)がメインビジュアル用のコードです。
<body class="has-video">
<div class="main-visual">
<div class="main-visual__inner">
<?php メインビジュアル表示関数など(); ?>
</div>
</div>
</body>
「main-visual」Blockの外、body
に「has-video」というクラスが付与されています。これはCMS側で「メインビジュアルには画像ではなく、動画を表示する」という設定がされている状況です。画像ならばbodyタグには「has-image」です。
それでは、この親要素(bodyタグ)のクラスを元にメインビジュアルのCSSを切り替える@at-root
を使用したコードを示します。
.main-visual {
&__inner {
width: 100%;
padding: 0;
text-align: center;
}
@at-root .has-video & {
&__inner {
position: relative;
padding-top: 56.25%;
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
}
}
肝は9行目の「@at-root」と「&」です。@at-root
は入れ子状態のセレクタを外に出す機能で、&(アンパサンド)は直前の親セレクタ名(今回で言えば”.main-visual”)を返す機能になっています。2つでクラス名を挟むと以下のCSSで出力されます。
.main-visual__inner {
width: 100%;
padding: 0;
text-align: center;
}
.has-video .main-visual__inner {
position: relative;
padding-top: 56.25%;
}
.has-video .main-visual__inner iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
このような形で、Blockより親要素のクラスを元に、Elementとの子孫セレクタを作ることができました。
(このコンパイルが通ったSassのバージョンは「3.4.23」です)
ちなみに今までの自分はこんな風に記述していました。コーディングしていたときは歯痒かったですね…。
.main-visual {
&__inner {
width: 100%;
padding: 0;
text-align: center;
}
}
.has-video {
.main-visual__inner {
width: 100%;
position: relative;
padding-top: 56.25%;
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
}
そのほか「_has-video.scss」ファイル内に記述したりなど。わだかまりが一つなくなり良かったです。