スマホサイトでよく見られるリンクリスト。
シンプルなものから複雑なものまであるが、まずはシンプルなものを作り、少しずつステップアップしてみよう。

シンプルなリンクリスト

まずはシンプルなリンクリストを作ってみよう。
最終形はこんな感じだ。
link-list_ss01
最初に用意するHTMLとCSSはこのようになる。
<ul>
    <li>
        <a href="">Docomo</a>
    </li>
    <li>
        <a href="">KDDI</a>
    </li>
    <li>
        <a href="">Softbank</a>
    </li>
</ul>
ul, li {
    list-style: none;
    padding: 0;
}

a {
    color: #000;
    text-decoration: none;
}

この状態で表示したものがこれだ。
link-list_ss02
これにリンクの幅や上下の線を設定しよう。
わかりやすくするためにリスト3のように、各li要素とa要素にclassを設定する。
    <li class="link-wrap">
        <a href="" class="link">Docomo</a>
    </li>
追加したclassの設定はこうだ。
.link-wrap {
    border: solid #000;
    border-width: 1px 0 0 0;
    font-size: 14px;
}

.link {
    display: block;
    height: 44px;
    padding-left: 10px;
}
この段階での表示はこのようになる。
link-list_ss03
だいぶ体裁が整ってきた。
しかし、各テキストが上に寄ってしまっている。
これを中央に寄せてみよう。

CSSで縦の中央寄せを行うのは難儀なことが多い。
しかし、一行のテキストだけに限られているならば話は簡単だ。
リスト5のようにline-heightをheightと同じ値にしてやればいい。
.link {
    display: block;
    height: 44px;
    line-height: 44px;
    padding-left: 10px;
}
これでテキストを縦に中央寄せ出来た。
さらに、最後のリンクに下線を付けるための設定も追加する。
.link-wrap:last-child {
    border-bottom-width: 1px;
}
この段階での表示はこのようになる。
link-list_ss04
完成まであと一歩だ。
最後にリンクの右側に矢印マークを表示してみよう。
今回はこのような画像を用意した。
arrow
このくらいのデザインならCSSのみで表現することも可能だ。
しかしその場合、端末(特に古いAndroid搭載のもの)によってはジャギが目立ってしまうこともあるし、顧客がデザインにこだわりたい場合もあるだろう。
そのようなケースを考慮して今回は画像を用いて実現してみる。

矢印マークの画像はa要素の背景として設定するのが良さそうだ。
配置場所が簡単に設定できるからである。
.linkに背景画像の指定を追加しよう。
.link {
    background: url(arrow.png) 98% 50% no-repeat;
    background-size: 20px 20px;
    display: block;
    height: 44px;
    line-height: 44px;
    padding-left: 10px;
}
これで完成だ。
当初の予定通りの仕上がりになった。
link-list_ss01
今回は、短くて必ず一行で収まる長さのテキストが前提にあった。
しかし、複数行に渡るような長いテキストを表示したい場合、このやり方ではうまくいかない。
次はその対応をしてみよう。

複数行のテキストを表示する

まずは複数行テキストをになるリンクを追加してみよう。
<ul>
    <li class="link-wrap">
        <a href="" class="link"><div>Docomo</div></a>
    </li>
    <li class="link-wrap">
        <a href="" class="link"><div>KDDI</div></a>
    </li>
    <li class="link-wrap">
        <a href="" class="link"><div>Softbank</div></a>
    </li>
    <li class="link-wrap">
        <a href="" class="link"><div>テキストが複数行に渡って表示されるケースに対応するため、少し長めのテキストを設定してみる。</div></a>
    </li>
</ul>
a要素の中にdivを挟むように変更している。
このままだと無駄に思えるかもしれないが、これは後で活きてくるので今は我慢しよう。

これをそのまま表示するとこのようになる。
link-list_ss05
ご覧の通り、2行目がはみ出している。
テキストの行の高さとリンク要素の高さが同じだから当然のことだ。
line-heightの設定は邪魔なので、削除しよう。
また、矢印マークにテキストが被っているので、これにも対応する。
.linkをこのように修正しよう。
.link {
    background: url(arrow.png) 98% 50% no-repeat;
    background-size: 20px 20px;
    display: block;
    height: 44px;
    padding: 0 30px 0 10px;
}

この結果はこうだ。
link-list_ss06
当然テキストは上寄せに戻る。
さらに、.linkの高さは44px固定なので、最後の項目のテキストが若干はみ出てしまっている。

