CSSから考えるデザインのディテール第3回:CSSだけでつくる、拡大縮小する画像メニュー(FlexBoxの応用)

CSSから考えるデザインのディテール

FlexBoxを使って、マウスオーバーに応じて拡大縮小する画像メニューの作り方を解説します。

マウスオーバーで「すーっ」と画像が拡大して、他の画像が縮小する

今回担当するのは、秋葉秀樹です。

Androidの新デザインガイドライン「Material Design」の中に、「アニメーションでユーザに気づきを与える」というコンセプトがあります。これは、Android端末に限らず、機械と人間との間でコミュニケーションを取る手段の一つと考えてもよいでしょう。

Webデザインにおいても、このコンセプトは何かしらのヒントになるかもしれません。今回は、このコンセプトを取り入れたサンプルを紹介します。第2回ではFlexBoxを使った「柔軟な横並びメニュー」を紹介しましたが、今回もFlexBoxを使って作成します。

まずはサンプルをご覧いただき、どのような効果が得られるかを確認してください。下側に並ぶ3枚の画像のどれかにマウスオーバーすると、その領域だけが「すーっ」と広がり、残り2枚の画像の領域が縮みます。

今回のサンプルを見る

具体的には、マウスオーバーした要素を1.6倍の大きさに拡大し、それ以外の要素は全体の横幅に収まるように縮小しています。

通常、このような演出はJavaScriptでちょっとした計算を行う必要がありますが、このサンプルはすべてCSSのFlexBoxで実現しています。

ただし、FlexBoxに対して、Safariなどではベンダープリフィックスが必要だったり、Internet Explorer 9は非対応だったりします。この記事に関しては、将来に向けて備えるという意味で読んでいただくと幸いです。よって、今回はベンダープリフィックスを省略して解説しますので、最新のChromeやFirefox、Internet Explorer 11などで確認してください。

もし、FlexBoxがわからないという方は、第2回の記事を読んでください。

※アニメーションの“やり過ぎ”には注意しましょう。過度にアニメーションさせると「酔う」という人もいるので、ユーザへの気づきを与える程度にするとよいでしょう。今回はサンプルのため、若干大げさにアニメーションさせています。なお、アニメーションを行う際の拡大率やスピードは、CSSの値で簡単に調整できます。

Flexboxで横並びにする

まずは前回の記事と同じように、親要素(ul要素)に「display: flex」と「justify-content: space-around」を指定し、子要素(li要素)にはflexプロパティ、さらにアニメーションのためにtransitionプロパティも指定しておきます。

ちなみにtransitionプロパティとは、数値を持つプロパティを「何秒かけてアニメーションさせるか指定できる」というものです。今回でいうと、「flex: 1」を「flex:1.6」に0.3秒かけてアニメーションさせたいので「transition: flex .3s」と記述します。この「flex」を省略すると、数値を持つすべてのプロパティにアニメーションが影響します。

今回は3枚の写真を均等に横並びにして、マウスオーバーした(:hover)要素をアニメーションで1.6倍に広げ、他の2枚はそれに応じて逆に縮小するという動きをつくります。3枚のうちのどれか1枚が:hover状態であれば、「flex: 1.6」を指定します。

基本コーディングはこれだけです。実にシンプルですね。

【HTML】

<div class=”wrapper”> <ul> <li></li> <li></li> <li></li> </ul> </div>

【CSS】

