WEB / HTML / CSS / VIDEO

LESSON 03

背景動画の上にタイトルを重ねて表示する方法

第2回では、CSSのheight: 100vhobject-fit: coverを使って、動画をブラウザー画面いっぱいに表示しました。

現在のHeroエリアには背景動画だけが表示されています。今回は、その動画の上にWebサイトのタイトル、説明文、リンクボタンを追加します。

動画と文字を同じHeroエリアに重ねるときに使うのが、position: relativeposition: absoluteの組み合わせです。今回は、親要素が「配置の基準」を作り、子要素が「基準の中で移動する」という関係を、段階を追って確認します。

この記事は「動画を使ったHeroエリアを作る」全5回の第3回です。
第2回の記事をまだ読んでいない場合は、先にCSSで動画を画面いっぱいに表示する方法を読み、動画を画面いっぱいに表示しておきましょう。

今回作成するもの

第2回で作成したHero背景動画の上に、次の内容を重ねて表示します。

  • 英文のラベル
  • Webサイトのタイトル
  • サイトの内容を伝える説明文
  • ページ内を移動するリンクボタン

完成すると、背景動画の中央付近にタイトルが表示され、リンクボタンから次のコンテンツへ移動できるようになります。

背景動画の上にタイトル、説明文、リンクボタンを重ねた完成画面
完成イメージ:背景動画の上にタイトル、説明文、リンクボタンを重ねたHeroエリア

この記事で学べること

  • HTMLでタイトル部分をひとまとまりにする方法
  • position: relativeで子要素の配置基準を作る方法
  • position: absoluteで文字を動画の上に重ねる方法
  • topleftで要素の位置を指定する方法
  • transform: translateY(-50%)で縦方向の中央を合わせる方法
  • z-indexで動画と文字の重なり順を指定する方法
  • 文字とリンクボタンの見た目をCSSで整える方法

作業を始める前の準備

今回は、第2回で作成したファイルを引き続き使用します。

作業用フォルダーを複製し、フォルダー名をweb-003へ変更しておきましょう。フォルダー内は、次の構成にします。

web-003/
├─ index.html
├─ css/
│  └─ style.css
└─ video/
   └─ hero.mp4

第2回終了時点のHTMLは、次のようになっています。

<div class="hero">
  <video autoplay muted loop playsinline>
    <source src="video/hero.mp4" type="video/mp4">
    お使いのブラウザーは動画の再生に対応していません。
  </video>
</div>

CSSは、次の状態です。

body {
  margin: 0;
}

.hero {
  position: relative;
  height: 100vh;
  overflow: hidden;
}

.hero video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

ファイルを複製したら、index.htmlをブラウザーで開き、動画が画面いっぱいに表示されることを確認してください。

STEP 1

タイトル部分のHTMLを追加する

最初に、動画の上へ表示する内容をHTMLに追加します。

videoタグの終了タグ</video>のあとに、次のコードを追加してください。

<div class="hero__content">
  <p class="hero__label">STACK CREATIVE CONTENTS COMPANY</p>
  <h1 class="hero__title">
    伝える技術を、<br>
    もっと分かりやすく。
  </h1>
  <p class="hero__text">
    書籍・動画・Web・教育コンテンツを通じて、<br>
    知識を「伝わる形」に変えます。
  </p>
  <a class="hero__button" href="#contents">活動を見る</a>
</div>

追加後のHeroエリアは、次のようになります。

<div class="hero">
  <video autoplay muted loop playsinline>
    <source src="video/hero.mp4" type="video/mp4">
    お使いのブラウザーは動画の再生に対応していません。
  </video>

  <div class="hero__content">
    <p class="hero__label">STACK CREATIVE CONTENTS COMPANY</p>
    <h1 class="hero__title">
      伝える技術を、<br>
      もっと分かりやすく。
    </h1>
    <p class="hero__text">
      書籍・動画・Web・教育コンテンツを通じて、<br>
      知識を「伝わる形」に変えます。
    </p>
    <a class="hero__button" href="#contents">活動を見る</a>
  </div>