中央寄せを行う前にこれを修正しておこう。
heightをmin-heightに変更してやればはみ出すことは無くなるはずだ。
.link {
    background: url(arrow.png) 98% 50% no-repeat;
    background-size: 20px 20px;
    display: block;
    min-height: 44px;
    padding: 0 30px 0 10px;
}
結果を見るとはみ出しが直っていることがわかる。
link-list_ss07
しかしこれでは少々窮屈だ。
上下に余白を付けるために.linkを修正しよう。
.link {
    background: url(arrow.png) 98% 50% no-repeat;
    background-size: 20px 20px;
    display: block;
    min-height: 44px;
    padding: 5px 30px 5px 10px;
}
結果はこうだ。
link-list_ss08
余白が出来たことでスッキリした。
しかし、新たな問題が発生してしまった。
1~3つ目の項目が太くなっている。

これはmin-heightに44pxを指定しているためだ。
基本の高さは44pxとしたいので、上下の余白分である10pxを引いて34pxとしてみよう。
.link {
    background: url(arrow.png) 98% 50% no-repeat;
    background-size: 20px 20px;
    display: block;
    min-height: 34px;
    padding: 5px 30px 5px 10px;
}
結果はこうだ。
link-list_ss09
期待通り、一行の場合は高さが44pxとなり、複数行の場合は高さが増加して余白も効いている。

次はいよいよ縦の中央寄せだ。

フレキシブルボックスを使って中央寄せ

フレキシブルボックスとはCSS3で追加された機能で、これを使うとレイアウトの可能性が大きく広がるだろう。
ただし注意しなければならない点もある。
これまで仕様がちょくちょく変わってきたということだ。
その辺の詳細はこのページがわかりやすくてためになった。

flexboxの旧仕様、改定仕様、現行仕様の一覧 - NAVER Engineers' Blog

では早速中央寄せに取り掛かってみよう。
各a要素に.display-flexというclassを追加する。
<a href="" class="link display-flex"><div>Docomo</div></a>
次に.display-flexを定義する。
.display-flex {
    -webkit-box-align: center;
    -webkit-align-items: center;
    align-items : center;
    
    display: -webkit-box;
    display: -webkit-flex;
    display: flex;
}
6~8行はa要素をフレキシブルボックスとして使うための設定だ。
これにより、a要素の子要素を様々なレイアウトで使うことが出来るようになる。

2~4行はa要素の子要素を表示方向に対して垂直な表示位置を決める。
デフォルトでの表示方向は横であるのでこの記述により縦に中央寄せすることになる。

ちなみに、ここでは古い記述方法と新しい記述方法を併記してある。
こうしておかないと古い端末(特にAndroid搭載のもの)をカバーできないからだ。

新しい記述方法は無くても現状では問題ないかと思う。
しかし、ある日突然古い仕様に対応していない端末が発売されるかもしれない。
その時になって顧客から(時として怒りを交えた)問い合わせを受けるよりも、あらかじめ対応しておいたほうが私達は心穏やかにいることが出来る事だろう。

さて、結果はこうだ。
link-list_ss10
期待通りの結果を得ることが出来た。
次は表示する要素を増やしてみよう。

サブテキストを追加する

サブテキストとして日付を追加してみよう。
これは主テキストの下に配置し、少しフォントサイズを小さめにする。
日付の見栄えを変えるためにdateというclassを持たせておく。
    <li class="link-wrap">
        <a href="" class="link display-flex">
            <div>Docomo</div>
            <div class="date">YYYY/MM/DD</div>
        </a>
    </li>
.dateについての記述も追加する。
.date {
    color: #00f;
    font-size: 11px;
}
結果はこうだ。
link-list_ss11
日付が右側に出てしまっている。
これはフレキシブルボックスの表示方向が横になっているためだ。
これを縦方向にするために、.flex-direction-columnというclassを設定し、a要素に追加する。
    <li class="link-wrap">
        <a href="" class="link display-flex flex-direction-column">
            <div>Docomo</div>
            <div class="date">YYYY/MM/DD</div>
        </a>
    </li>
.flex-direction-column {
    -webkit-box-orient: vertical;
    box-orient: vertical;
    flex-direction: column;
}
.flex-direction-columnも新旧仕様の記述を併用しているので注意して欲しい。
これらは全て表示方向を縦に設定するためのものだ。

