CSSのtarget擬似クラスでウィンドウの開閉アニメーションを実装する



Webページ内でウィンドウの開閉アニメーションを実装していきたい時には、JavaScriptやJavaScriptのライブラリであるjQueryなど、プログラミングを駆使して実装していくことになりますが、aタグ(アンカー要素)と併用してCSSの「:target擬似クラス」を利用すると、クリック処理で要素の表示をコントロールすることができます。

:target擬似クラスは、一致するidを持つ固有の要素が対象要素となります。
その対象要素に対して、CSSで表示または非表示のスタイルを適応させれば、ウィンドウの開閉アニメーションのように表示をコントロールすることができます。

:target擬似クラスを利用するとJavaScriptを使わず、CSSのみでLightbox(ライトボックス)を作成することもできます。

以下、Webブラウザのサポート状況になります。
:target擬似クラスはCSS3から追加された擬似クラスで、現在はほぼすべてのWebブラウザに利用できます。

Can I use(:target)
https://caniuse.com/?search=%3Atarget

意外と便利な擬似クラス。使い方や動作をサンプルで確認してみましょう。

:target擬似クラスの利用


ここではサンプルとして、イメージギャラリーのように複数の画像を並べて、クリックした画像をLightboxで拡大表示してみます。

まずはHTMLから。
読み込む画像はimg要素のほか、picture要素で画面幅によって画像を切り分けたり、WebPやJPEG XLなど画像フォーマットを最適化させることもあると思うので、4つ目のli要素からpicture要素の構造としています。

HTML

<ul class="flex-layout">

  <li>
    <a href="#img-box01"><img src="images/image01.jpg" alt="Image01"></a>
    <div id="img-box01" class="lightbox">
      <figure>
        <a href="#close" class="close"></a>
        <img src="images/image01.jpg" alt="Image01">
        <figcaption>image01 caption</figcaption>
      </figure>
    </div>
  </li>

  <li>
    <a href="#img-box02"><img src="images/image02.jpg" alt="Image02"></a>
    <div id="img-box02" class="lightbox">
      <figure>
        <a href="#close" class="close"></a>
        <img src="images/image02.jpg" alt="Image02">
        <figcaption>image02 caption</figcaption>
      </figure>
    </div>
  </li>

  <li>
    <a href="#img-box03"><img src="images/image03.jpg" alt="Image03"></a>
    <div id="img-box03" class="lightbox">
      <figure>
        <a href="#close" class="close"></a>
        <img src="images/image03.jpg" alt="Image03">
        <figcaption>image03 caption</figcaption>
      </figure>
    </div>
  </li>

  <li>
    <a href="#img-box04">
      <picture>
        <source srcset="images/image01.webp" type="image/webp">
        <img src="images/image01.jpg" alt="Image01">
      </picture>
    </a>
    <div id="img-box04" class="lightbox">
      <figure>
        <a href="#close" class="close"></a>
        <picture>
          <source srcset="images/image01.webp" type="image/webp">
          <img src="images/image01.jpg" alt="Image01">
        </picture>
        <figcaption>image01 caption</figcaption>
      </figure>
    </div>
  </li>

  <li>
    <a href="#img-box05">
      <picture>
        <source srcset="images/image02.webp" type="image/webp">
        <img src="images/image02.jpg" alt="Image02">
      </picture>
    </a>
    <div id="img-box05" class="lightbox">
      <figure>
        <a href="#close" class="close"></a>
        <picture>
          <source srcset="images/image02.webp" type="image/webp">
          <img src="images/image02.jpg" alt="Image02">
        </picture>
        <figcaption>image02 caption</figcaption>
      </figure>
    </div>
  </li>

  <li>
    <a href="#img-box06">
      <picture>
        <source srcset="images/image03.webp" type="image/webp">
        <img src="images/image03.jpg" alt="Image03">
      </picture>
    </a>
    <div id="img-box06" class="lightbox">
      <figure>
        <a href="#close" class="close"></a>
        <picture>
          <source srcset="images/image03.webp" type="image/webp">
          <img src="images/image03.jpg" alt="Image03">
        </picture>
        <figcaption>image03 caption</figcaption>
      </figure>
    </div>
  </li>

</ul>



サムネイルとして用意している画像のa要素のhref属性には、ページ内リンクでよく利用する#(ハッシュ)を使い、対象の画像のターゲットとなる、CSSクラス「lightbox」の要素をリンク先とします。

lightboxのブロックコンテンツの内容は、figure要素を使って画像とキャプション(figcaption要素)とします。
閉じるボタンを用意するため、CSSクラス「close」のa要素を各要素の前に追加します。(重ね順を調整しやすくするため前に追加)
closeのバツボタンのリンクは「#close」としていますが、#の後の名前はなんでもかまいません。#のみにしてしまうと、lightboxを閉じた時にページ上部に移動してしまいます。

