CSS3アニメーションでつくるインターフェイス表現

第6回 画像をパネルに分けてアニメーションで切り替える

この記事を読むのに必要な時間:およそ 11.5 分

画像をパネルに分けてクロスフェードする

いよいよ画像を4つのパネルに分けて,伸縮しつつクロスフェードさせる。まず,HTMLにパネルの要素をつぎのように加える。4つのパネルは<div>要素にして,それぞれに4つの画像用の<span>要素を含めた。要素の中身は空なので,CSSで画像や位置を定める。

<div class="bg-img">
    <div><!--Slice 1 -->
        <span><!-- Image 1 --></span>
        <span><!-- Image 2 --></span>
        <span><!-- Image 3 --></span>
        <span><!-- Image 4 --></span>
    </div>
    <div><!-- Slice 2 -->
        <span><!-- Image 1 --></span>
        <span><!-- Image 2 --></span>
        <span><!-- Image 3 --></span>
        <span><!-- Image 4 --></span>
    </div>
    <div><!-- Slice 3 -->
        <span><!-- Image 1 --></span>
        <span><!-- Image 2 --></span>
        <span><!-- Image 3 --></span>
        <span><!-- Image 4 --></span>
    </div>
    <div><!-- Slice 4 -->
        <span><!-- Image 1 --></span>
        <span><!-- Image 2 --></span>
        <span><!-- Image 3 --></span>
        <span><!-- Image 4 --></span>
    </div>
</div>

それぞれの<span>要素には,つぎのようにやはりbackground-imageプロパティで画像のURLを定め,パネルごとに位置決めした。さらに,transformプロパティに与えたscale()関数で拡大している。けれど,opacityプロパティが透明(0)なので表示されず,ここまでは目に見える動きは変わらない。

.bg-img div {
    width: 100px;
    height: 100%;
    position: relative;
    float: left;
    overflow: hidden;
}
.bg-img div span {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0px;
    left: 0px;
    transform: scale(1.5);
    opacity: 0;
}
#select-img-1:checked ~ .bg-img,
.bg-img div span:nth-child(1) {
    background-image: url(images/image_001.png);
}
#select-img-2:checked ~ .bg-img,
.bg-img div span:nth-child(2) {
    background-image: url(images/image_002.png);
}
#select-img-3:checked ~ .bg-img,
.bg-img div span:nth-child(3) {
    background-image: url(images/image_003.png);
}
#select-img-4:checked ~ .bg-img,
.bg-img div span:nth-child(4) {
    background-image: url(images/image_004.png);
}
.bg-img div:nth-child(1) span {
    background-position: 0px 0px;
}
.bg-img div:nth-child(2) span {
    background-position: -100px 0px;
}
.bg-img div:nth-child(3) span {
    background-position: -200px 0px;
}
.bg-img div:nth-child(4) span {
    background-position: -300px 0px;
}

そこで,画像の読み込まれた<span>要素に,つぎのようにtransitionプロパティでアニメーションを加えた。そして,ボタンで選んだパネルの<span>要素は,つぎのようにopacityプロパティの値を1の不透明にすれば,画像もクロスフェードする。さらにその画像の<span>要素は,transformプロパティのscale()関数に渡す値を実寸(1)に戻すことによりアニメーションに伸縮も加えた図4)⁠

.bg-img {

    z-index: 1;
}

.container input:checked ~ .bg-img div span {
    transition: 0.5s ease-in-out;
}
#select-img-1:checked ~ .bg-img div span:nth-child(1),
#select-img-2:checked ~ .bg-img div span:nth-child(2),
#select-img-3:checked ~ .bg-img div span:nth-child(3),
#select-img-4:checked ~ .bg-img div span:nth-child(4) {
    opacity: 1;
    transform: scale(1);
    z-index: 100;
}

図4 パネルの画像が伸縮しながらクロスフェードする

図4 パネルの画像が伸縮しながらクロスフェードする

これで,前掲サンプル1の表現ができあがった。<body>要素への記述とCSSの定めはつぎのコード3にまとめている。CSSのコードは150行を超えて,少々長めとなった。だが,参考にしたSliding Image Panels with CSS3と比べればかなり絞り込んである。

コード3 パネルに分けた画像を伸縮させながらクロスフェードする

