はてなブログで記事タイトルの前に画像を表示する方法

f:id:c-miya:20170310214200j:plain カード型デザインのはてなブログ用テーマZeno Teal(仮)は、もう少ししたら公開できそうです。とりあえずそのテーマのキモとなっているカード型デザインの「タイトルの上にアイキャッチ画像を表示する」方法について解説します。

これはもちろんcssで制御するのですが、これにはいくつかの方法があります。

display:tableを利用する

基本的には以下の記事で紹介されています。

www.cocococococococococococo.com

htmlの構造

はてなブログのトップページ、各エントリー部分の構造は以下のようになっています。(かなり簡略化しています。)

<article class="entry">
<div class="entry-inner">
    <header class="entry-header">
        <div class="entry-date">
            投稿日
        </div>
        <h1 class="entry-title">
            記事タイトル
        </h1>
        <div class="entry-categories">
            カテゴリー
        </div>
    </header>
    <div class="entry-content">
        記事本文
        <a class="entry-see-more">続きを読む</a>
    </div>
    <footer class="entry-footer">
        <p class="entry-footer-section">
            投稿者・投稿日
        </p>
        <div class="social-buttons">
            SNSボタン
        </div>
        <div class="comment-box">
            コメント
        </div>
    </footer>
</div>
</article>

簡略化した表示

図であらわすと以下のようになります。 f:id:c-miya:20170310203713p:plain

イメージつくでしょうか。これのheader(.entry-header)と.entry-contentの位置を入れ替えて、本文の最初に画像があれば、画像→タイトルという順番になります。

cssで順番を制御

順番を入れ替えるために、cssに以下のように入力します。

.entry-inner{display:table;}
.entry-content{display:table-header-group;}

これで入れ替わります。

f:id:c-miya:20170310203950p:plain

少し説明すると、.entry-header.entry-contentを含む.entry-innerdisplay:table;を指定することでテーブルのような表示になります。そして.entry-contentdisplay:table-header-group;を指定することで、.entry-contentはテーブルのヘッダーとして表示されます。ヘッダーなのでテーブルの最初に、一番上に表示されます。逆にdisplay:table-footer-group;を指定すればフッターとなり、.entry-inner内の最後に表示されるようになります。

これだけでもいいのですが、(カード型だと特に).entry-footer部分は必要ないので非表示にします。

.entry-footer{display:none;}

f:id:c-miya:20170310204500p:plain これでスッキリしました。画像のすぐ下に「続きを読む」を持ってきて本文は表示させないほうがいいでしょう。

position:absoluteを使う

別の方法を考えてみました。(というよりは、最初の方法は私は思いつかなかったので、自分で考え、このブログでも使っているのはこちらになります。)

まずデフォルト状態です。(.entry-footerは非表示にしています。) f:id:c-miya:20170310205131p:plain

.entry-contentを上に持ってくる

以下のcssを適用します。

.entry{position:relative;}
.entry-content{position:absolute;top:0;}

これで表示は以下のようになります。 f:id:c-miya:20170310210036p:plain

よくわからないかもしれませんが、.entry-contentが親要素.entry-innertop:0、つまり一番上に移動しました。.entry-headerとは重なって表示されます。

.entry–headerを下に持ってくる

タイトルを画像の下に表示するために、画像の縦の大きさ分だけ下にずらします。

.entry{position:relative;}
.entry-content{position:absolute;top:0;}
.entry-header{position:relative;top:180px;left:0;}

f:id:c-miya:20170310210744p:plain

画像の下にはなりましたが、本文とタイトルがかぶっています。

本文を間に移動する

本文はタイトルの下にしたいので、タイトルの高さを決めてしまい、その下に本文が来るように調整します。

.entry{position:relative;}
.entry-content{position:absolute;top:0;}
.entry-header{position:relative;top:180px;left:0;height:120px;overflow:hidden;}
.entry-content img:nth-of-type(1){margin-bottom:150px;}

f:id:c-miya:20170310211611p:plain

.entry-content img:nth-of-type(1)というのは、.entry-contentの中の最初のimg要素ということです。本文の先頭に画像があること前提ですが、その画像の下に.entry-header分のマージンを作っています。これで見た目上は画像→タイトル→本文になりました。

あとは一応.entryの高さも指定しておけばOKです。

.entry{position:relative;height:420px;}
.entry-content{position:absolute;top:0;}
.entry-header{position:relative;top:180px;left:0;height:120px;overflow:hidden;}
.entry-content img:nth-of-type(1){margin-bottom:150px;}

f:id:c-miya:20170310212347p:plain

細かい数値はそれぞれのブログで変えなくてはなりませんが、だいたいの考え方はこのとおりです。カード型のように見せるには.entryのスタイルをもっと調整する必要がありますね。

まとめ

うん、わかりにくいですね。とりあえず、最初の方法は.entry-contentをヘッダー扱いにして最初に持ってくる(順番を変える)ということで、2つ目の方法は順番ではなく表示位置を指定するという方法です。

単に画像を上に持ってくるだけなら最初の方法でいいのですが、画像と本文の間にタイトルを持ってくるようにするには2つ目の方法がいいと思います。

何かほかにも方法はあるかもしれません。cssはいろいろできますからね。1つの結果をいろいろな方法で実現させるのを考えるのも面白いです。

追記:display:flexを使う

もう1つあったのを書くの忘れていました。要素を横並びにするdisplay:flexいわゆるflexboxを使う方法です。

.entry-inner{
    display: -webkit-flex; /* Safari */
    -webkit-flex-direction: column; /* Safari */
    display: flex;
    flex-direction: column;
}
.entry-content{
    -webkit-order: 1; /* Safari */
    order: 1;
}
.entry-header{
    -webkit-order: 2; /* Safari */
    order: 2;
}
.entry-footer{
    -webkit-order: 3; /* Safari */
    order: 3;
}

flexboxはflex-direction: columnを指定すると縦並びになります。そしてorderはflexboxの子要素の順番をコントロールします。デフォルトが0なので、.entry-contentorder: -1を指定すれば他の要素の前に表示されます。.entry-header, .entry-content, .entry-footerそれぞれに指定すれば順番は思うままです。

f:id:c-miya:20170310224047p:plain

個人的にはこれが一番スッキリしていて理解しやすいかな、と思います。まぁ画像と本文の間にタイトルを挟むには2つ目の方法のようなことをやらなければならないですが。