chlonolog

web, digital gadgets, and more.

Hexoで画像をアイキャッチっぽく表示する

エントリにアイキャッチ画像をつけたいと思ったのですが、毎回専用の画像を作るのは手間がかかります。
ちゃんとやった方がいいのは分かっているのです。でも、できる限り無精したいじゃないですかー!(魂の叫び)

なので、

  • きちんとアイキャッチ画像を指定している場合は、その画像を表示
  • アイキャッチ画像を指定しておらず、エントリ内で画像が使用されている場合は、その画像を元にリサイズしたアイキャッチ画像を表示
  • どちらもない場合は表示しない

という処理でお茶を濁すことにしました。
具体的なイメージは、当サイトの「よもやま」カテゴリをご覧いただければなんとなくお分かりいただけるんじゃないかと思います。

注意事項

当然ながらOGPに文字は反映されませんので、集客目的などでアイキャッチ画像をつけたい場合はきちんと作る必要があります。こちらはあくまで「なんちゃってアイキャッチ」です。
「それってどうなんだ」と思われるかもしれませんが、ちゃんとした画像を作る前にとりあえず公開、みたいな用途では案外アリなんじゃないかという気がします。

うちの場合、雑記的なエントリはこれでいいかなーなんて考えています。差し替える気になったら画像を作る方向で……。


ディレクトリ構造

ブログ内の画像は、gulpを使ってサムネイル画像とアイキャッチ画像を生成してあります。
実際に行っている処理については、「現在のgulpfile.jsを公開します」で詳しく説明しています。

格納している場所はこんな感じ。

source ┬ _images/        ← gulpで処理する画像を置く場所
    └ images/ ┬ thumbnail/ ← サムネイル画像
         └ eyecatch/  ← アイキャッチ画像

サムネイル画像とアイキャッチ画像のディレクトリを、同じ階層に置いているのがポイントです。
なお、大元の画像・サムネイル画像・アイキャッチ画像のファイル名はすべて同じにしてあります。

source/_posts/XXXXXX.mdの記述

画像は2種類の方法で取得しています。

本文中に貼られている画像(をリサイズしたアイキャッチ画像)を使用する

まず、画像を貼ります。
梅雨の頃に近所で撮った、あじさいの写真です。いい色合い。

梅雨の頃に撮ったあじさい

出力されるHTMLはこちら。

<a data-lity="data-lity" href="/images/2018-07-26_1.jpg"><img src="/images/thumbnail/2018-07-26_1.jpg" class="img-responsive lazyload"></a>

<img>には、サムネイル画像のパスを指定しています。
当サイトはエントリ内でサムネイル画像を表示し、Lityを使うことで大元の画像を参照できるようにしています。大元の画像をそのまま貼ることはありません。
この設定が後々効いてきますので、覚えておいてください。

貼られている画像の中からランダムで画像を表示するようにしますので、画像は何枚貼っても構いません。
エントリ内に複数の画像を貼っていて、「どうしてもこの画像を使いたい/この画像だけはアイキャッチに使いたくない」という希望がある場合は、後述の方法を使うのが無難です。

Front-matterに設定した画像を使用する

---
title: エントリのタイトル
description: エントリの概要
image: XXXXXX.png
---

image:の指定がある場合は、そこに指定されている画像を優先的に表示するよう実装しています。
指定していない場合でエントリ内に画像を貼っている場合は、その画像を元にしたアイキャッチ画像を表示します。
かっこいいアイキャッチ画像を特別に作った場合も安心ですね!(あるかどうかは別として)

どちらも存在しない場合は、アイキャッチ画像自体を表示しません。

テンプレート内の処理