<div class="container">
    <input id="select-img-1" name="radio-set" type="radio" checked/>
    <label for="select-img-1" class="label-img-1">1</label>
    <input id="select-img-2" name="radio-set" type="radio" />
    <label for="select-img-2" class="label-img-2">2</label>
    <input id="select-img-3" name="radio-set" type="radio" />
    <label for="select-img-3" class="label-img-3">3</label>
    <input id="select-img-4" name="radio-set" type="radio" />
    <label for="select-img-4" class="label-img-4">4</label>
    <div class="bg-img">
        <div><!--Slice 1 -->
            <span><!-- Image 1 --></span>
            <span><!-- Image 2 --></span>
            <span><!-- Image 3 --></span>
            <span><!-- Image 4 --></span>
        </div>
        <div><!-- Slice 2 -->
            <span><!-- Image 1 --></span>
            <span><!-- Image 2 --></span>
            <span><!-- Image 3 --></span>
            <span><!-- Image 4 --></span>
        </div>
        <div><!-- Slice 3 -->
            <span><!-- Image 1 --></span>
            <span><!-- Image 2 --></span>
            <span><!-- Image 3 --></span>
            <span><!-- Image 4 --></span>
        </div>
        <div><!-- Slice 4 -->
            <span><!-- Image 1 --></span>
            <span><!-- Image 2 --></span>
            <span><!-- Image 3 --></span>
            <span><!-- Image 4 --></span>
        </div>
    </div>
    <div class="img-titles">
        <h3><span class="img-title">Child</span><span class="img-caption">Single emperor penguin chick</span></h3>
        <h3><span class="img-title">Adult</span><span class="img-caption">Single penguin on a piece of ice</span></h3>
        <h3><span class="img-title">Family</span><span class="img-caption">Emperor penguin with chicks</span></h3>
        <h3><span class="img-title">Children</span><span class="img-caption">Emperor penguin chicks</span></h3>
    </div>
</div>
body {
    font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif;
    background: aliceblue;
}
.container {
    width: 400px;
    height: 267px;
    position: relative;
    margin: 0 auto;
    text-align: center;
    border: 15px solid white;
    box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
}
.container label {
    font-style: italic;
    width: 100px;
    height: 30px;
    cursor: pointer;
    color: white;
    line-height: 24px;
    font-size: 20px;
    float: left;
    position: relative;
    margin-top: 230px;
    z-index: 100;
}
.container label::before {
    content: '';
    width: 24px;
    height: 24px;
    background: rgba(135, 206, 235, 0.9);
    position: absolute;
    left: 50%;
    margin-left: -12px;
    border-radius: 50%;
    box-shadow: 0px 0px 0px 4px rgba(255, 255, 255, 0.3);
    z-index: -1;
}
.container label::after {
    content: '';
    width: 1px;
    height: 267px;
    background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
    position: absolute;
    bottom: -20px;
    right: 0px;
}
#select-img-1:checked ~ label.label-img-1,
#select-img-2:checked ~ label.label-img-2,
#select-img-3:checked ~ label.label-img-3,
#select-img-4:checked ~ label.label-img-4 {
    color: deepskyblue;
}
#select-img-1:checked ~ label.label-img-1::before,
#select-img-2:checked ~ label.label-img-2::before,
#select-img-3:checked ~ label.label-img-3::before,
#select-img-4:checked ~ label.label-img-4::before {
    background: white;
    box-shadow: 0px 0px 0px 4px rgba(0, 191, 255, 0.6);
}
.container input {
    display: none;
}
.bg-img {
    width: 400px;
    height: 267px;
    position: absolute;
    z-index: 1;
}
.bg-img div {
    width: 100px;
    height: 100%;
    position: relative;
    float: left;
    overflow: hidden;
}
.bg-img div span {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0px;
    left: 0px;
    transform: scale(1.5);
    opacity: 0;
}
#select-img-1:checked ~ .bg-img,
.bg-img div span:nth-child(1) {
    background-image: url(images/image_001.png);
}
#select-img-2:checked ~ .bg-img,
.bg-img div span:nth-child(2) {
    background-image: url(images/image_002.png);
}
#select-img-3:checked ~ .bg-img,
.bg-img div span:nth-child(3) {
    background-image: url(images/image_003.png);
}
#select-img-4:checked ~ .bg-img,
.bg-img div span:nth-child(4) {
    background-image: url(images/image_004.png);
}
.bg-img div:nth-child(1) span {
    background-position: 0px 0px;
}
.bg-img div:nth-child(2) span {
    background-position: -100px 0px;
}
.bg-img div:nth-child(3) span {
    background-position: -200px 0px;
}
.bg-img div:nth-child(4) span {
    background-position: -300px 0px;
}
.container input:checked ~ .bg-img div span {
    transition: 0.5s ease-in-out;
}
#select-img-1:checked ~ .bg-img div span:nth-child(1),
#select-img-2:checked ~ .bg-img div span:nth-child(2),
#select-img-3:checked ~ .bg-img div span:nth-child(3),
#select-img-4:checked ~ .bg-img div span:nth-child(4) {
    opacity: 1;
    transform: scale(1);
    z-index: 100;
}
.img-title, .img-caption {
    font-weight: normal;
    color: white;
    z-index: 100;
    position: absolute;
    width: 100%;
    left: 0px;
    opacity: 0;
    top: 90px;
    transition: 0.8s ease-in-out;
}
.img-title {
    left: 0px;
    font-family: "Oswald", sans-serif;
    font-size: 48px;
    letter-spacing: 3px;
}
.img-caption {
    margin-top: 100px;
    letter-spacing: 0px;
    background: rgba(130, 195, 217, 0.9);
    font-size: 14px;
    padding: 4px 0px;
    font-style: italic;
}
#select-img-1:checked ~ .img-titles h3:nth-child(1) span,
#select-img-2:checked ~ .img-titles h3:nth-child(2) span,
#select-img-3:checked ~ .img-titles h3:nth-child(3) span,
#select-img-4:checked ~ .img-titles h3:nth-child(4) span {
    opacity: 1;
}

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書

コメント

コメントの記入