結果はこうだ。
link-list_ss12
主テキストとサブテキストを縦に並べることには成功したが、これらは左に寄って欲しい。
横方向の中央に寄っているのはリスト3-2の2~4行目で、表示方向に対して垂直に中央寄せするように設定したからだ。

これを回避するために、該当箇所を.display-flexから切り出して.align-items-centerというclassを作る。
.align-items-centerはここでは使わないので、HTML上には追加しないでおく。
.display-flex {
    display: -webkit-box;
    display: -webkit-flex;
    display: flex;
}

.align-items-center {
    -webkit-box-align: center;
    -webkit-align-items: center;
    align-items : center;
}
これで横方向の中央寄せが解除されたはずだ。
結果を見てみよう。
link-list_ss13
期待通り、左寄せになった。
しかし、よく見てみると若干上よりになっていることに気づく。
再び縦方向の中央寄せを行わなければならない。

ただし、今は表示方向が縦になっているので、.align-items-centerでは縦に中央寄せは出来ない。
それを行うために.justify-content-centerというclassを作り、a要素に追加する。
    <li class="link-wrap">
        <a href="" class="link display-flex flex-direction-column justify-content-center">
            <div>Docomo</div>
            <div class="date">YYYY/MM/DD</div>
        </a>
    </li>
.justify-content-center {
    -webkit-box-pack : center;
    -webkit-justify-content: center;
    justify-content: center
}
結果はこうだ。
link-list_ss14
縦に中央寄せすることが出来た。
これで目的は達成だ。

newマークを付ける

サイトを更新した場合に更新した項目にnewマークを付けたくなることがあるだろう。
今回は項目の左側にnewマークを付けることにする。

newマークはCSSで記述することも出来るが、矢印マークと同様に今回は画像を用意した。
new
そして目指す最終形はこうだ。
link-list_ss15
まず.newというclassを定義して、HTML上で必要なa要素に追加する。
今回は最初と最後の項目に追加してみよう。
リスト5-1では最初の項目だけ表示しているが、最後の項目も同じようにすること。
    <li class="link-wrap">
        <a href="" class="link display-flex flex-direction-column justify-content-center new">
            <div>Docomo</div>
            <div class="date">YYYY/MM/DD</div>
        </a>
    </li>
.new::before {
    background: url(new.png);
    background-size: 100% 100%;
    content: "";
    display: block;
    height: 16px;
    margin-right: 10px;
    width: 40px;
}
newマークはbefore擬似要素を使って追加する。

結果はこうだ。
link-list_ss16
newマークが縦に追加されてしまっている。
一つ前のセクションでフレキシブルボックスの表示方向を縦に設定したのでこれは想定通りだ。

だが、今回はnewマークだけを左側に表示したい。
どうすればよいか。
フレキシブルボックスを入れ子にして横のフレキシブルボックスと縦のフレキシブルボックスを作れば良い。
イメージはこのようになる。
link-list_ss17
まずは縦のフレキシブルボックスを実現するために主テキストとサブテキストをdivで囲み、縦に並べる様にclassを設定する。
    <li class="link-wrap">
        <a href="" class="link display-flex flex-direction-column justify-content-center new">
            <div class="display-flex flex-direction-column justify-content-center">
                <div>Docomo</div>
                <div class="date">YYYY/MM/DD</div>
            </div>
        </a>
    </li>
次にa要素の余計なclassを削除する。
具体的に言うと.flex-direction-columnと.justify-content-centerだ。
これで、外側のフレキシブルボックスは横方向になり、内側のフレキシブルボックスは縦になったはずだ。
    <li  class="link-wrap">
        <a  class="link display-flex new">
            <div  class="display-flex flex-direction-column justify-content-center">
                <div>Docomo</div>
                <div  class="date">YYYY/MM/DD</div>
            </div>
        </a>
    </li>
結果はこうだ。
link-list_ss18
予定通りの配置になった。
後は微調整だけだ。

まずはa要素に.align-items-centerを追加する。
これはリスト4-5で作っておいたclassだ。
これにより、newマークを縦に中央寄せする。
    <li class="link-wrap">
        <a href="" class="link display-flex align-items-center new">
            <div class="display-flex flex-direction-column justify-content-center">
                <div>Docomo</div>
                <div class="date">YYYY/MM/DD</div>
            </div>
        </a>
    </li>
結果はこうだ。
link-list_ss19
newマークが縦に中央寄せされた。
完成まであと一歩だ。