続いてはCSS。

レスポンシブWebデザインにも対応できるよう、メディアクエリ(モバイルファースト)でもデザインを調整していきます。
CSSクラス「flex-layout」のセレクタまでは、通常の表示のレイアウトになります。

CSS

* {
  margin: 0;
  padding: 0;
}

.flex-layout {
  margin: 3rem auto;
  display: flex;
  flex-flow: column;
  gap: 2rem 0;
}

.flex-layout li {
  list-style: none;
}

.flex-layout img {
  width: auto;
  max-width: 90%;
  max-height: 400px;
  margin: auto;
}

.lightbox {
  visibility: hidden;
  opacity: 0;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  transition: all .5s;
}

.lightbox picture {
  position: relative;
}

.lightbox:target {
  visibility: visible;
  opacity: 1;
}

.lightbox figure {
  position: relative;
  width: 80%;
  max-width: 900px;
}

.lightbox figcaption {
  position: relative;
  padding: 0.6rem 2.4rem 0.6rem 0.6rem;
  color: #fff;
}

.lightbox figure img {
  position: relative;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: 380px;
  margin: auto;
}

.lightbox .close {
  display: block;
  position: absolute;
  right: 0;
  bottom: 0.4rem;
  text-decoration: none;
}

.lightbox .close::after {
  content: "\00d7";
  position: relative;
  width: 2rem;
  height: 2rem;
  font-size: 1.5rem;
  padding: 0 0 0.15rem;
  color: #fff;
  cursor: pointer;
  background-color: rgba(0,0,0,.5);
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1;
}

.lightbox .close::before {
  content: "";
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  position: fixed;
  background-color: rgba(0,0,0,.8);
  cursor: default;
}


/*------------------------------------------------------
 Tablet ~
------------------------------------------------------*/
@media screen and (min-width:768px) {

  /* contents
  ================================================ */
  .flex-layout {
    background-color: #fff3eb;
    max-width: 1000px;
    padding: 2%;
    display: flex;
    flex-flow:row wrap;
    justify-content: center;
    gap: 0;
  }

  .flex-layout li {
    width: calc(100% / 3);
    padding: 2%;
  }

  .flex-layout img {
    width: 100%;
    max-width: none;
    height: 250px;
    object-fit: cover;
  }

  .lightbox figure {
    width: auto;
  }

  .lightbox img {
    max-width: 900px;
  }

}



CSSクラス「lightbox」は、「visibility: hidden;」「opacity: 0;」で最初は非表示にしておきます。
サムネイル用の画像をクリックした時、一致するidを持つ固有の要素が:target擬似クラスの対象要素となり、「visibility: visible;」「opacity: 1;」で表示するようにします。
表示をふわりと切り替えるアニメーションは、「transition: all .5s;」で実装しています。
他、CSSクラス「lightbox」に関係するスタイルは、lightboxのレイアウトのデザインとなります。

lightboxの画像では、幅や高さを最大幅、最大高さも一緒に指定していくと、lightboxで拡大表示する画像を、画面内でうまく調整していくことができます。

CSSのみで実装するLightbox



サムネイル用の画像にて、縦横比(アスペクト比)が違う画像を並べて扱う場合には、CSSのobject-fitプロパティを使うと、綺麗に揃えることができます。
object-fitプロパティについては、以下の記事でご紹介しています。
気になる方は、後で参考にしてもらえればと。

CSSセレクタ「.lightbox .close::before」では、コンテンツ全体に透過させたグレーのオーバーレイを実装してしています。
a要素の擬似要素として、バツボタンと一緒にlightbox周りのオーバーレイでも、クリックしてlightboxを閉じることができますが、もし閉じるのはバツボタンのみにする場合は、before擬似要素のa要素の効果を無効にするため、「pointer-events: none;」を追加してください。

CSS(.lightbox .close::before)

.lightbox .close::before {
  content: "";
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  position: fixed;
  background-color: rgba(0,0,0,.8);
  cursor: default;
  pointer-events: none; //aタグの無効化
}



以下、ここまでの流れの実装動画です。
動画(4分30分)



もちろん、Lightboxを閉じるためにつけたバツボタンも、positionプロパティで配置を調整してもらってもかまいません。
キャプションのデザインも、自分好みのデザインに調整してみてください。

まとめ


Lightboxを実装することができるJavaScriptライブラリは、jQueryなどでもたくさんありますが、ライブラリをたくさん読み込むのが嫌な方や、自分で構築していきたいという方は、CSSのみでLightboxを実装してみてもいいですね。

今回はイメージギャラリーをサンプルで見てきましたが、テキストリンクやボタンデザインのリンクからコンテンツの説明を表示させるなど、ページ内でのいろんなアニメーションでCSSのtarget擬似クラスは使っていけそうです。

ぜひ使ってみてください。