ul, li { margin: 0; padding: 0; list-style-type: none; } .wrapper { width: 960px; } ul { display: flex; justify-content: space-around; } li { flex: 1; height: 220px; transition: flex .3s; background-color: orange; border: 1px solid #fff; } li:hover { flex: 1.6; }

上記コードの結果が次の図です。要素にマウスオーバーすると、「すーっ」とアニメーションして膨らみます。

上図のサンプルを見る

写真は背景画像にする

では、写真を入れていきましょう。li要素にはa要素を内包して文字を入れておきます。a要素はクリックしてもらうために必要ですね。以下のようにa要素に背景画像を入れました。

【HTML】

<li class=”stroll”><a href=”stroll.html”>散歩ギャラリー</a></li> <li class=”sleepy”><a href=”sleepy.html”>眠りの場所</a></li> <li class=”bathroom”><a href=”bathroom.html”>猫とお風呂</a></li>

【CSS】

li a { width: 100%; height: 100%; display: block; background-repeat: no-repeat; background-position: center center; } li.stroll a {background-image: url(img/stroll.jpg);} li.sleepy a {background-image: url(img/sleepy.jpg);} li.bathroom a {background-image: url(img/bathroom.jpg);}

テキストもFlexBoxで縦横センター合わせ

FlexBoxは、HTML要素だけでなく、テキストもレイアウトできます。縦方向のセンター、横方向のセンターに合わせるプロパティが用意されているので覚えておくと便利でしょう。

これはテキストの直接の親要素、a要素に指定します、なお、ここでも「display:flex」を指定することを忘れないでください。

横方向の配置基準には、justify-contentプロパティを指定します。

縦方向の配置基準には、align-itemsプロパティを指定します。

それでは、a要素に「display: flex;」「justify-content: center; 」「align-items: center;」を指定し、ボックスの真ん中に配置します。

【CSS】

li a { width: 100%; height: 100%; background-repeat: no-repeat; background-position: center center; background-size: cover; display: flex; justify-content: center; // 水平方向の真ん中にテキストを配置する align-items: center; // 垂直方向の真ん中にテキストを配置する text-decoration: none; font-size: 1.2em; font-weight: bold; color: #fff; text-shadow: 0 0 5px #000; }

上記コードで「justify-content: flex-end;」「align-items: flex-end;」と変更すると、ボックスの右下に配置できます。

目線を集中させる工夫

例えば、「マウスオーバーしたら、他の要素を薄くする」というように、フォーカスしている要素だけを強調したいとき、あえて「他を強調しない」という見せ方もあります。

以下の場合もそういった方法の一つです。ul要素が:hover状態にあれば、li要素をすべて薄くして、さらに:hover状態のli要素だけ薄くしないという、:hover疑似クラスの掛け合わせで実現できます。

【CSS】

ul:hover li { opacity: 0.4; } ul:hover li:hover { opacity: 1; flex: 1.6; }

完成したコード

サンプルで使っている全コードはこれだけです。詳しくは実際の動作サンプルと合わせて確認してください。

【HTML, CSS】

<!DOCTYPE html> <html lang=”ja”> <head> <meta charset=”UTF-8″> <title>FlexBox Interactive</title> <style> ul, li { margin: 0; padding: 0; list-style-type: none; } #main_visual { width: 960px; height: 400px; background: url(img/main_visual.jpg) center center no-repeat; } .wrapper { width: 960px; margin: auto; } ul { display: flex; justify-content: space-around; background-color: #fff; } li { flex: 1; height: 220px; transition: flex .3s, opacity .3s; } li a { width: 100%; height: 100%; background-repeat: no-repeat; background-position: center center; background-size: cover; display: flex; justify-content: center; align-items: center; text-decoration: none; font-size: 1.2em; font-weight: bold; color: #fff; text-shadow: 0 0 5px #000; } li.stroll a {background-image: url(img/stroll.jpg);} li.sleepy a {background-image: url(img/sleepy.jpg);} li.bathroom a {background-image: url(img/bathroom.jpg);} ul:hover li { opacity: 0.4; } ul:hover li:hover { opacity: 1; flex: 1.6; } </style> </head> <body> <div class=”wrapper”> <div id=”main_visual”></div> <ul> <li class=”stroll”><a href=”stroll.html”>散歩ギャラリー</a></li> <li class=”sleepy”><a href=”sleepy.html”>眠りの場所</a></li> <li class=”bathroom”><a href=”bathroom.html”>猫とお風呂</a></li> </ul> </div> </body> </html>

(補足)なぜimg要素ではなく、a要素に背景画像を使ったのか?

なぜ今回のサンプルではimg要素ではなく背景画像にしたかというと、なるべく簡単に実装したかったからです。background-sizeプロパティを使えば、簡単に「:hover時に1.6倍に拡大されたa要素の幅に応じて背景画像も拡大させる」ことができます。

以下の2つの例は、どちらもimg要素を使わず、背景画像として表示しています。

background-sizeプロパティを使わないと、要素の幅が画像サイズより大きくなったらこのように隙間が出ることも…。

background-size:coverを指定すると、背景画像が要素の大きさにフィットするように拡大縮小します。

background-positionプロパティで、拡大縮小する「変形の中心」を指定できます。今回は「background-position: center center」としました。領域の中心から自動的に拡大縮小してくれるという点もimg要素ではなく背景画像を使った理由です。

いかがでしたでしょうか?
前述した通り、あまりやり過ぎはよくありませんが、ちょっとしたユーザへの気づきを与えるという意味でもインターフェイスのフィードバックをデザインする参考にしてください。