OOCSSでよく取り上げられるMediaオブジェクトに4つのModifierを指定できるように作ってみました。以下の4つのパターンを組み合わせて指定できます。もちろんネストにも対応しています。
-
padding
プロパティで3段階の余白指定 -
vertical-align
プロパティで3段階の垂直位置指定 -
direction
プロパティで要素の反転 -
display: block;
でブレイクポイント以下で横並びから縦並びに変更
CodePenにデモを用意しています。
See the Pen Media object by ManabuYasuda (@gaku) on CodePen.
マークアップ
マークアップは以下のように記述します。BEMっぽくはなっていますが、マークアップをシンプルにするためにElement
をBlock__Element--Modifier
にはしていません。[]
はModifierであることを示しています。
<div class="c-media [c-media--small c-media--middle c-media--rev c-media--stack-md]">
<div class="c-media__item">
<img>
</div>
<div class="c-media__item">
<p></p>
</div>
</div>
ネストする場合は以下のように.c-media__item
の中に.c-media
を入れ子にします。
<div class="c-media">
<div class="c-media__item">
<img src="">
</div>
<div class="c-media__item">
<p></p>
<!-- ここからがネスト -->
<div class="c-media">
<div class="c-media__item">
<img src="">
</div>
<div class="c-media__item">
<p></p>
</div>
</div>
<!-- ネストの終了 -->
</div>
</div>
Sassコード
4つのModifierを指定するのでソースコードがやや複雑になっています。Sassが分かる人はCSSよりも把握しやすいと思います。
$media-gutter: 1em !default;
$media-gutter-small: ($my-media-gutter / 2) !default;
$media-gutter-large: ($my-media-gutter * 2) !default;
.c-media {
display: table;
width: 100%;
margin: 0;
padding: 0;
}
.c-media__item {
display: table-cell;
margin: 0;
padding: 0;
vertical-align: top;
&:not(:first-child) {
padding-left: $my-media-gutter;
}
& > :first-child {
margin-top: 0;
}
& > :last-child {
margin-bottom: 0;
}
}
.c-media__item > img {
display: block;
}
.c-media--middle {
> .c-media__item {
vertical-align: middle;
}
}
.c-media--bottom {
> .c-media__item {
vertical-align: bottom;
}
}
.c-media--rev {
text-align: left;
direction: rtl;
> .c-media__item {
text-align: left;
direction: ltr;
}
> .c-media__item:not(:first-child) {
padding-right: $my-media-gutter;
padding-left: 0;
}
}
.c-media--small {
> .c-media__item:not(:first-child) {
padding-left: $my-media-gutter-small;
}
&.c-media--rev > .c-media__item:not(:first-child) {
padding-right: $my-media-gutter-small;
padding-left: 0;
}
}
.c-media--large {
> .c-media__item:not(:first-child) {
padding-left: $my-media-gutter-large;
}
&.c-media--rev > .c-media__item:not(:first-child) {
padding-right: $my-media-gutter-large;
padding-left: 0;
}
}
@media screen and (max-width: 399px) {
.c-media--stack-sm {
> .c-media__item {
display: block;
}
> .c-media__item:not(:first-child) {
padding: $my-media-gutter 0 0;
}
> .c-media__item > img {
margin: auto;
}
&.c-media--small > .c-media__item:not(:first-child) {
padding: $my-media-gutter-small 0 0;
}
&.c-media--large > .c-media__item:not(:first-child) {
padding: $my-media-gutter-large 0 0;
}
}
}
@media screen and (max-width: 767px) {
.c-media--stack-md {
> .c-media__item {
display: block;
}
> .c-media__item:not(:first-child) {
padding: $my-media-gutter 0 0;
}
> .c-media__item > img {
margin: auto;
}
&.c-media--small > .c-media__item:not(:first-child) {
padding: $my-media-gutter-small 0 0;
}
&.c-media--large > .c-media__item:not(:first-child) {
padding: $my-media-gutter-large 0 0;
}
}
}
CSSコード
Sassコードをコンパイルすると以下のようになります。
.c-media {
display: table;
width: 100%;
margin: 0;
padding: 0;
}
.c-media__item {
display: table-cell;
margin: 0;
padding: 0;
vertical-align: top;
}
.c-media__item:not(:first-child) {
padding-left: 1em;
}
.c-media__item > :first-child {
margin-top: 0;
}
.c-media__item > :last-child {
margin-bottom: 0;
}
.c-media__item > img {
display: block;
}
.c-media--middle > .c-media__item {
vertical-align: middle;
}
.c-media--bottom > .c-media__item {
vertical-align: bottom;
}
.c-media--rev {
text-align: left;
direction: rtl;
}
.c-media--rev > .c-media__item {
text-align: left;
direction: ltr;
}
.c-media--rev > .c-media__item:not(:first-child) {
padding-right: 1em;
padding-left: 0;
}
.c-media--small > .c-media__item:not(:first-child) {
padding-left: 0.5em;
}
.c-media--small.c-media--rev > .c-media__item:not(:first-child) {
padding-right: 0.5em;
padding-left: 0;
}
.c-media--large > .c-media__item:not(:first-child) {
padding-left: 2em;
}
.c-media--large.c-media--rev > .c-media__item:not(:first-child) {
padding-right: 2em;
padding-left: 0;
}
@media screen and (max-width: 399px) {
.c-media--stack-sm > .c-media__item {
display: block;
}
.c-media--stack-sm > .c-media__item:not(:first-child) {
padding: 1em 0 0;
}
.c-media--stack-sm > .c-media__item > img {
margin: auto;
}
.c-media--stack-sm.c-media--small > .c-media__item:not(:first-child) {
padding: 0.5em 0 0;
}
.c-media--stack-sm.c-media--large > .c-media__item:not(:first-child) {
padding: 2em 0 0;
}
}
@media screen and (max-width: 767px) {
.c-media--stack-md > .c-media__item {
display: block;
}
.c-media--stack-md > .c-media__item:not(:first-child) {
padding: 1em 0 0;
}
.c-media--stack-md > .c-media__item > img {
margin: auto;
}
.c-media--stack-md.c-media--small > .c-media__item:not(:first-child) {
padding: 0.5em 0 0;
}
.c-media--stack-md.c-media--large > .c-media__item:not(:first-child) {
padding: 2em 0 0;
}
}
コードの解説
table-cell
を使用するとvertical-align
プロパティが指定できる
Mediaオブジェクトはfloat
プロパティを使ったものがよく使われていましたが、それでは垂直方向の変更ができません。vertical-align
プロパティを指定できるのはインラインレベルとテーブルセル要素です。
適用対象 インラインレベルとテーブルセル要素. It also applies to ::first-letter and ::first-line.
今回はtop
をデフォルトにしています。
.c-media {
display: table;
width: 100%;
margin: 0;
padding: 0;
}
.c-media__item {
display: table-cell;
margin: 0;
padding: 0;
vertical-align: top;
}
.c-media--middle > .c-media__item {
vertical-align: middle;
}
.c-media--bottom > .c-media__item {
vertical-align: bottom;
}
要素を反転させるdirection
プロパティ
float
プロパティを使用しないと要素の反転ができないかというと、そうではありません。direction
プロパティを使用すればテーブルでも反転することができます。
direction
プロパティはヘブライ語やアラビア語などの右から左へ読む言語で使用されるものです。親要素にdirection: rtl;
を指定することで反転、子要素にdirection: ltr;
を指定することで元の状態に戻します。
.c-media--rev {
text-align: left;
direction: rtl;
}
.c-media--rev > .c-media__item {
text-align: left;
direction: ltr;
}
これはinline-block
にも使用できるので覚えておくとレイアウトの幅が広がります。
:not(:first-child)
で余白指定をシンプルにする
余白の指定には否定擬似クラスの:not()
を使用しています。Mediaオブジェクトは__image
と__body
のようなクラスを指定することが多いですが、否定擬似クラスを使用すると、同じクラスでマークアップすることができます。
.c-media__item:not(:first-child) {
padding-left: 1em;
}
.c-media--small > .c-media__item:not(:first-child) {
padding-left: 0.5em;
}
.c-media--large > .c-media__item:not(:first-child) {
padding-left: 2em;
}
:not()
はIE9から使えます。もしIE8でも使いたい場合は以下のように隣接セレクタを使います(詳細度も同じです)。
.c-media__item + .c-media__item {}
あるブレイクポイント以下でblock
にする
画像とテキストが横並びになるMediaオブジェクトはスマホなどの横幅が狭いデバイスでは縦に並べたい場合もあると思います。メディアクエリを使用してブレイクポイント以下になったときにdisplay: table-cell
をblock
にすることで縦に配置します。
@media screen and (max-width: 767px) {
.c-media--stack-md > .c-media__item {
display: block;
}
.c-media--stack-md > .c-media__item:not(:first-child) {
padding: 1em 0 0;
}
.c-media--stack-md > .c-media__item > img {
margin: auto;
}
.c-media--stack-md.c-media--small > .c-media__item:not(:first-child) {
padding: 0.5em 0 0;
}
.c-media--stack-md.c-media--large > .c-media__item:not(:first-child) {
padding: 2em 0 0;
}
}
padding
プロパティは縦方向にだけ余白を指定するように変更しています。img
要素にmargin: auto;
を指定しているのはバランス的にセンタリングした方がいいのではということで指定しています。