</div>

hero__contentクラスの役割

タイトル、説明文、リンクボタンは、divタグで囲んでひとまとまりにしています。

<div class="hero__content">
  ...
</div>

このdivタグには、hero__contentというクラス名を付けました。CSSでこのまとまり全体の位置を指定すれば、中にあるタイトルや説明文、リンクボタンを一緒に移動できます。

h1タグの役割

h1タグは、そのページで最も重要な見出しに使用します。

<h1 class="hero__title">
  伝える技術を、<br>
  もっと分かりやすく。
</h1>

brタグは、文章を任意の位置で改行するためのタグです。この例では、タイトルを2行に分けています。

見た目を大きくするためだけにh1タグを使うのではありません。ページの中心となる内容を表す見出しであることを考えて使用します。

aタグの役割

aタグは、別のページやページ内の指定位置へ移動するリンクを作るために使用します。

<a class="hero__button" href="#contents">活動を見る</a>

href="#contents"は、同じページ内にあるid="contents"の位置へ移動する指定です。

今回の実習用HTMLには、あとで移動先となる要素も追加します。リンク先のidが存在しない場合、ボタンを押しても目的の位置へ移動できません。

STEP 2

動画を配置する層を設定する

次に、背景動画の配置方法と重なり順を指定します。

style.cssにある.hero videoのコードへ、positioninsetz-indexを追加します。

