はじめに
レスポンシヴデザインのコーディングで度々出会う、PCとスマホでレイアウトが異なるデザイン。
今回のお仕事で出会ったデザインは次のようなものでした。
よくある横並びを縦並びに変えたように見えますが、PCで左列にある画像が、スマホでは文章とリンクの間に入っているところが少々やっかいです。
今回の記事は、このデザインについて順を追ってコーディングしていく様子を解説します。
また、以前にも似たような内容で、PCとスマホで見出し・文章・画像のレイアウトが異なる場合の記事を書きましたので、こちらもご参考ください。
PCとスマホでレイアウトが違う場合のCSSをじっくりコーディング
設計
CSSグリッドレイアウトを使う
今回も、CSSグリッドレイアウト(display: grid
)を使う方針で考えます。
Can I Useによると、CSSグリッドレイアウトは記事執筆の2021年5月時点で主要ブラウザのほとんどをカバーしています。
CSS Grid Layout Module Level 1 - Can I Use
IEのみ、ベンダープレフィックスが必要となっています。IE対応まで必要な場合は、Autoprefixerを使うなどして対応してください。
HTML設計
<div class="contents">
<div class="contents__title">
<p>Catchcopy</p>
<h2>記事のタイトル</h2>
</div>
<p class="contents__text">親譲りの無鉄砲で小供の時から損ばかりしている。小学校に居る時分学校の二階から飛び降りて一週間ほど腰を抜かした事がある。なぜそんな無闇をしたと聞く人があるかも知れぬ。</p>
<div class="contents__image">
<img src="https://picsum.photos/400/300" alt="" decoding="async" />
</div>
<div class="contents__link">
<a class="contents__linkItem" href="" target="_blank" rel="noopener noreferrer">
<span>READ MORE</span>
</a>
</div>
</div>
CSSグリッドレイアウト(display: grid
)を使うと、画像とそれ以外を左右に分けるレイアウトのdiv
すら不要なので、HTMLがスッキリ書けますね。
ブレイクポイント
ブレイクポイントは@media only screen and ( max-width: 767px )
とし、PCのレイアウトから組み始め、ブラウザの横幅が768px未満になったところからスマホのレイアウトになるよう設定します。
CSSコーディング
レイアウトに関係ない部分
まず、今回のレイアウトと関係のない部分は今回のメインテーマではないので、先にスタイルを書いておきます。
SCSS記法のSassを使用します。
.contents {
width: 900px;
max-width: 100%;
margin: 0 auto;
}
.contents__image {
img {
width: 100%;
}
}
.contents__title {
p {
margin-bottom: 15px;
font-size: 12px;
color: #bababa;
}
h2 {
font-size: 38px;
font-weight: normal;
@media only screen and ( max-width: 768px) {
font-size: 20px;
}
}
}
.contents__text {
font-size: 16px;
line-height: 2;
margin: 30px 0;
}
.contents__link {
@media only screen and ( max-width: 768px) {
margin-top: 30px;
text-align: center;
}
}
.contents__linkItem {
font-size: 14px;
color: #4659ab;
text-decoration: none;
&::after {
margin-left: 1em;
content: ">";
}
&:hover {
border-bottom: 1px solid #4659ab;
}
}
この時点での見た目は次のようになります。
このままでスマホのレイアウトは完成しています。
ただし今回は先にPCファーストで組んで後からスマホのレイアウトに変換する方針のため、ここからいったんPC用に組み、あとで元に戻すような書き方をします。
グリッドコンテナーを定義
外側の.contents
にdisplay: grid;
を指定することで、これがグリッドコンテナーとなります。また、グリッドコンテナーの直下の要素が自動的にグリッドアイテムとなります。
.contents {
width: 900px;
max-width: 100%;
margin: 0 auto;
display: grid;}
.contents__image {
img {
width: 100%;
}
}
.contents__title {
p {
margin-bottom: 15px;
font-size: 12px;
color: #bababa;
}
h2 {
font-size: 38px;
font-weight: normal;
@media only screen and ( max-width: 768px) {
font-size: 20px;
}
}
}
.contents__text {
font-size: 16px;
line-height: 2;
margin: 30px 0;
}
.contents__link {
@media only screen and ( max-width: 768px) {
margin-top: 30px;
text-align: center;
}
}
.contents__linkItem {
font-size: 14px;
color: #4659ab;
text-decoration: none;
&::after {
margin-left: 1em;
content: ">";
}
&:hover {
border-bottom: 1px solid #4659ab;
}
}
グリッドコンテナー・グリッドアイテムを定義しただけでは見た目の変化はほとんどありません。
しかしGoogle Chromeのディベロッパーツールで確認すると、指定前と異なり、要素の隣にgridという表示が確認できます。(記事執筆時点のChromeのインターフェイスです。)
配置する要素にグリッド用の名前をつける
次に、配置をコントロールしたい見出しとキャッチコピーのセット、テキスト、画像、リンクの要素に、グリッド用の名前を付けていきます。
CSSに、以下のような追加を行います。
.contents {
width: 900px;
max-width: 100%;
margin: 0 auto;
display: grid;
}
.contents__image {
grid-area: image;
img {
width: 100%;
}
}
.contents__title {
grid-area: title;
p {
margin-bottom: 15px;
font-size: 12px;
color: #bababa;
}
h2 {
font-size: 38px;
font-weight: normal;
@media only screen and ( max-width: 768px) {
font-size: 20px;
}
}
}
.contents__text {
grid-area: text; font-size: 16px;
line-height: 2;
margin: 30px 0;
}
.contents__link {
grid-area: link;
@media only screen and ( max-width: 768px) {
margin-top: 30px;
text-align: center;
}
}
.contents__linkItem {
font-size: 14px;
color: #4659ab;
text-decoration: none;
&::after {
margin-left: 1em;
content: ">";
}
&:hover {
border-bottom: 1px solid #4659ab;
}
}
追加したtitle
、image
、text
、link
といった名前は自由なもので構いません。
これらを追加しても見た目に変化はありませんが、これでそれぞれの要素のレイアウトを制御できるようになりました。
グリッドアイテムの配置を定義する
グリッドコンテナーの要素(.contents
)に、grid-template
とcolumn-gap
というプロパティを以下のよう指定します。
.contents {
width: 900px;
max-width: 100%;
margin: 0 auto;
display: grid; grid-template: "image title" 3fr "image text" auto "image link" 2fr / 50% auto; column-gap: 30px;}
.contents__image {
grid-area: image;
img {
width: 100%;
}
}
.contents__title {
grid-area: title;
p {
margin-bottom: 15px;
font-size: 12px;
color: #bababa;
}
h2 {
font-size: 38px;
font-weight: normal;
@media only screen and ( max-width: 768px) {
font-size: 20px;
}
}
}
.contents__text {
grid-area: text;
font-size: 16px;
line-height: 2;
margin: 30px 0;
}
.contents__link {
grid-area: link;
@media only screen and ( max-width: 768px) {
margin-top: 30px;
text-align: center;
}
}
.contents__linkItem {
font-size: 14px;
color: #4659ab;
text-decoration: none;
&::after {
margin-left: 1em;
content: ">";
}
&:hover {
border-bottom: 1px solid #4659ab;
}
}
このコードの追加により、見た目は次のようになります。
要素配置が完成形と若干異なりますが、ほぼ想定するPCのレイアウトと同じになったといえます。
grid-template
の中の""
で囲った部分によって、次のようなイメージで、前のセクションで定義した名前の着いたエリアが配置されます。
この部分だけ見ると、次のように書いたものと同じように動きます。
grid-template-areas:
"image title"
"image text"
"image link";
grid-template
の最下段に書いてある50% auto;
では、左列(画像)の横幅を50%
とし、右列は残りの幅をよしなに使うという指定になります。
grid-template
の各行にある○fr
やauto
で、各行の高さを定義しています。まずauto
が指定してあるtext
の行で必要最低限の分の高さをとり、残った分をtitle
の行とlink
の行で3:2の配分になるように分けるということになります。
"image title" 3fr
"image text" auto
"image link" 2fr /
また、column-gap: 30px;
で、左右の列間の余白を30px
開けるようにします。
このプロパティは以前grid-column-gap
というプロパティ名だったようですが、column-gap
が最新の定義のようです。
column-gap (grid-column-gap) - CSS: カスケーディングスタイルシート | MDN
見出しの領域を下寄せに
デザインの指定では、右列が縦位置中央に寄っているような形なので、上寄せになっている見出しの領域を下寄せにします。
見出しの領域に対してalign-self: flex-end;
を指定します。
//(略)
.contents__title {
grid-area: title;
align-self: flex-end;
p {
margin-bottom: 15px;
font-size: 12px;
color: #bababa;
}
h2 {
font-size: 38px;
font-weight: normal;
@media only screen and ( max-width: 768px) {
font-size: 20px;
}
}
}
//(略)
これでPCの見た目が完成し、次のようになりました。
スマホの見た目を作る
最後に、メディアクエリを指定してスマホの見た目を作っていきます。
メディアクエリの中で、grid-template
の値を上書きするだけです。
.contents {
width: 900px;
max-width: 100%;
margin: 0 auto;
display: grid;
grid-template:
"image title" 3fr
"image text" auto
"image link" 2fr /
50% auto;
column-gap: 30px;
@media only screen and ( max-width: 768px) { grid-template: "title" auto "text" auto "image" auto "link" auto / auto; }}
.contents__image {
grid-area: image;
img {
width: 100%;
}
}
.contents__title {
grid-area: title;
align-self: flex-end;
p {
margin-bottom: 15px;
font-size: 12px;
color: #bababa;
}
h2 {
font-size: 38px;
font-weight: normal;
@media only screen and ( max-width: 768px) {
font-size: 20px;
}
}
}
.contents__text {
grid-area: text;
font-size: 16px;
line-height: 2;
margin: 30px 0;
}
.contents__link {
grid-area: link;
@media only screen and ( max-width: 768px) {
margin-top: 30px;
text-align: center;
}
}
.contents__linkItem {
font-size: 14px;
color: #4659ab;
text-decoration: none;
&::after {
margin-left: 1em;
content: ">";
}
&:hover {
border-bottom: 1px solid #4659ab;
}
}
grid-template
で、すべての要素を1列の縦に並べるように指定しました。
高さは、それぞれの要素が持つ高さを保って貰えばよいのですべてauto
、横幅もauto
です。
これで、冒頭で紹介したレイアウトの実装が完了しました。
IE対応
IE対応については以前の記事 PCとスマホでレイアウトが違う場合のCSSをじっくりコーディング でも書きましたが、手動で対応するのは現実的ではありません。
Autoprefixerを使い、自動でベンダープレフィックスを付与するようにしてください。
終わりに
この記事では、CSSグリッドレイアウトを使って、PCとスマホで別のレイアウトを表現する方法を解説しました。
最終的なコードをご覧になりたい方は、以下のCodePenにアクセスしてください。
先日Windows 10におけるIE11のサポート終了まであと約1年と発表されましたが、CSSグリッドレイアウトのような便利な書き方がどんどんできるようになるのは嬉しいことです。
実際のお仕事でもどんどん利用し、知見を貯めていきたいと思います。
最後までお読みいただきありがとうございました。