miyaoka.dev

画像クリックでフルスクリーン表示するようにした

このブログでは画像を imgur に配置していて記事中ではサムネイルを表示するようにしている。

<figure>
  <a href="https://i.imgur.com/WZajJkg.jpg" target="_blank" rel="noopener"
    ><picture>
      <source
        type="image/webp"
        sizes="(max-width: 320px) 320px, (max-width: 640px) 640px, 640px"
        srcset="
          https://i.imgur.com/WZajJkgh.webp 1024w,
          https://i.imgur.com/WZajJkgl.webp  640w,
          https://i.imgur.com/WZajJkgm.webp  320w
        "
      />
      <img
        src="https://i.imgur.com/WZajJkgl.jpg"
        alt="image"
        loading="lazy"
        style=""
        onload="this.style={minHeight:'auto'}"
      /> </picture
  ></a>
</figure>

サムネイルは srcset で 幅 1024 までの webp 画像を出し分け、フォールバック用には幅 640 の画像を指定していて、a タグでクリックすると imgur に投稿したオリジナルサイズの 画像 URL を開くようにしている。

オリジナル画像表示できない問題

しかし imgur への画像直リンはうまくいかない。

画像本体が見たいのに post ページにリダイレクトされてしまう
画像本体が見たいのに post ページにリダイレクトされてしまう

これが imgur の仕様だし、無料で使ってるから文句も言えないわけだが、でもやっぱりフルサイズ画像を簡単に見たいのでちょっと手を加えることにした。

ツイッターで画像クリックしたときみたいなやつ
ツイッターで画像クリックしたときみたいなやつ

で、lightbox というかツイッターの画像表示みたいなのを実装した。特にローディング表示も閉じるボタンも無く、クリックすると開き、またクリックすると閉じるだけのシンプルなもの。

やってることはオリジナル画像を css で fixed にして画面いっぱいに表示してるだけだがどうしても JS は必要になる。ただ、あまり記事自体に JS 制御を盛り込みたくないのでこれも以前と同様に Web Component 化して勝手に処理するようにした。

クリックするとフル表示する Web Component

このサイトでの Web Components については以下の記事で書いている。現状は埋め込みツイートのロードと記事一覧でのサムネイル画像表示の 2 つで使っている。

tsx

import { Component, Host, h, Prop, State } from '@stencil/core'

@Component({
  tag: 'miyaoka-lightbox',
  styleUrl: 'miyaoka-lightbox.css',
  shadow: true,
})
export class MiyaokaLightbox {
  @Prop() src: string
  @State() visible: boolean = false

  render() {
    return (
      <Host>
        <div onClick={() => (this.visible = true)} class="container">
          {this.visible && (
            <div
              onClick={(e) => {
                e.stopPropagation()
                this.visible = false
              }}
              class="backdrop"
            >
              <img src={this.src} />
            </div>
          )}
          <slot></slot>
        </div>
      </Host>
    )
  }
}

css

.container {
  cursor: pointer;
  display: inline;
}
.backdrop {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  z-index: 100;
  background-color: rgba(64, 62, 62, 0.9);
}
.backdrop img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

こんな感じのコンポーネントにして、オリジナル画像への a タグだったところをこのコンポーネントに置き換えるようにした。

作ってみてから思ったが、bool の state 一つなので、頑張れば checkbox や details の状態と css だけでもいけるのかもしれない