この記事では「画像の上に要素を重ねるレイアウトの実装方法」について解説します。画像の上に要素を重ねるレイアウトはWeb制作において出てくる頻出レイアウトの一つなので、実装方法を覚えておきましょう。
- 画像の上に要素を重ねるレイアウトの実装方法が分かる
- 擬似要素の活用方法が分かる
今回実装するデザインはnoteの【中–上級編】XDカンプコーディングの一部となります。
目次
画像の上に要素を重ねるレイアウトの実装
画像の上に要素が重なっているレイアウトとは以下のようなデザインです。
今回解説するイメージは以下のようになります。
See the Pen 画像の上に要素を重ねるレイアウト by 山中滉大 (@tips-web) on CodePen.
こちらの実装コード全文は以下になります。
<div class="p-contents">
<div class="l-inner">
<div class="p-textImgBox">
<div class="p-textImgBox__inner">
<div class="p-textImgBox__img">
<img src="images/img1.jpg" alt="一人一人に最適な治療法を">
</div>
<div class="p-textImgBox__textBox">
<span class="p-textImgBox__number"></span>
<h3 class="p-textImgBox__title">一人一人に最適な治療法を</h3>
<p class="p-textImgBox__text">当院では、虫歯などの一般治療はもちろんランパセラピー
専門医院としての矯正歯科・予防や健診でお口の健康から
心身の健康を目指します。より良い歯科治療をお求めの患
者さまは是非ともご相談ください。<br>
治療内容を丁寧にわかりやすく説明をし、患者さまが安心
して頂けるよう十分なカウンセリングを行います。</p>
<a href="" class="p-textImgBox__button c-button">診療内容</a>
</div>
</div>
</div>
<div class="p-textImgBox">
<div class="p-textImgBox__inner">
<div class="p-textImgBox__img">
<img src="images/img2.jpg" alt="親子で安心の設備">
</div>
<div class="p-textImgBox__textBox">
<span class="p-textImgBox__number"></span>
<h3 class="p-textImgBox__title">親子で安心の設備</h3>
<p class="p-textImgBox__text">当院の診療室は全て個室、半個室になっていますのでお子
様と安心してご来院いただけます。最新機器を導入した繊
密な治療と、モニターを使用した丁寧な説明を行うことで
安心・安全な診療を提供しております。</p>
<a href="" class="p-textImgBox__button c-button">設備紹介</a>
</div>
</div>
</div>
<div class="p-textImgBox">
<div class="p-textImgBox__inner">
<div class="p-textImgBox__img">
<img src="images/img3.jpg" alt="女性ドクター・スタッフが多く在籍">
</div>
<div class="p-textImgBox__textBox">
<span class="p-textImgBox__number"></span>
<h3 class="p-textImgBox__title">女性ドクター・スタッフが多く在籍</h3>
<p class="p-textImgBox__text">女性ならではのきめ細かな気配りを活かしながら、小児歯
科や予防治療、根管治療などの治療にあたっています。特
にお子さまは男性の歯科医師が近づいただけで泣いてしま
うこともありますので、お子さまの診療には、小児歯科の
経験が豊富な女性ドクターを中心に対応しています。</p>
<a href="" class="p-textImgBox__button c-button">スタッフ紹介</a>
</div>
</div>
</div>
</div>
</div>
:root {
--font-noto: 'Noto Sans JP', sans-serif;
--base-color: #998969;
--sub-color: #AE9F7F;
--color-black: #565656;
--color-gray: #F4F4F2;
--color-white: #Fff;
}
body {
background-color: var(--color-gray);
font-family: var(--font-noto);
letter-spacing: 0.1em;
}
.l-inner {
margin-right: auto;
margin-left: auto;
max-width: 600px;
}
@media screen and (min-width: 760px) {
.l-inner {
max-width: 1232px;
padding-right: 16px;
padding-left: 16px;
}
}
@media screen and (min-width: 760px) {
.p-contents {
padding-top: 120px;
padding-bottom: 120px;
}
}
.c-button {
font-size: 18px;
line-height: calc(21.6/18);
font-weight: 400;
display: block;
position: relative;
border-radius: 8px;
border: 1px solid var(--base-color);
background-color: var(--color-white);
padding: 21px 48px 23px;
text-align: center;
color: var(--base-color);
letter-spacing: 0.1em;
transition: color .4s, background-color .4s;
}
.c-button::after {
content: '';
width: 8px;
height: 8px;
border: 0;
border-top: solid 2px var(--base-color);
border-right: solid 2px var(--base-color);
position: absolute;
top: 50%;
right: 36px;
margin-top: -4px;
transform: rotate(45deg);
transition: border-color .4s;
}
.c-button:hover {
background-color: var(--base-color);
color: var(--color-white);
}
.c-button:hover::after {
border-color: var(--color-white);
}
.p-textImgBox {
margin-top: 60px;
counter-increment: number 1;
}
@media screen and (min-width: 760px) {
.p-textImgBox {
margin-top: 62px;
}
}
.p-textImgBox__inner {
display: block;
}
@media screen and (min-width: 760px) {
.p-textImgBox__inner {
display: flex;
}
}
.p-textImgBox__textBox {
position: relative;
background-color: var(--color-white);
padding: 60px 88px 42px;
width: 100%;
z-index: 1;
}
@media screen and (min-width: 760px) {
.p-textImgBox__textBox {
padding: 60px 72px 48px;
margin-top: 50px;
}
}
.p-textImgBox__textBox::before {
position: absolute;
content: "";
width: 100%;
height: 53px;
background-color: var(--color-white);
top: -53px;
left: 0;
z-index: -1;
}
@media screen and (min-width: 760px) {
.p-textImgBox__textBox::before {
width: 150px;
height: 100%;
top: 0;
left: -150px;
}
}
.p-textImgBox__title {
font-size: 22px;
line-height: calc(26.4/22);
font-weight: 600;
color: var(--color-black);
text-align: center;
}
@media screen and (min-width: 760px) {
.p-textImgBox__title {
text-align: left;
}
}
.p-textImgBox__text {
font-size: 16px;
line-height: calc(27.2/16);
font-weight: 400;
color: var(--color-black);
margin-top: 39px;
}
.p-textImgBox__img {
width: 100%;
max-width: 500px;
display: block;
position: relative;
z-index: 5;
margin-right: auto;
margin-left: auto;
}
@media screen and (min-width: 760px) {
.p-textImgBox__img {
max-width: 600px;
}
}
.p-textImgBox__img img {
aspect-ratio: 600 / 400;
height: auto;
object-fit: cover;
}
.p-textImgBox__button {
margin-top: 40px;
}
.p-textImgBox__number::before {
position: absolute;
font-size: 70px;
letter-spacing: 0.1em;
line-height: calc(84/70);
color: var(--base-color);
right: 25px;
font-weight: 100;
content: "0"counter(number) " ";
top: 0;
}
@media screen and (min-width: 760px) {
.p-textImgBox__number::before {
right: 50px;
top: -50px;
}
.p-textImgBox:nth-child(even) .p-textImgBox__inner {
flex-direction: row-reverse;
}
.p-textImgBox:nth-child(even) .p-textImgBox__textBox::before {
left: initial;
right: -150px;
}
.p-textImgBox:nth-child(even) .p-textImgBox__number::before {
right: initial;
left: 50px;
}
}
ここからコードについて解説していきます。
HTMLの解説
HTMLの基本構造は、以下のようにp-textImgBox要素を中心に構成されています。
<div class="p-textImgBox">
<div class="p-textImgBox__inner">
<div class="p-textImgBox__img">
<img src="images/img1.jpg" alt="一人一人に最適な治療法を">
</div>
<div class="p-textImgBox__textBox">
<span class="p-textImgBox__number"></span>
<h3 class="p-textImgBox__title">一人一人に最適な治療法を</h3>
<p class="p-textImgBox__text">当院では、虫歯などの一般治療はもちろんランパセラピー
専門医院としての矯正歯科・予防や健診でお口の健康から
心身の健康を目指します。より良い歯科治療をお求めの患
者さまは是非ともご相談ください。<br>
治療内容を丁寧にわかりやすく説明をし、患者さまが安心
して頂けるよう十分なカウンセリングを行います。</p>
<a href="" class="p-textImgBox__button c-button">診療内容</a>
</div>
</div>
</div>
p-textImgBox__innerを、子要素の画像とテキストブロックをflexboxで横並びに配置できるように配置しておきます。
2つ目のp-textImgBox要素では、画像とテキストが逆になったデザインですが、1つ目のp-textImgBoxとまったく同じHTMLで作成します。
逆にする配置は、後述するCSSで配置していきます。
CSSの解説:画像とテキストが重なっている部分
まず、テキストと画像をCSSで横並びに配置します。
.p-textImgBox__inner {
display: flex;
}
テキスト周りの部分は以下のCSSです。テキストと画像の間の余白はデザインと同じように設定します。画像とテキストの上下のずれは、p-textImgBox__textBoxに上マージンを適用してずらします。
.p-textImgBox__textBox {
position: relative;
background-color: var(--color-white);
padding: 60px 88px 42px;
width: 100%;
z-index: 1;
}
@media screen and (min-width: 760px) {
.p-textImgBox__textBox {
padding: 60px 72px 48px;
margin-top: 50px;
}
}
今回の実装のポイントである「画像とテキストの背景が重なっている部分」は、疑似要素で作成します。
分かりやすくするために、画像とテキストが被っている部分を背景色を赤で作成します。
.p-textImgBox__textBox::before {
position: absolute;
content: "";
width: 100%;
height: 53px;
/* background-color: var(--color-white); */
background-color: red;
top: -53px;
left: 0;
z-index: -1;
}
@media screen and (min-width: 760px) {
.p-textImgBox__textBox::before {
width: 150px;
height: 100%;
top: 0;
left: -150px;
}
}
SP時も同様に疑似要素で作成することができます(赤い背景部分)。
まとめると、以下のようなイメージになります。
このような配置を、positionプロパティを使ったり、ネガティブマージンを使うなどの方法で作成することもできます。
CSSの解説:左右交互のレイアウト
PC時の左右交互配置のスタイルは以下のようになります。
@media screen and (min-width: 760px) {
.p-textImgBox__number::before {
right: 50px;
top: -50px;
}
.p-textImgBox:nth-child(even) .p-textImgBox__inner {
flex-direction: row-reverse;
}
.p-textImgBox:nth-child(even) .p-textImgBox__textBox::before {
left: initial;
right: -150px;
}
.p-textImgBox:nth-child(even) .p-textImgBox__number::before {
right: initial;
left: 50px;
}
}
nth-child(even)で偶数番目だけスタイルを適用、nth-child(odd)で奇数番目だけスタイルを適用することができます。今回の場合、p-textImgBoxの2番目、4番目...だけ画像とテキストの配置が逆になるように指定しています。
CSSの解説:ナンバーのカウント
HTMLの以下の部分に適用されるナンバー(01,02,03…)を、要素が増えたら自動的に数が増えるように指定します。
<span class="p-textImgBox__number"></span>
.p-textImgBox {
counter-increment: number 1;
}
.p-textImgBox__number::before {
content: "0"counter(number) " ";
}
counter-incrementプロパティを使うと、要素が増えると自動的に連番が付くようにできます。
まとめ
画像の上に要素を重ねるレイアウトの実装方法について解説しました。positionプロパティやネガティブマージンで実装することもできますが、今回解説した疑似要素で実装することもできるので覚えておきましょう。