主テキストが右側にはみ出してしまっているのを修正しよう。
これは、フレキシブルボックスの伸縮機能を使えば簡単にできる。
そのために.flex-1というclassを追加しよう。
.flex-1 {
    -webkit-box-flex: 1;
    -webkit-flex: 1 1 auto;
    flex: 1 1 auto;
}
これはフレキシブルボックスに余白があったり、はみ出している部分があったりすると伸縮してくれるプロパティだ。
これを内側のフレキシブルボックス自体に適用する。
    <li class="link-wrap">
        <a href="" class="link display-flex align-items-center new">
            <div class="display-flex flex-direction-column justify-content-center flex-1">
                <div>Docomo</div>
                <div class="date">YYYY/MM/DD</div>
            </div>
        </a>
    </li>
結果はこうだ。
link-list_ss20
期待通りの結果が得られた。
これで完成だ!
…と言いたいが、一つ問題がある。

最新のフレキシブルボックスの仕様を取り込んでいると思われるWindows版Chromeで見るとこのようになっている。
link-list_ss21
最後の項目のnewマークがひしゃげてしまっている。
これはおそらくflexの値を正しく設定してやれば解決するだろう。
.new::beforeをこのように修正する。
.new::before {
    -webkit-box-flex: 0;
    -webkit-flex: none;
    flex: none;
    background: url(new.png);
    background-size: 100% 100%;
    content: "";
    display: block;
    height: 16px;
    margin-right: 10px;
    width: 40px;
}
flexの値を伸縮しないように設定した。
結果はこうだ。
link-list_ss22
全て期待通りの結果が得られた。
もちろん、スマホでも問題ない。

フレキシブルボックスの効果を確認するために随分長々とやってきた。
しかし、それに見合う結果は得られたはずだ。
今後もこの機能を大いに活かしていきたい。

最後に、最終形のソース全文を掲載しておく。
<ul>
    <li class="link-wrap">
        <a href="" class="link display-flex align-items-center new">
            <div class="display-flex flex-direction-column justify-content-center flex-1">
                <div>Docomo</div>
                <div class="date">YYYY/MM/DD</div>
            </div>
        </a>
    </li>
    <li class="link-wrap">
        <a href="" class="link display-flex align-items-center">
            <div>
                <div>KDDI</div>
                <div class="date">YYYY/MM/DD</div>
            </div>
        </a>
    </li>
    <li class="link-wrap">
        <a href="" class="link display-flex align-items-center">
            <div>
                <div>Softbank</div>
                <div class="date">YYYY/MM/DD</div>
            </div>
        </a>
    </li>
    <li class="link-wrap">
        <a href="" class="link display-flex align-items-center new">
            <div class="display-flex flex-direction-column justify-content-center flex-1">
                <div>テキストが複数行に渡って表示されるケースに対応するため、少し長めのテキストを設定してみる。</div>
                <div class="date">YYYY/MM/DD</div>
            </div>
        </a>
    </li>
</ul>
ul, li {
    list-style: none;
    padding: 0;
}

a {
    color: #000;
    text-decoration: none;
}

.link-wrap {
    border: solid #000;
    border-width: 1px 0 0 0;
    font-size: 14px;
}

.link-wrap:last-child {
    border-bottom-width: 1px;
}

.link {
    background: url(arrow.png) 98% 50% no-repeat;
    background-size: 20px 20px;
    display: block;
    min-height: 34px;
    padding: 5px 30px 5px 10px;
}

.date {
    color: #00f;
    font-size: 11px;
}

.display-flex {
    display: -webkit-box;
    display: -webkit-flex;
    display: flex;
}

.align-items-center {
    -webkit-box-align: center;
    -webkit-align-items: center;
    align-items : center;
}

.justify-content-center {
    -webkit-box-pack : center;
    -webkit-justify-content: center;
    justify-content: center
}

.flex-direction-column {
    -webkit-box-orient: vertical;
    box-orient: vertical;
    flex-direction: column;
}

.flex-1 {
    -webkit-box-flex: 1;
    -webkit-flex: 1 1 auto;
    flex: 1 1 auto;
}

.new::before {
    -webkit-box-flex: 0;
    -webkit-flex: none;
    flex: none;
    background: url(new.png);
    background-size: 100% 100%;
    content: "";
    display: block;
    height: 16px;
    margin-right: 10px;
    width: 40px;
}