.hero video {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

position: absolute;

position: absoluteを指定すると、要素は通常の配置の流れから外れ、topleftなどを使って位置を指定できるようになります。

今回の背景動画は、position: relativeが指定されている親要素.heroを基準として配置されます。

inset: 0;

insetは、要素の上、右、下、左の位置をまとめて指定するプロパティです。

inset: 0;

これは、次の4行をまとめて書いたものと同じ意味です。

top: 0;
right: 0;
bottom: 0;
left: 0;

動画の四辺を親要素.heroの四辺に合わせるため、Heroエリア全体を覆う位置に配置されます。

z-index: 1;

z-indexは、要素が重なったときの表示順を指定します。

z-index: 1;

今回の動画には1を指定し、あとで追加するタイトル部分には2を指定します。数値の大きいタイトル部分が、動画より手前に表示されます。

STEP 3

タイトルを動画の上に配置する

続いて、タイトル部分を動画の上へ配置します。

style.cssに、次のコードを追加してください。

.hero__content {
  position: absolute;
  top: 50%;
  left: 8%;
  z-index: 2;
  color: #fff;
  transform: translateY(-50%);
}

このCSSによって、.hero__contentは親要素.heroを基準にして、動画より手前へ配置されます。

position: absolute;

タイトル部分を通常の配置の流れから外し、動画と同じHeroエリア内へ重ねて配置します。

top: 50%;

親要素.heroの上端から、Heroエリアの高さの50%にあたる位置へタイトル部分を移動します。

ただし、この段階では.hero__contentの上端が50%の位置に合います。そのままでは、タイトル部分全体がHeroエリアの中央より下へ寄って見えます。

left: 8%;

親要素.heroの左端から、Heroエリアの横幅の8%にあたる位置へタイトル部分を移動します。

ピクセルではなくパーセントで指定しているため、ブラウザーの横幅が変わると、左側の余白も画面幅に合わせて変化します。

transform: translateY(-50%);

top: 50%で移動したタイトル部分を、.hero__content自身の高さの50%だけ上へ戻します。

その結果、.hero__contentの縦方向の中央が、親要素.heroの高さ50%の位置に合います。

ここで重要なのは、toptranslateYに指定した二つの50%では、基準になる要素が異なることです。

指定 50%の基準
top: 50% 親要素.heroの高さ
translateY(-50%) .hero__content自身の高さ

「親の高さの半分まで移動してから、自分の高さの半分だけ戻す」と考えると、位置関係を理解しやすくなります。

color: #fff;

.hero__content内の文字色を白に指定します。

colorプロパティは子要素に引き継がれるため、ラベル、タイトル、説明文にも白が適用されます。ただし、リンクの文字色はブラウザー標準の色が適用される場合があるため、リンクボタンにはあとで改めて文字色を指定します。

relativeabsoluteの関係を理解しよう

position: relativeposition: absoluteは、どちらか一方がもう一方へ変化する指定ではありません。

今回は、親要素.herorelativeを指定し、子要素.hero__contentabsoluteを指定します。親と子へ別々の役割を与えることで、タイトルの配置位置を決めています。

次の図では、各CSSを一度に指定せず、1つずつ追加したときに配置がどのように変わるのかを確認します。

relativeとabsoluteの関係を理解する5段階 通常配置から、親要素を配置基準にし、子要素を絶対配置し、topとleftで位置を決め、translateYで縦中央を合わせるまでを5段階で示した図。 positionの指定なし .hero .hero__video .hero__content .hero { position: relative; } .hero=配置の基準 .hero__video .hero__content .hero__content { position: absolute; } .hero=配置の基準 .hero__video .hero__content top: 50%; left: 8%; .hero .hero__content left: 8% top: 50% transform: translateY(-50%); .hero .hero__content 自分の高さの50% top: 50% translateY(-50%)
通常配置から縦中央の補正までを示す5段階

1 まだpositionを指定していない状態

通常、HTML要素は、HTMLに記述した順番に上から下へ配置されます。

<div class="hero">
  <video>...</video>
  <div class="hero__content">...</div>
</div>

この段階では、動画のあとに.hero__contentが続くのが通常の配置です。タイトルは動画の上には重ならず、動画に続く位置へ押し出されます。

なお、第2回の.heroにはheight: 100vhoverflow: hiddenが指定されています。そのため、Heroエリアの外へ押し出されたタイトル部分は、ブラウザー上では隠れて見えない場合があります。

2 親要素.heroposition: relativeを指定

.hero {
  position: relative;
}

.heroposition: relativeを指定しても、topleftを指定していなければ、.hero自体の表示位置は基本的に変わりません。

この指定の目的は、子要素を絶対配置するときの「配置の基準となる枠」を作ることです。見た目には変化がなくても、.heroの左上が子要素の位置を測る基準になります。

3 子要素.hero__contentposition: absoluteを指定

.hero__content {
  position: absolute;
}

.hero__contentposition: absoluteを指定すると、タイトル部分は通常の配置の流れから外れます。

絶対配置された要素は、配置の基準にできる祖先要素を外側へ向かって探します。今回は、すぐ外側の.heroposition: relativeが指定されているため、.heroが基準になります。

この時点で、タイトル部分は通常の配置の流れから外れます。ただし、まだtopleftを指定していないため、移動先は決まっていません。

4 top: 50%left: 8%で位置を指定

.hero__content {
  position: absolute;
  top: 50%;
  left: 8%;
}

.heroの上端から高さ50%、左端から横幅8%の位置を求め、その交点に.hero__contentの左上を配置します。

この段階では、.hero__contentの左上が高さ50%の位置にあるため、タイトル部分の大半は中央線より下側に表示されます。

5 translateY(-50%)で中央位置を補正

.hero__content {
  position: absolute;
  top: 50%;
  left: 8%;
  transform: translateY(-50%);
}

最後に、.hero__contentを自身の高さの50%だけ上へ移動します。

これにより、.hero__contentの左上ではなく、縦方向の中央が.heroの高さ50%の位置に合います。

left: 8%に対する横方向の補正は行っていないため、.hero__contentの左端は、引き続き.heroの横幅8%の位置にあります。

この5段階をまとめると、.heroが「どこを基準にするか」を決め、.hero__contentが「その基準の中でどこへ移動するか」を決めています。

STEP 4

ラベルとタイトルの見た目を整える

タイトル部分の配置ができたら、文字サイズや余白を整えます。

まず、英文ラベルに次のCSSを指定します。

.hero__label {
  margin: 0 0 16px;
  font-size: 14px;
  letter-spacing: 0.2em;
}

margin: 0 0 16px;

marginは、要素の外側に余白を作るプロパティです。

今回のように3つの値を指定した場合は、上、左右、下の順に適用されます。

margin: 上 左右 下;

したがって、margin: 0 0 16px;は、上と左右の余白を0、下の余白を16pxにする指定です。

letter-spacing: 0.2em;

letter-spacingは、文字と文字の間隔を指定します。

emは、その要素の文字サイズを基準にする単位です。0.2emを指定すると、文字サイズの20%にあたる間隔が文字間に追加されます。

次に、タイトルへCSSを指定します。

.hero__title {
  margin: 0 0 24px;
  font-size: clamp(40px, 6vw, 80px);
  font-weight: 300;
  line-height: 1.15;
}

font-size: clamp(40px, 6vw, 80px);

font-sizeは文字サイズを指定するプロパティです。

clamp()を使うと、画面幅に応じて文字サイズを変化させながら、最小値と最大値も設定できます。

clamp(最小値, 基準値, 最大値)

今回の指定では、次のように文字サイズが決まります。

役割
40px 最小の文字サイズ
6vw 画面幅に応じて変化する文字サイズ
80px 最大の文字サイズ

1vwは、ブラウザーの表示領域の横幅の1%です。画面が広くなると文字も大きくなりますが、80pxより大きくはなりません。画面が狭くなっても、今回の段階では40pxより小さくなりません。

スマートフォンでの文字サイズや改行位置は、第4回で詳しく調整します。

font-weight: 300;

font-weightは、文字の太さを指定します。

300は比較的細い文字です。ただし、指定した太さのフォントが利用できない場合は、ブラウザーが利用可能な近い太さで表示します。

line-height: 1.15;

line-heightは行の高さを指定します。

単位を付けずに1.15と指定すると、文字サイズの1.15倍の行の高さになります。複数行の大きなタイトルでは、本文よりも行間を狭くすると、2行をひとまとまりとして見せやすくなります。

STEP 5

説明文の見た目を整える

説明文には、次のCSSを指定します。

.hero__text {
  margin: 0 0 32px;
  font-size: 18px;
  line-height: 1.8;
}

タイトルよりも文字サイズを小さくし、line-height: 1.8で行間を広めに設定しています。

margin-bottomにあたる位置へ32pxの余白を作ることで、説明文とリンクボタンの間隔も確保できます。

STEP 6

リンクをボタンの形にする

最後に、aタグで作成したリンクの見た目を整えます。

.hero__button {
  display: inline-block;
  padding: 14px 28px;
  border: 1px solid #fff;
  color: #fff;
  text-decoration: none;
}

display: inline-block;

aタグは、初期状態ではインライン要素として扱われます。

display: inline-blockを指定すると、文章の流れの中に配置できる性質を保ちながら、上下のpaddingや大きさを指定しやすくなります。

padding: 14px 28px;

paddingは、要素の内容と枠線との間に内側の余白を作るプロパティです。

値を二つ指定した場合は、1番目が上下、2番目が左右に適用されます。

padding: 上下 左右;

今回の指定では、上下に14px、左右に28pxの余白を追加しています。

border: 1px solid #fff;

borderは、要素の枠線を指定します。

border: 太さ 線の種類 色;

1px solid #fffは、太さ1ピクセルの実線を白で表示する指定です。

text-decoration: none;

リンクに初期状態で表示される下線を取り除きます。

リンクであることは、枠線によって視覚的に示されます。下線を外すだけでなく、リンクだと判断できる見た目を残すことが重要です。

マウスポインターを重ねたときの表示を設定する

リンクボタンにマウスポインターを重ねたときの変化も追加しておきましょう。

.hero__button:hover {
  background-color: #fff;
  color: #111;
}

:hoverは、要素にマウスポインターが重なっている状態を表す疑似クラスです。

背景を白、文字を濃い色へ変更することで、ボタンを操作できることが分かりやすくなります。

STEP 7

リンクの移動先を追加する

リンクボタンのhref属性には、#contentsを指定しました。

<a class="hero__button" href="#contents">活動を見る</a>

移動先を作るため、Heroエリアの終了タグ</div>のあとに、次のコードを追加します。

<section id="contents" class="contents">
  <h2>活動とコンテンツ</h2>
  <p>この位置に、Heroエリアに続くコンテンツを配置します。</p>
</section>

確認しやすいように、style.cssへ次のCSSも追加します。

.contents {
  padding: 80px 8%;
}

ブラウザーで「活動を見る」ボタンを押し、「活動とコンテンツ」の位置へ移動すれば、ページ内リンクは正しく機能しています。

STEP 8

完成コードを確認する

ここまでの作業が完了したら、HTMLとCSSのコード全体を確認しましょう。

完成版のHTML

index.htmlには、次のコードを記述します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>背景動画の上にタイトルを表示する</title>
  <link rel="stylesheet" href="css/style.css">
</head>
<body>

  <div class="hero">
    <video autoplay muted loop playsinline>
      <source src="video/hero.mp4" type="video/mp4">
      お使いのブラウザーは動画の再生に対応していません。
    </video>

    <div class="hero__content">
      <p class="hero__label">STACK CREATIVE CONTENTS COMPANY</p>
      <h1 class="hero__title">
        伝える技術を、<br>
        もっと分かりやすく。
      </h1>
      <p class="hero__text">
        書籍・動画・Web・教育コンテンツを通じて、<br>
        知識を「伝わる形」に変えます。
      </p>
      <a class="hero__button" href="#contents">活動を見る</a>
    </div>
  </div>

  <section id="contents" class="contents">
    <h2>活動とコンテンツ</h2>
    <p>この位置に、Heroエリアに続くコンテンツを配置します。</p>
  </section>

</body>
</html>

完成版のCSS

css/style.cssには、次のコードを記述します。

body {
  margin: 0;
}

.hero {
  position: relative;
  height: 100vh;
  overflow: hidden;
}

.hero video {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__content {
  position: absolute;
  top: 50%;
  left: 8%;
  z-index: 2;
  color: #fff;
  transform: translateY(-50%);
}

.hero__label {
  margin: 0 0 16px;
  font-size: 14px;
  letter-spacing: 0.2em;
}

.hero__title {
  margin: 0 0 24px;
  font-size: clamp(40px, 6vw, 80px);
  font-weight: 300;
  line-height: 1.15;
}

.hero__text {
  margin: 0 0 32px;
  font-size: 18px;
  line-height: 1.8;
}

.hero__button {
  display: inline-block;
  padding: 14px 28px;
  border: 1px solid #fff;
  color: #fff;
  text-decoration: none;
}

.hero__button:hover {
  background-color: #fff;
  color: #111;
}

.contents {
  padding: 80px 8%;
}

ファイルを保存したら、index.htmlをブラウザーで開きます。

背景動画の上に白いタイトル、説明文、リンクボタンが表示されていれば完成です。「活動を見る」ボタンを押し、Heroエリアの下にある「活動とコンテンツ」へ移動することも確認してください。

HTMLとCSSの関係を整理しよう

今回のHeroエリアには、動画とタイトル部分という二つの子要素があります。

<div class="hero">
  <video>...</video>
  <div class="hero__content">...</div>
</div>

親要素.heroは、子要素を配置する範囲と基準を作ります。

.hero {
  position: relative;
  height: 100vh;
  overflow: hidden;
}

子要素の動画は、Heroエリア全体を覆う背景として配置します。

.hero video {
  position: absolute;
  inset: 0;
  z-index: 1;
}

もう一つの子要素.hero__contentは、Heroエリアを基準にして、動画より手前へ配置します。

.hero__content {
  position: absolute;
  top: 50%;
  left: 8%;
  z-index: 2;
  transform: translateY(-50%);
}

今回の重なりは、次の3層で考えると整理しやすくなります。

要素 役割
基準となる外枠 .hero Heroエリアの大きさと配置基準を作る
背面 .hero video Heroエリア全体に動画を表示する
前面 .hero__content タイトル、説明文、ボタンを表示する

HTMLの親子関係は、CSSで位置を決めるときにも重要です。どの要素を基準にするのか、どの要素を移動するのかを分けて考えましょう。

表示が崩れた場合の確認項目

タイトルが動画の下に表示される

.hero__contentに、position: absoluteが指定されているか確認してください。

.hero__content {
  position: absolute;
}

また、クラス名がHTMLとCSSで一致しているかも確認します。hero_contenthero__contentは別のクラス名です。

タイトルがHeroエリアではなく、ページ全体を基準に配置される

親要素.heroposition: relativeが抜けていないか確認します。

.hero {
  position: relative;
}

この指定がないと、.hero__content.hero以外の祖先要素や、ページ全体を基準にして配置される場合があります。

タイトルが中央より下に表示される

top: 50%だけでは、.hero__contentの上端がHeroエリアの高さ50%の位置に置かれます。

次の指定も追加されているか確認してください。

transform: translateY(-50%);

これにより、.hero__content自身の高さの半分だけ上へ移動し、縦方向の中央が合います。

タイトルが動画の後ろに隠れる

動画とタイトル部分のz-indexを確認してください。

.hero video {
  z-index: 1;
}

.hero__content {
  z-index: 2;
}

タイトル部分の数値を動画より大きくすると、タイトルが手前に表示されます。

文字が動画と同化して読みにくい

明るい動画の上に白い文字を表示すると、背景と文字のコントラストが不足し、読みにくくなる場合があります。

使用する動画を選ぶときは、タイトルを配置する左側に細かい模様や明るい被写体が集中していないか確認してください。

実際のWebサイトでは、動画と文字の間に半透明の暗いレイヤーを加える方法もあります。ただし、今回はpositionz-indexの基本を理解することを優先し、詳しい調整は別の回で扱います。

リンクボタンを押しても移動しない

リンクのhref属性と、移動先のid属性が一致しているか確認します。

<a href="#contents">活動を見る</a>

<section id="contents">

#href側だけに付けます。移動先のidには付けません。

今回のまとめ

今回は、背景動画の上にタイトル、説明文、リンクボタンを重ねて表示しました。

  • タイトル部分をdivタグでひとまとめにする
  • 親要素.heroposition: relativeを配置基準にする
  • 動画とタイトル部分をposition: absoluteで重ねる
  • top: 50%left: 8%でタイトルの位置を指定する
  • translateY(-50%)でタイトル部分の縦中央を合わせる
  • z-indexで動画を背面、タイトルを前面に配置する
  • 文字サイズ、行間、余白をCSSで整える
  • aタグをリンクボタンとして表示する

position: relativeを指定しただけでは、親要素の見た目は基本的に変わりません。しかし、子要素へposition: absoluteを指定したとき、親要素が配置の基準として機能します。

この親子関係を理解すると、動画の上に文字を重ねるだけでなく、画像の上にラベルを置く、カードの隅にアイコンを置く、といったレイアウトにも応用できます。

次回は、今回作成したHeroエリアをスマートフォンでも見やすくします。画面幅に合わせてタイトルの大きさや改行、左右の余白、動画の表示位置を調整します。