画像出力の部分だけ切り出しています。

  <%
  var urls = lazyImage(post);
  var random = Math.floor(Math.random() * (urls.length));
  var _photoUrl = '';
  if (post.image) {
    //post.imageに画像が指定されているならそれを使う
    _photoUrl = post.image;
  }
  else if (urls.length > 0 && urls[random]) {
    //post.imageに指定がなく、エントリ内に画像が貼られている場合はそちらを使う
    //アイキャッチ画像は /thumbnail/ と同じ階層の /eyecatch/ に格納すること
    _photoUrl = urls[random].replace('/thumbnail/', '/eyecatch/');
  }
  if(_photoUrl) { %>
    <figure class="post-media">
      <% if (index) { //インデックスページ %>
        <a href="<%- url_for(post.path) %>">
          <img src="<%- _photoUrl %>"  alt="<%- post.title %>" class="img-responsive"> 
        </a>
        <figcaption><%- post.description %></figcaption>
      <% } else { //インデックスページ以外 %>
        <img src="<%- _photoUrl %>"  alt="<%- post.title %>" class="img-responsive"> 
        <figcaption><%- post.description %></figcaption>
      <% } %>
    </figure>
  <% } %>

中で呼んでいるlazyImage()は、hexo-theme-snippet というテーマのスクリプトを拝借したものです。
実行すると、エントリ内で<img>を使って表示している画像のパスを配列で返してくれます。
その後、配列の中からランダムでアイキャッチに使う画像(の、大元の画像のサムネイル)のパスを取得しています。

エントリ内でサムネイル画像のみを貼っていることから、lagyImage()で取得できるファイル名はすべて「/images/thumbnail/XXXXXX.png」というサムネイル画像のものになります。
このパスに対し「thumbnail」を「eyecatch」に置換することで、アイキャッチ画像のファイル名を指定しています。

post.imageに画像名が指定されていた場合は、そちらを表示します。
また、アイキャッチ画像の上にはpost.descriptionのテキストを被せています。

<% if (page.image) { %>
  <%- open_graph({image: config.root + 'images/' + page.image}) %>
<% } %>

<head>内に記述します。
post.imageに画像が指定されている場合は、OGPタグを出力しています。

スタイルシート

ウィンドウリサイズ時によきにはからってもらうため、figcaptionに対してvwでもろもろの指定をしています。

/**
 * アイキャッチ画像
 * 
 * 幅: 822px
 * 高さ: 200px
 * post.image に指定した画像か エントリ内の画像(ランダム)を使用
 * images/eyecatch/ 内のファイル名は、サムネイル画像と同じにすること
 */
figure.post-media {
  display: block;
  width: 100%;
  margin: 0;
  position: relative;
  text-align: center;

  & img {
    //少し暗めにしてぼかす
    -webkit-filter: brightness(0.7) blur(5px);
    -moz-filter: brightness(0.7) blur(5px);
    -ms-filter: brightness(0.7) blur(5px);
    -o-filter: brightness(0.7) blur(5px);
    filter: brightness(0.7) blur(5px);
  }
  
  figcaption {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    height: 50%;
    margin: auto;
    padding: 3vw 10vw;
    color: #FFF;
    text-align: center;
    vertical-align: middle;
    opacity: 0.5;
    //両端をぼかす
    background: -webkit-linear-gradient(left, transparent, #555 25%, #555 75%, transparent);
    background: linear-gradient(to right, transparent, #555 25%, #555 75%, transparent);

// ボックスの中央揃え
    display: -webkit-flex;
    display: flex;
// 縦方向
    -webkit-align-items: center;
    align-items: center;
// 横方向
    -webkit-justify-content: center;
    justify-content: center;

    @media only screen and (max-width: 480px) {
      //スマホのときは表示と行間を広めに調整
      font-size: 2.5vw;
      line-height: 3.2vw;
    }
    @media only screen and (min-width: 901px) {
      //コンテナのサイズより表示画面が大きい場合は、
      //画面サイズに合わせたフォントのリサイズを行わない
      font-size: 1rem;
      line-height: 1.7rem;
    }
  }
}

エントリ内の画像を使用するとどうしてもアイキャッチとして不向きな画像も出てきますので、画像は明度を落とした上でぼかしてあります。
その上に<figcaption>のテキストを載せることで、それらしく体裁を整えています。

補足

上記の設定では、post.imageの画像を表示する際にも概要を被せています。
「特別にアイキャッチ画像を作る場合は手動で文字を入れるから、概要は邪魔」という場合は、テンプレートから<figcaption>の部分を削ってしまうのが手っ取り早いと思います。
その場合は、スタイルシートのぼかし設定が外れるように条件分岐を入れる必要がありますね。

コメント

© 2018 chlono