Lopan.jp

CSSだけでスライドショーはつくれるよ。

この記事はCSS Programming Advent Calendar 2012、22日目のための記事です。

CSS Programmingとは、jsを使わないでHTMLとCSSを駆使してゲームとかスライドショーとか作る技術です

ということで、ここでは、前回の記事で作った、グローバルナビの下の大きめの画像のところ(以下:スライドショー)を、CSSだけで実装してみます。JavaScriptで実装したサンプルはこちら

以下が目次になります。

まえがき

CSSは、HTMLなどで書かれた文書の見栄えを指定したり、装飾したりするための言語で、<p><div>といったHTML要素に対して、加えたいスタイルを指定していきます。

CSSには「font-size(文字の大きさを指定する)」とか「background(背景に敷く色や画像を指定する)」といった、HTML要素のどの属性(特性)を装飾するかを指定するためのプロパティや、HTML要素に、より効率良くスタイルを適用できるようにするための疑似クラスセレクタといった仕様がたくさん取り揃えられています。

CSS Programmingでは、その中でも新しめの技術を使って動くものを作り出します(※なので新しめのブラウザでしか動きません)
まずは、スライドショーを作るのに使った、便利プロパティ、便利疑似クラス、便利セレクタと、便利HTML要素について。

CSS Programmingに使える便利なやつ

transitionプロパティ
CSSの値の変化をスムーズにします(トランジション効果)
値が数値のものであればなんだってスムーズになります。色は特別に数値じゃなくてもスムーズになります。
ブラウザの対応状況(transitions)

指定方法は下記の通り。

element-name {
  transition: property-name 1s ease 0s;
}

値は、transition-propertytransition-durationtransition-timing-functiontransition-delayの順番に指定します。詳しくはこちらを参照のこと。

下のサンプルでは、通常時とロールオーバー時にそれぞれ違う値を指定しており、その値の変化をtransitionでスムーズにさせています。
一番上はmargin-left、2行めはpadding-leftcolor、3行めはtext-indentletter-spacing、一番下はleftbackgroundbox-shadowの値をスムーズに変化させています。※該当CSSは52行めから67行め。

  • HTML
  • CSS
  • PREVIEW
<body id="sample1">
<div>
<p id="a">margin-left<br>
<span>transition: all 1s ease 0s</span></p>
<p id="b">padding-left &amp; color<br>
<span>transition: all 1s ease-in 0s</span></p>
<p id="c">text-indent &amp; letter-spacing<br>
<span>transition: all 1s ease-out 0s</span></p>
<p id="d">left, background &amp; box-shadow<br>
<span>transition: all 1s ease-in-out 0s</span></p>
</div>
</body>
/* :::::: sample1 :::::: */
#sample1 p {
  font: 1em/1 monospace;
}
#sample1 p span {
  font-size: 0.75em;
}
#sample1 {
  position: relative;
  width: 100%;
  height: 200px;
  margin: 0 auto;
  background: url(../img/grid.gif) left top;
}
#sample1 div {
  padding: 10px;
}
#sample1 p {
  margin: 0;
  padding: 5px 0;
  color: #593869;
  cursor: default;
  white-space: nowrap;
}
#sample1 #c {
  letter-spacing: 0;
}
#sample1 #d {
  position: absolute;
  top: 9em;
  left: 0;
  padding: 3px 10px;
}

#sample1:hover #a {
  margin-left: 200px;
}
#sample1:hover #b {
  padding-left: 200px;
  color: red;
}
#sample1:hover #c {
  text-indent: 200px;
  letter-spacing: 5px;
}
#sample1:hover #d {
  left: 200px;
  background: white;
  box-shadow: 0 3px 5px rgba(0,0,0,0.3);
}

#sample1 #a {
  transition: margin 1s ease 0s;
  -webkit-transition: margin 1s ease 0;
}
#sample1 #b {
  transition: padding 1s ease-in 0s, color 1s ease-in 0s;
  -webkit-transition: padding 1s ease-in 0, color 1s ease-in 0;
}
#sample1 #c {
  transition: text-indent 1s ease-out 0s, letter-spacing 1s ease-out 0s;
  -webkit-transition: text-indent 1s ease-out 0, letter-spacing 1s ease-out 0;
}
#sample1 #d {
  transition: left 1s ease-in-out 0s, background 1s ease-in-out 0s, box-shadow 1s ease-in-out 0s;
  -webkit-transition: left 1s ease-in-out 0, background 1s ease-in-out 0, box-shadow 1s ease-in-out 0;
}

E ~ F(間接セレクタ)
要素名と要素名の間に「~(チルダ)」を挟みます。
E ~ F」と指定した場合、「E要素より下に書かれた兄弟関係にあるF要素」にスタイルを適用します。
ブラウザの対応状況(CSS3 selector)(CSSセレクタのレベルはこちらで確認。)

HTMLの階層構造について

兄弟関係というのは、同じ階層にある要素ってこと。同じ階層というのは、同じセクション内の同じアウトラインレベルの要素ってこと。同じセクション内の同じアウトラインレベルというのはつまり、右図の通り。
左の帯の色が同じ行(インデントが同じ行)が、同じアウトラインレベルという事になります。
上下で繋がってる行が同じセクションという事になります。
上下で繋ってしかも帯の色が同じ行が同じ階層という事になります。

下に、右図と似た構造のサンプルを作ってみました。「h3 ~ p」と「blockquote ~ p」と指定したときの、スタイルの適用具合がわかります:)。※該当CSSは35行めから40行め。

<body id="sample2">  
<h1>Lopan cafe</h1>
<p>これは「<code>~</code><span>(間接セレクタ)</span>」のサンプルです。<br>
<span>※所々に入るパンの話はダミー文として読み流してください。<br>
※各テキストの要素名が分かるように<code>::before</code>疑似要素と<code>::after</code>疑似要素を使って、タグを表示してます。</span></p>
<article>
  <h2>Lopan cafeのご紹介</h2>
  <p>「<code>~</code><span>(チルダ)</span>」<span>(間接セレクタ)</span>を使って、以下のふたつのスタイルを用意しました。</p>
  <ul>
    <li>「<code>h3 ~ p</code><span>(<code>&lt;h3&gt;</code>より下に書かれた同じ階層の<code>&lt;p&gt;</code>)</span>」には赤い枠線をつける</li>
    <li>「<code>blockquote ~ p</code><span>(<code>&lt;blockquote&gt;</code>より下に書かれた同じ階層の<code>&lt;p&gt;</code>)</span>」にはグレーの背景色をつける</li>
  </ul>
  <p>それぞれ、どのように反映されるか見てみましょう。</p>
  <section>
    <p>このテキストは、<code>&lt;h3&gt;</code>より上にあるので、赤い枠線はつきません。</p>
    <h3>Lopanのパン</h3>
    <p>このテキストのように「<code>&lt;h3&gt;</code>より下に書かれた<code>&lt;p&gt;</code>」には、赤い枠線がつきます。<br>
    下の<code>&lt;ol&gt;</code>の中の<code>&lt;li&gt;</code>の中にも<code>&lt;p&gt;</code>がありますが、<em>同じ階層</em>ではないので、赤い枠線はつきません。</p>
    <ul>
      <li><p>カンパーニュ</p></li>
      <li><p>ポンデケージョ</p></li>
      <li><p>クロワッサン</p></li>
      <li><p>チョココロネ</p></li>
      <li><p>マフィン</p></li>
    </ul>
    <p>このテキストは、<code>&lt;h3&gt;</code>と<em>同じ階層</em>にあるので、赤い枠線がつきます。</p>
    <section>
      <h4>パン</h4>
      <p>このテキストは、<code>&lt;h3&gt;</code>と<em>同じ階層</em>じゃないので、赤い枠線はつきません。下の<code>&lt;blockquote&gt;</code>の中の<code>&lt;p&gt;</code>も同じく。</p>
      <blockquote cite="http://ja.wikipedia.org/wiki/パン">
        <p>1718年発行の『御前菓子秘伝抄』には、酵母菌を使ったパンの製法が記載されている。酵母菌の種として甘酒を使うという本格的なものであるが、実際に製造されたという記録はない。最初にパン(堅パン)を焼いた日本人は江戸時代の末の江川英龍とされ、彼を日本のパン祖と呼ぶ。<cite>パン - Wikipedia</cite></p>
      </blockquote>
      <p>2つめのスタイル「<code>&lt;blockquote&gt;</code>より下に書かれた同じ階層の<code>&lt;p&gt;</code>」は、背景色がグレーになります。</p>
    </section>
    <p>このテキストは<code>&lt;h3&gt;</code>と<em>同じ階層</em>。</p>
  </section>
  <section>
    <p>このテキストは、上の<code>&lt;h3&gt;</code>と同じアウトラインレベルですが、セクションが違うので、赤い枠線はつきません。</p>
    <h3>店舗について</h3>
    <p>Lopan cafeは架空の店舗です。</p>
    <blockquote cite="http://cafe.lopan.jp/pan/">
      <p>手作りパンの香りがほっこりやさしい気持ちにしてくれる、あなたの街のパンカフェです。<br>
      おいしいパンとあったかカフェで、心やすらぐ特別なひとときをご提供いたします。<cite>Lopanのパン | カフェ&ベーカリー「Lopan cafe」</cite></p>
    </blockquote>
    <p>美味しそうなパンがめくるめくよりどりみどり。</p>
  </section>
</article>
</body>
/* :::::: sample2 :::::: */
#sample2 {
  padding: 10px;
}
#sample2 h2,
#sample2 h3,
#sample2 h4,
#sample2 p {
  margin: 0 0 10px;
}
#sample2 p span,
#sample2 li span {
  font-size: 0.8em;
}
#sample2 li p {
  margin: 0;
}
#sample2 code,
#sample2 em {
  margin: 0 2px;
}
#sample2 article,
#sample2 section {
  padding: 10px;
  border: 1px #ccc solid;
}
#sample2 section {
  margin-bottom: 10px;
}
#sample2 blockquote cite {
  font-size: 80%;
  font-style: normal;
}

#sample2 h3 ~ p {
  border: #e34556 2px solid;
}
#sample2 blockquote ~ p {
  background: #eee url(../img/bg_amiten.gif);
}

#sample2 section::before,
#sample2 h1::after,
#sample2 h2::after,
#sample2 h3::after,
#sample2 h4::after,
#sample2 p::after,
#sample2 ul::before,
#sample2 li::before,
#sample2 blockquote::before {
  padding: 0 3px;
  background: white;
  color: #999;
  font: 10px/1 "lucida grande",Arial,sans-serif;
  font-size: 10px;
  font-weight: normal;
  vertical-align: text-top;
}
#sample2 section::before { content: "<section>"; }
#sample2 h1::after { content: "<h1>"; }
#sample2 h2::after { content: "<h2>"; }
#sample2 h3::after { content: "<h3>"; }
#sample2 h4::after { content: "<h4>"; }
#sample2 p::after { content: "<p>"; }
#sample2 ul::before { content: "<ul>"; }
#sample2 li::before { content: "<li>"; float: left; }
#sample2 blockquote::before { content: "<blockquote>"; }

:not(s)否定疑似クラス
(s)の部分には、要素の属性、もしくは属性とその値を指定できます。
「その属性を持った要素」、もしくは「その属性でその値を持った要素」以外に、スタイルを適用します。

classとかtypeとかtitleとかを、下記みたく指定できます。※該当CSSは14行めから30行め。

  • HTML
  • CSS
  • PREVIEW
<body id="sample3">  
<h1><code>:not(s)</code><span>(否定疑似クラス)</span>を使ったサンプル</h1>
<ul>
  <li class="notSmall">小さくないテキスト</li>
  <li class="notRed">赤くないテキスト</li>
  <li>何も指定してないテキスト</li>
</ul>
<blockquote>
  <p><abbr title="Cascading Style Sheets">CSS</abbr>は<abbr title="HyperText Markup Language">HTML</abbr>で表現可能と考えられるデザインの大部分を実現できる要素を取り入れつつ、新たなデザイン機能を備える。<span><a href="http://ja.wikipedia.org/wiki/Cascading_Style_Sheets" title="HyperText Markup Language - Wikipedia">Wikipediaより</a></span></p>
</blockquote>
<form>
  <p><input type="checkbox" id="checkbox"> <label for="checkbox">チェックボックス</label><br>
  <input type="radio" id="radio"> <label for="radio">ラジオボタン<span>は半透明にならない</span></label><br>
  <input type="text" id="text"> <label for="text">テキストボックス</label><br>
  <input type="reset" id="reset" value="リセットボタン"> <label for="reset">リセットボタン</label></p>
</form>
</body>
/* :::::: sample3 :::::: */
#sample3 {
  padding: 10px;
}
#sample3 ul,
#sample3 p {
  margin-top: 0;
  margin-bottom: 10px;
}
#sample3 h1 span,
#sample3 p span {
  font-size: 0.75em;
}
/* notSmallというクラスが付いてないli要素 */
#sample3 li:not([class="notSmall"]) {
  font-size: small;
}
/* notRedというクラスが付いてないli要素 */
#sample3 li:not(.notRed) {
  color: red;
}
/* titleが「Cascading Style Sheets」以外のabbr要素 */
#sample3 abbr:not([title="Cascading Style Sheets"]) {
  background: #eee url(../img/bg_amiten.gif);
}
/* ラジオボタンとそのラベル以外のinput要素とlabel要素 */
#sample3 input:not([type="radio"]),
#sample3 label:not([for="radio"]) {
  opacity: 0.2;
}

#sample3 h1::after,
#sample3 p::after,
#sample3 li::after,
#sample3 input::after,
#sample3 label::after,
#sample3 blockquote::before {
  padding: 0 3px;
  background: white;
  color: #999;
  font: 10px/1 "lucida grande",Arial,sans-serif;
  font-size: 10px;
  font-weight: normal;
  vertical-align: text-top;
}
#sample3 h1::after { content: "<h1>"; }
#sample3 p::after { content: "<p>"; }
#sample3 li::after { content: "<li>"; }
#sample3 input::after { content: "<input>"; }
#sample3 label::after { content: "<label>"; }
#sample3 blockquote::before { content: "<blockquote>"; }

:checked疑似クラス
ラジオボタンチェックボックスがチェックされている時のみスタイルが適用されます。
input:checked ~ p」と指定した場合、「<input>がチェックされている時のみ、その<input>より下に書かれた兄弟関係にあるF要素」にスタイルが適用されます。

例えば下のサンプルでは、左側のチェックボックスがチェックされている時は下のテキストが赤色に、右側のチェックボックスがチェックされている時は青色に、両方ともチェックされている時は紫色になります。※該当CSSは44行めから52行め。

  • HTML
  • CSS
  • PREVIEW
<body id="sample4">	
<div>
<input type="checkbox" name="color" id="red"> <label for="red">←id="red"</label>
<input type="checkbox" name="color" id="blue"> <label for="blue">←id="blue"</label>
<ul>
<li><label for="red">label for="red"</label></li>
<li><label for="blue">label for="blue"</label></li>
</ul>
<p>このテキストの色が変わります。</p>
</div>
</body>
/* :::::: sample4 :::::: */
#sample4 div {
  position: relative;
  width: 360px;
  margin: 0 auto;
  padding: 10px 10px 0;
  text-align: center;
}

#sample4 input {
  vertical-align: text-bottom;
}

#sample4 ul {
  margin: 10px 0;
  padding: 0;
  overflow: hidden;
  list-style: none;
  color: white;
}
#sample4 ul li {
  width: 48%;
  border-radius: 5px;
}
#sample4 ul li label {
  display: block;
  padding: 3px;
}
#sample4 li:first-child {
  float: left;
  background: red;
}
#sample4 li:last-child {
  float: right;
  background: blue;
}

#sample4 p {
  margin: 0;
  color: #aaa;
  font-size: 2.4em;
  line-height: 1.4;
}
#sample4 #red:checked ~ p {
  color: red;
}
#sample4 #blue:checked ~ p {
  color: blue;
}
#sample4 #red:checked ~ #blue:checked ~ p {
  color: purple;
}

<label>要素
<input>id属性の値と、<label>for属性の値を同じにすることで、ふたつの要素を関連づける事ができるようになります<label>の部分をクリックしても、<input>を切り替えることができるようになる)

上のサンプルを参照のこと:)。

目次に戻る

それCSSで出来るよ。

上記をふまえて、CSSでスライドショーをつくります。といってもベースはJavaScriptのものと同じです。
(※スライドショーの仕様やHTMLの構造については前回の記事を参照ください。X)

JavaScriptで実装したスライドショーは 、クリックしたら動く仕組み

まずは、動かすためのきっかけづくりから。

前回、JavaScriptで実装した時には、画像をスライドさせるきっかけは「クリックした時」でした。
例えば、矢印をクリックしたら隣の画像の位置までスライドしたり、下のチョボをクリックしたらその画像の位置までスライドしたり…。
クリックをきっかけに、その時の条件によって行う処理を変えていました。

これをCSSで実現するにはどうすればいいでしょう?

きっかけづくり

例えば下記のコード。
「リンクには下線をつける。ロールオーバーした時は下線を消す」という指定です。

a { text-decoration: underline; }
a:hover { text-decoration: none; }

これと同じ要領で、「最初のラジオボタンをチェックした時は○○する。二番目のラジオボタンをチェックした時は○○する」というような指定にすれば、クリックしたら表示が切り替わるという事になりますね。

きっかけを「(ラジオボタンを)チェックした時」などに置き換えれば、「クリックした時」みたいな処理も実現できそうです。

目次に戻る

チョボのところの仕組み

下のチョボをクリックした時に、画像がチョボ番目までスライドするようにします。
チョボはちょうど見た目もラジオボタンみたいな形だし、機能としてもラジオボタンとほぼ同じなので、ラジオボタンに置き換えてみます。<input type="radio">に。

<ul class="nav">
  <li><a href="#"></a></li>
  <li><a href="#"></a></li>
  <li><a href="#"></a></li>
</ul>
	⇓
<ul class="nav">
  <li><input type="radio" name="gallery" checked="checked"></li>
  <li><input type="radio" name="gallery"></li>
  <li><input type="radio" name="gallery"></li>
</ul>

ひとつめのチョボは初期位置なので始めからチェックしておいて、CSSでチェックされているチョボの位置によって.slideFrameの中の<ul>の位置を変更するように指定します。

~:checked

チョボをチェックした時の画像の位置

input:first-of-type:checked ~ .slideFrame ul {
  left: 90px;
}

上記は「ひとつめのinput要素がチェックされてる時は、それ以降の兄弟関係にある.slideFrameの中のul要素の位置を、左から90pxの位置にする」という指定です。:first-of-typeとかについては後述します。

同じように、2番目の時は-450px、3番目のときは-990px、となるようにそれぞれ指定します。※該当CSSは107行めから115行め

  • HTML
  • CSS
  • PREVIEW
<div id="gallery">
  <div class="slideFrame">
    <ul>
      <li><a href="#"><img src="img/gallery_visual1.jpg" alt="gallery_visual1" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual2.jpg" alt="gallery_visual2" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual3.jpg" alt="gallery_visual3" width="520" height="280"></a></li>
    </ul>
  </div>
  <ul class="nav">
    <li><input type="radio" id="switch1" name="gallery" checked="checked"></li>
    <li><input type="radio" id="switch2" name="gallery"></li>
    <li><input type="radio" id="switch3" name="gallery"></li>
  </ul>
  <p class="prev"><a href="#"></a></p>
  <p class="next"><a href="#"></a></p>
<!-- /#gallery --></div>
</body>
/* :::::: gallery ::::::
 * #gallery内の指定
 */
#gallery {
  position: relative;
  width: 700px;
  height: 300px;
  margin: 10px auto;
  padding: 10px 0;
  background: url(../img/bg_gallery.jpg);
}
#gallery .slideFrame {
  position: relative;
  height: 280px;
  overflow: hidden;
  margin-bottom: 10px;
}

/* slide images */
#gallery .slideFrame ul {
  position: absolute;
  top: 0;
  left: 90px;
  width: 1620px;
  margin: 0;
}
#gallery .slideFrame ul li {
  float: left;
  width: 520px;
  margin-right: 20px;
}
#gallery .slideFrame ul li:last-child {
  margin-right: 0;
}
#gallery .slideFrame ul li a {
  background: none;
}

/* gallery items */
#gallery ul li,
#gallery ul li input,
#gallery p,
#gallery p a {
  background: url(../img/gallery_item.png);
}

/* gallery list button */
#gallery ul.nav {
  width: 62px;
  margin: 0 auto;
  padding: 0;
}
#gallery ul.nav li {
  float: left;
  margin-right: 16px;
  background-position: -260px 0;
}
#gallery ul.nav li:last-child {
  margin-right: 0;
}
#gallery ul.nav li input {
  display: block;
  width: 10px;
  height: 10px;
  border: 0;
  background-position: -260px -20px;
  cursor: pointer;
}
#gallery ul.nav li input:hover,
#gallery ul.nav li input:checked { opacity: 0; }

/* slider arrow button */
#gallery p {
  position: absolute;
  top: 0;
  margin: 0;
  width: 110px;
  height: 320px;
  cursor: pointer;
}
#gallery p.prev {
  left: 0;
}
#gallery p.next {
  right: 0;
  background-position: -110px 0;
}
#gallery p a {
  display: block;
  width: 26px;
  height: 26px;
  margin: 140px 0 0 40px;
  background-position: -230px 0;
}
#gallery p:hover a {
  margin: 140px 0 0 32px;
}
#gallery p.next a {
  margin-left: 44px;
  background-position: -230px -30px;
}
#gallery p.next:hover a {
  margin-left: 52px;
}

/* CSS Programming */
#gallery input:first-of-type:checked ~ .slideFrame ul {
  left: 90px;
}
#gallery input:nth-of-type(2):checked ~ .slideFrame ul {
  left: -450px;
}
#gallery input:nth-of-type(3):checked ~ .slideFrame ul {
  left: -990px;
}

/* transition */
#gallery ul.nav li input {
  transition: opacity 0.5s ease 0s;
  -webkit-transition: opacity 0.5s ease 0;
}
#gallery p a {
  transition: margin 0.3s ease 0s;
  -webkit-transition: margin 0.3s ease 0;
}

/* clearfix */
#gallery ul:before, #gallery ul:after {
  content: ""; display: table;
}
#gallery ul:after {
  clear: both;
}
#gallery ul {
  *zoom: 1;
}

動きませんね…X(。

それもそのはず、<input>.slideFrameよりも下になっちゃってるからです。「~(間接セレクタ)」はその要素より下に書かれた兄弟関係にある要素にスタイルを適用するので、

は上に添えるだけ

ちゃんと適用するには、<input>.slideFrameよりも上に、しかも.slideFrameの兄弟関係でないといけないので、<ul>から出して、<input>だけを3つ並べます。
これで「inputの下に書かれた兄弟関係にある.slideFrame」という構造になりました:)。

<label>

チョボは<label>に

そしてチョボのところはというと、<input>の代わりに<label>に置き換えます。
この<label>for属性の値と、上の<input>id属性の値を同じにすれば、チョボをクリックして上の<input>を切り替えることができるようになりますもんね。属性の値はswitch1, switch2, switch3という感じにしました。

あと、チェックしたチョボ自体の表示も変わるように、CSSに下記のような指定もプラスインします。(※<input>id属性が付いたので、input:first-of-type#switch1input:nth-of-type(n)#switch2#switch3に置き換えられますね。)

チョボの仕組み

#switch1:checked ~ .nav li label[for="switch1"],
#switch2:checked ~ .nav li label[for="switch2"],
#switch3:checked ~ .nav li label[for="switch3"] {
  opacity: 0;
}

チェックされた<input>に関連づけられた<label>を透明にする事で、<li>の背景画像(黄チョボ)が表示されるようになってます。

上に移動した<input>は、チェックしたか/チェックしてないかを切り替えるためのスイッチ的な役割だけなので、display: none;で非表示にしても問題ないです(下のサンプルではまだ表示してます)

  • HTML
  • CSS
  • PREVIEW
<div id="gallery">
  <input type="radio" id="switch1" name="gallery" checked="checked">
  <input type="radio" id="switch2" name="gallery">
  <input type="radio" id="switch3" name="gallery">
  <div class="slideFrame">
    <ul>
      <li><a href="#"><img src="img/gallery_visual1.jpg" alt="gallery_visual1" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual2.jpg" alt="gallery_visual2" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual3.jpg" alt="gallery_visual3" width="520" height="280"></a></li>
    </ul>
  </div>
  <ul class="nav">
    <li><label for="switch1"></label></li>
    <li><label for="switch2"></label></li>
    <li><label for="switch3"></label></li>
  </ul>
  <p class="prev"><a href="#"></a></p>
  <p class="next"><a href="#"></a></p>
<!-- /#gallery --></div>
/* gallery items */
#gallery ul li,
#gallery ul li label,
#gallery p,
#gallery p a {
  background: url(../img/gallery_item.png);
}

/* gallery list button */
#gallery ul.nav {
  width: 62px;
  margin: 0 auto;
  padding: 0;
}
#gallery ul.nav li {
  float: left;
  margin-right: 16px;
  background-position: -260px 0;
}
#gallery ul.nav li:last-child {
  margin-right: 0;
}
#gallery ul.nav li label {
  display: block;
  width: 10px;
  height: 10px;
  background-position: -260px -20px;
}
#gallery ul.nav li label:hover { opacity: 0; }

/* slider arrow button */
#gallery p {
  position: absolute;
  top: 0;
  margin: 0;
  width: 110px;
  height: 320px;
  cursor: pointer;
}
#gallery p.prev {
  left: 0;
}
#gallery p.next {
  right: 0;
  background-position: -110px 0;
}
#gallery p a {
  display: block;
  width: 26px;
  height: 26px;
  margin: 140px 0 0 40px;
  background-position: -230px 0;
}
#gallery p:hover a {
  margin: 140px 0 0 32px;
}
#gallery p.next a {
  margin-left: 44px;
  background-position: -230px -30px;
}
#gallery p.next:hover a {
  margin-left: 52px;
}

/* CSS Programming */
#gallery #switch1:checked ~ .slideFrame ul {
  left: 90px;
}
#gallery #switch2:checked ~ .slideFrame ul {
  left: -450px;
}
#gallery #switch3:checked ~ .slideFrame ul {
  left: -990px;
}
#gallery #switch1:checked ~ .nav li label[for="switch1"],
#gallery #switch2:checked ~ .nav li label[for="switch2"],
#gallery #switch3:checked ~ .nav li label[for="switch3"] {
  opacity: 0;
}

/* transition */
#gallery ul.nav li label {
  transition: opacity 0.5s ease 0s;
  -webkit-transition: opacity 0.5s ease 0;
}
#gallery p a {
  transition: margin 0.3s ease 0s;
  -webkit-transition: margin 0.3s ease 0;
}

チョボをクリックすると、チョボ番目の画像が表示されるようになりましたね。
けどまだただ切り替わってるだけなので、これを、transitionを使って、スムーズに切り替わるようにします。

transition

.slideFrameの中の<ul>の、leftプロパティの値を変化させているので、下記のように指定します。
ちょっとゆっくりめに、1秒かけてスライドするようにしました。該当CSSは93行めから96行め。
※矢印はまだクリックしても何も起きません。

  • HTML
  • CSS
  • PREVIEW
<div id="gallery">
  <input type="radio" id="switch1" name="gallery" checked="checked">
  <input type="radio" id="switch2" name="gallery">
  <input type="radio" id="switch3" name="gallery">
  <div class="slideFrame">
    <ul>
      <li><a href="#"><img src="img/gallery_visual1.jpg" alt="gallery_visual1" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual2.jpg" alt="gallery_visual2" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual3.jpg" alt="gallery_visual3" width="520" height="280"></a></li>
    </ul>
  </div>
  <ul class="nav">
    <li><label for="switch1"></label></li>
    <li><label for="switch2"></label></li>
    <li><label for="switch3"></label></li>
  </ul>
  <p class="prev"><a href="#"></a></p>
  <p class="next"><a href="#"></a></p>
<!-- /#gallery --></div>
/* gallery items */
#gallery ul li,
#gallery ul li label,
#gallery p,
#gallery p a {
  background: url(../img/gallery_item.png);
}

/* gallery list button */
#gallery ul.nav {
  width: 62px;
  margin: 0 auto;
  padding: 0;
}
#gallery ul.nav li {
  float: left;
  margin-right: 16px;
  background-position: -260px 0;
}
#gallery ul.nav li:last-child {
  margin-right: 0;
}
#gallery ul.nav li label {
  display: block;
  width: 10px;
  height: 10px;
  background-position: -260px -20px;
}
#gallery ul.nav li label:hover { opacity: 0; }

/* slider arrow button */
#gallery p {
  position: absolute;
  top: 0;
  margin: 0;
  width: 110px;
  height: 320px;
  cursor: pointer;
}
#gallery p.prev {
  left: 0;
}
#gallery p.next {
  right: 0;
  background-position: -110px 0;
}
#gallery p a {
  display: block;
  width: 26px;
  height: 26px;
  margin: 140px 0 0 40px;
  background-position: -230px 0;
}
#gallery p:hover a {
  margin: 140px 0 0 32px;
}
#gallery p.next a {
  margin-left: 44px;
  background-position: -230px -30px;
}
#gallery p.next:hover a {
  margin-left: 52px;
}

/* CSS Programming */
#gallery #switch1:checked ~ .slideFrame ul {
  left: 90px;
}
#gallery #switch2:checked ~ .slideFrame ul {
  left: -450px;
}
#gallery #switch3:checked ~ .slideFrame ul {
  left: -990px;
}
#gallery #switch1:checked ~ .nav li label[for="switch1"],
#gallery #switch2:checked ~ .nav li label[for="switch2"],
#gallery #switch3:checked ~ .nav li label[for="switch3"] {
  opacity: 0;
}
#gallery input {
  display: none;
}

/* transition */
#gallery ul.nav li label {
  transition: opacity 0.5s ease 0s;
  -webkit-transition: opacity 0.5s ease 0;
}
#gallery p a {
  transition: margin 0.3s ease 0s;
  -webkit-transition: margin 0.3s ease 0;
}
#gallery .slideFrame ul {
  transition: left 1s ease 0s;
  -webkit-transition: left 1s ease 0;
}

これにて、3つチョボの機能、実装完了です!

目次に戻る

目次に戻る

左右の矢印の機能

矢印はチョボと違って、クリックする度に役割が変わります。(※詳しい話は前回の記事を参照ください。X)

左右の矢印の機能

例えば、一番左の画像が表示されてる時に右矢印をクリックすると、二番目の画像のところまでスライドします。これを<input>的に言うと「<input id="switch2">checkedにする」という事。
二番めの画像が表示されてる時に右矢印をクリックすると、三番目の画像のところまでスライドします。これは「<input id="switch3">checkedにする」という事になります。

矢印をクリックする度に<label>for属性を替える事ができれば実現できそうです。

<label>ごと切り替える

とはいったものの、for属性だけを書き換える事はCSSだけじゃ出来ないので、左右にそれぞれ<label>を3つずつ用意して、クリックする度に<label>自体を切り替えるようにしてみます。
「一番左の画像が表示されてる時に右矢印をクリック」した時は、<label for="switch2">をクリックさせたいので、<label for="switch1"><label for="switch3">を非表示に。「二番目の画像が表示されてる時に右矢印をクリック」した時は、<label for="switch3">をクリックさせたいので、<label for="switch1"><label for="switch2">を非表示に…、
と、全部のパターンを書き出すと、下記のようになりました(上の<input>を非表示にしてるやつに書き足しました)

#gallery input,
#gallery #switch1:checked ~ .prev label[for="switch1"],
#gallery #switch1:checked ~ .prev label[for="switch2"],
#gallery #switch2:checked ~ .prev label[for="switch2"],
#gallery #switch2:checked ~ .prev label[for="switch3"],
#gallery #switch3:checked ~ .prev label[for="switch1"],
#gallery #switch3:checked ~ .prev label[for="switch3"],
#gallery #switch1:checked ~ .next label[for="switch1"],
#gallery #switch1:checked ~ .next label[for="switch3"],
#gallery #switch2:checked ~ .next label[for="switch1"],
#gallery #switch2:checked ~ .next label[for="switch2"],
#gallery #switch3:checked ~ .next label[for="switch2"],
#gallery #switch3:checked ~ .next label[for="switch3"] {
  display: none;
}

:not(s)

:not(s)(否定疑似クラス)」を使ったらちょっと短くなりました。

#gallery input,
#gallery #switch1:checked ~ .prev label:not([for="switch3"]),
#gallery #switch2:checked ~ .prev label:not([for="switch1"]),
#gallery #switch3:checked ~ .prev label:not([for="switch2"]),
#gallery #switch1:checked ~ .next label:not([for="switch2"]),
#gallery #switch2:checked ~ .next label:not([for="switch3"]),
#gallery #switch3:checked ~ .next label:not([for="switch1"]) {
  display: none;
}

上記に倣って、左右の矢印に<label>を設置します。

  • HTML
  • CSS
  • PREVIEW
<div id="gallery">
  <input type="radio" id="switch1" name="gallery" checked="checked">
  <input type="radio" id="switch2" name="gallery">
  <input type="radio" id="switch3" name="gallery">
  <div class="slideFrame">
    <ul>
      <li><a href="#"><img src="img/gallery_visual1.jpg" alt="gallery_visual1" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual2.jpg" alt="gallery_visual2" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual3.jpg" alt="gallery_visual3" width="520" height="280"></a></li>
    </ul>
  </div>
  <ul class="nav">
    <li><label for="switch1"></label></li>
    <li><label for="switch2"></label></li>
    <li><label for="switch3"></label></li>
  </ul>
  <p class="prev">
    <label for="switch1"><i></i></label>
    <label for="switch2"><i></i></label>
    <label for="switch3"><i></i></label>
  </p>
  <p class="next">
    <label for="switch1"><i></i></label>
    <label for="switch2"><i></i></label>
    <label for="switch3"><i></i></label>
  </p>
<!-- /#gallery --></div>
/* gallery items */
#gallery ul li,
#gallery ul li label,
#gallery p label,
#gallery p label i {
  background: url(../img/gallery_item.png);
}

/* gallery list button */
#gallery ul.nav {
  width: 62px;
  margin: 0 auto;
  padding: 0;
}
#gallery ul.nav li {
  float: left;
  margin-right: 16px;
  background-position: -260px 0;
}
#gallery ul.nav li:last-child {
  margin-right: 0;
}
#gallery ul.nav li label {
  display: block;
  width: 10px;
  height: 10px;
  background-position: -260px -20px;
}
#gallery ul.nav li label:hover { opacity: 0; }

/* slider arrow button */
#gallery p label {
  position: absolute;
  top: 0;
  margin: 0;
  width: 110px;
  height: 320px;
  cursor: pointer;
}
#gallery .prev label {
  left: 0;
}
#gallery .next label {
  right: 0;
  background-position: -110px 0;
}
#gallery p label i {
  display: block;
  width: 26px;
  height: 26px;
  margin: 140px 0 0 40px;
  background-position: -230px 0;
}
#gallery p:hover label i {
  margin: 140px 0 0 32px;
}
#gallery .next label i {
  margin-left: 44px;
  background-position: -230px -30px;
}
#gallery .next:hover label i {
  margin-left: 52px;
}

/* CSS Programming */
#gallery #switch1:checked ~ .slideFrame ul {
  left: 90px;
}
#gallery #switch2:checked ~ .slideFrame ul {
  left: -450px;
}
#gallery #switch3:checked ~ .slideFrame ul {
  left: -990px;
}
#gallery #switch1:checked ~ .nav li label[for="switch1"],
#gallery #switch2:checked ~ .nav li label[for="switch2"],
#gallery #switch3:checked ~ .nav li label[for="switch3"] {
  opacity: 0;
}
#gallery input,
#gallery #switch1:checked ~ .prev label[for="switch1"],
#gallery #switch1:checked ~ .prev label[for="switch2"],
#gallery #switch2:checked ~ .prev label[for="switch2"],
#gallery #switch2:checked ~ .prev label[for="switch3"],
#gallery #switch3:checked ~ .prev label[for="switch1"],
#gallery #switch3:checked ~ .prev label[for="switch3"],
#gallery #switch1:checked ~ .next label[for="switch1"],
#gallery #switch1:checked ~ .next label[for="switch3"],
#gallery #switch2:checked ~ .next label[for="switch1"],
#gallery #switch2:checked ~ .next label[for="switch2"],
#gallery #switch3:checked ~ .next label[for="switch2"],
#gallery #switch3:checked ~ .next label[for="switch3"] {
  display: none;
}

/* transition  */
#gallery ul.nav li label {
  transition: opacity 0.5s ease 0s;
  -webkit-transition: opacity 0.5s ease 0;
}
#gallery p label i {
  transition: margin 0.3s ease 0s;
  -webkit-transition: margin 0.3s ease 0;
}
#gallery .slideFrame ul {
  transition: left 1s ease 0s;
  -webkit-transition: left 1s ease 0;
}

これにて、左右の矢印も実装完了です!

目次に戻る

イージングを調整する

CSSのtransition変化の仕方(イージング)を微調整することもできます。
最初から定義されているイージングにはeaselinearease-inease-outease-in-outの5つあります(前述のtransitionのサンプル参照)が、それ以外にも、オリジナルなイージングが作れます!

cubic-bezier()

transition: left 1s ease 0s;

上記の「ease」のところを「cubic-bezier()」に置き換えて、下記のように書きます。

transition: left 1s cubic-bezier(0.25, 0.1, 0.25, 1.0) 0s;

パスで線を描く時に操作するアレ

括弧の中には、数値が4つ「,(コンマ)」区切りで入ります。この数値が何を表すかと言うと、右図参照。

Illustratorとかで使うベジェ曲線(パス)のベクトル(?)を操作する時に触るアレの、座標位置になります。
括弧の中は「左下のX座標, 左下のY座標, 右上のX座標, 右上のY座標」という順番で記述します。

けどこの数値を、想像だけで指定するなんて無茶ですよね…X(。なので、下記のようなサイトがちゃんと用意されています。

cubic-bezier ✿ cubic-bezier.com

作ったベジェ曲線を保存しておけて、後からそれを並べて比較できるので分かりよいです。(2012.12.22現在)
これでビジュアルで確認しながら思い通りの動きが作れますね:D!

普通のイージングは嫌だけど自分で作るのはめんどくさいなって人は、下記のサイトに、jQuery easingにあるイージングがすでに用意(定義)されているので、こちらからコピペするのが簡単かもしれません。

Easing Functions Cheat Sheet

Easing Functions Cheat Sheet

並んでるイージングの中から好きなものをクリックして、詳細ページにあるコードをコピペするだけです。
JavaScript用と、SCSS用、CSS用とありますが、今回はCSS用のものをコピペ。
※個人的に「jQuery EasingではeaseOutExpoが一番好き」なので、下のサンプルでは「easeOutExpo」をコピペしてみました。該当CSSは100、101行め。

  • HTML
  • CSS
  • PREVIEW
<div id="gallery">
  <input type="radio" id="switch1" name="gallery" checked="checked">
  <input type="radio" id="switch2" name="gallery">
  <input type="radio" id="switch3" name="gallery">
  <div class="slideFrame">
    <ul>
      <li><a href="#"><img src="img/gallery_visual1.jpg" alt="gallery_visual1" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual2.jpg" alt="gallery_visual2" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual3.jpg" alt="gallery_visual3" width="520" height="280"></a></li>
    </ul>
  </div>
  <ul class="nav">
    <li><label for="switch1"></label></li>
    <li><label for="switch2"></label></li>
    <li><label for="switch3"></label></li>
  </ul>
  <p class="prev">
    <label for="switch1"><i></i></label>
    <label for="switch2"><i></i></label>
    <label for="switch3"><i></i></label>
  </p>
  <p class="next">
    <label for="switch1"><i></i></label>
    <label for="switch2"><i></i></label>
    <label for="switch3"><i></i></label>
  </p>
<!-- /#gallery --></div>
/* gallery items */
#gallery ul li,
#gallery ul li label,
#gallery p label,
#gallery p label i {
  background: url(../img/gallery_item.png);
}

/* gallery list button */
#gallery ul.nav {
  width: 62px;
  margin: 0 auto;
  padding: 0;
}
#gallery ul.nav li {
  float: left;
  margin-right: 16px;
  background-position: -260px 0;
}
#gallery ul.nav li:last-child {
  margin-right: 0;
}
#gallery ul.nav li label {
  display: block;
  width: 10px;
  height: 10px;
  background-position: -260px -20px;
}
#gallery ul.nav li label:hover { opacity: 0; }

/* slider arrow button */
#gallery p label {
  position: absolute;
  top: 0;
  margin: 0;
  width: 110px;
  height: 320px;
  cursor: pointer;
}
#gallery .prev label {
  left: 0;
}
#gallery .next label {
  right: 0;
  background-position: -110px 0;
}
#gallery p label i {
  display: block;
  width: 26px;
  height: 26px;
  margin: 140px 0 0 40px;
  background-position: -230px 0;
}
#gallery p:hover label i {
  margin: 140px 0 0 32px;
}
#gallery .next label i {
  margin-left: 44px;
  background-position: -230px -30px;
}
#gallery .next:hover label i {
  margin-left: 52px;
}

/* CSS Programming */
#gallery #switch1:checked ~ .slideFrame ul {
  left: 90px;
}
#gallery #switch2:checked ~ .slideFrame ul {
  left: -450px;
}
#gallery #switch3:checked ~ .slideFrame ul {
  left: -990px;
}
#gallery #switch1:checked ~ .nav li label[for="switch1"],
#gallery #switch2:checked ~ .nav li label[for="switch2"],
#gallery #switch3:checked ~ .nav li label[for="switch3"] {
  opacity: 0;
}
#gallery input,
#gallery #switch1:checked ~ .prev label:not([for="switch3"]),
#gallery #switch2:checked ~ .prev label:not([for="switch1"]),
#gallery #switch3:checked ~ .prev label:not([for="switch2"]),
#gallery #switch1:checked ~ .next label:not([for="switch2"]),
#gallery #switch2:checked ~ .next label:not([for="switch3"]),
#gallery #switch3:checked ~ .next label:not([for="switch1"]) {
  display: none;
}

/* transition  */
#gallery ul.nav li label {
  transition: opacity 0.5s ease 0s;
  -webkit-transition: opacity 0.5s ease 0;
}
#gallery p label i {
  transition: margin 0.3s ease 0s;
  -webkit-transition: margin 0.3s ease 0;
}
#gallery .slideFrame ul {
  transition: left 1s cubic-bezier(0.19, 1, 0.22, 1) 0s;
  -webkit-transition: left 1s cubic-bezier(0.19, 1, 0.22, 1) 0;
}

easeOutExpoがいまいちだったので…、自分なりに調整してみました。「easeInOutExpo」に似てるかな:)。

  • HTML
  • CSS
  • PREVIEW
<div id="gallery">
  <input type="radio" id="switch1" name="gallery" checked="checked">
  <input type="radio" id="switch2" name="gallery">
  <input type="radio" id="switch3" name="gallery">
  <div class="slideFrame">
    <ul>
      <li><a href="#"><img src="img/gallery_visual1.jpg" alt="gallery_visual1" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual2.jpg" alt="gallery_visual2" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual3.jpg" alt="gallery_visual3" width="520" height="280"></a></li>
    </ul>
  </div>
  <ul class="nav">
    <li><label for="switch1"></label></li>
    <li><label for="switch2"></label></li>
    <li><label for="switch3"></label></li>
  </ul>
  <p class="prev">
    <label for="switch1"><i></i></label>
    <label for="switch2"><i></i></label>
    <label for="switch3"><i></i></label>
  </p>
  <p class="next">
    <label for="switch1"><i></i></label>
    <label for="switch2"><i></i></label>
    <label for="switch3"><i></i></label>
  </p>
<!-- /#gallery --></div>
/* gallery items */
#gallery ul li,
#gallery ul li label,
#gallery p label,
#gallery label i {
  background: url(../img/gallery_item.png);
}

/* gallery list button */
#gallery ul.nav {
  width: 62px;
  margin: 0 auto;
  padding: 0;
}
#gallery ul.nav li {
  float: left;
  margin-right: 16px;
  background-position: -260px 0;
}
#gallery ul.nav li:last-child {
  margin-right: 0;
}
#gallery ul.nav li label {
  display: block;
  width: 10px;
  height: 10px;
  background-position: -260px -20px;
}
#gallery ul.nav li label:hover { opacity: 0; }

/* slider arrow button */
#gallery p label {
  position: absolute;
  top: 0;
  margin: 0;
  width: 110px;
  height: 320px;
  cursor: pointer;
}
#gallery .prev label {
  left: 0;
}
#gallery .next label {
  right: 0;
  background-position: -110px 0;
}
#gallery p label i {
  display: block;
  width: 26px;
  height: 26px;
  margin: 140px 0 0 40px;
  background-position: -230px 0;
}
#gallery p:hover label i {
  margin: 140px 0 0 32px;
}
#gallery .next label i {
  margin-left: 44px;
  background-position: -230px -30px;
}
#gallery .next:hover label i {
  margin-left: 52px;
}

/* CSS Programming */
#gallery #switch1:checked ~ .slideFrame ul {
  left: 90px;
}
#gallery #switch2:checked ~ .slideFrame ul {
  left: -450px;
}
#gallery #switch3:checked ~ .slideFrame ul {
  left: -990px;
}
#gallery #switch1:checked ~ .nav li label[for="switch1"],
#gallery #switch2:checked ~ .nav li label[for="switch2"],
#gallery #switch3:checked ~ .nav li label[for="switch3"] {
  opacity: 0;
}
#gallery input,
#gallery #switch1:checked ~ .prev label:not([for="switch3"]),
#gallery #switch2:checked ~ .prev label:not([for="switch1"]),
#gallery #switch3:checked ~ .prev label:not([for="switch2"]),
#gallery #switch1:checked ~ .next label:not([for="switch2"]),
#gallery #switch2:checked ~ .next label:not([for="switch3"]),
#gallery #switch3:checked ~ .next label:not([for="switch1"]) {
  display: none;
}

/* transition  */
#gallery ul.nav li label  {
  transition: all 0.5s ease 0s;
  -webkit-transition: all 0.5s ease 0;
}
#gallery label i  {
  transition: all 0.3s ease 0s;
  -webkit-transition: all 0.3s ease 0;
}
#gallery .slideFrame ul  {
  transition: left 1s cubic-bezier(0.85, 0.03, 0.15, 0.96) 0s;
  -webkit-transition: left 1s cubic-bezier(0.85, 0.03, 0.15, 0.96) 0;
}

目次に戻る

別の方法。

CSS Programming Advent Calendar 2012、どの記事も目からウロコの内容ばかりでとっても勉強になります!
今回やった方法以外にもいろんな方法があるんだなーと思ったので、ちょっと試してみました!
主に左右のボタンの切り替え方についてです:)。

z-indexで入れ替える

こちらは1026さんの記事で紹介されていた方法です。読んでてはっとしました:O。

CSS FreeThrow – a game, noJS, only CSS and HTML(2012.12.12)

z-indexの仕組み

クリックしたい要素以外を消してしまうんじゃなく、手前に持ってくるんですね。該当CSSは84行めから91行め。

けどそうすると、<label>は常に重なって表示されている状態になるので、<label>の背景画像として表示してたレースと、その中の<i>の背景画像として表示してた赤い矢印は、<label>以外の要素で表示するようにしました。<label>自体には何も指定せず、幅と高さだけ持たせます(右図参照)
こっちの方がHTMLソースがシンプルです:D!

  • HTML
  • CSS
  • PREVIEW
<div id="gallery">
  <input type="radio" id="switch1" name="gallery" checked="checked">
  <input type="radio" id="switch2" name="gallery">
  <input type="radio" id="switch3" name="gallery">
  <div class="slideFrame">
    <ul>
      <li><a href="#"><img src="img/gallery_visual1.jpg" alt="gallery_visual1" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual2.jpg" alt="gallery_visual2" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual3.jpg" alt="gallery_visual3" width="520" height="280"></a></li>
    </ul>
  </div>
  <ul class="nav">
    <li><label for="switch1"></label></li>
    <li><label for="switch2"></label></li>
    <li><label for="switch3"></label></li>
  </ul>
  <p class="prev">
    <i></i>
    <label for="switch1"></label>
    <label for="switch2"></label>
    <label for="switch3"></label>
  </p>
  <p class="next">
    <i></i>
    <label for="switch1"></label>
    <label for="switch2"></label>
    <label for="switch3"></label>
  </p>
<!-- /#gallery --></div>
/* gallery items */
#gallery ul li,
#gallery ul li label,
#gallery p,
#gallery p i {
  background: url(../img/gallery_item.png);
}

/* gallery list button */
#gallery ul.nav {
  width: 62px;
  margin: 0 auto;
  padding: 0;
}
#gallery ul.nav li {
  float: left;
  margin-right: 16px;
  background-position: -260px 0;
}
#gallery ul.nav li:last-child {
  margin-right: 0;
}
#gallery ul.nav li label {
  display: block;
  width: 10px;
  height: 10px;
  background-position: -260px -20px;
}
#gallery ul.nav li label:hover { opacity: 0; }

/* slider arrow button */
#gallery p,
#gallery p label {
  position: absolute;
  top: 0;
  margin: 0;
  width: 110px;
  height: 320px;
  cursor: pointer;
}
#gallery .prev {
  left: 0;
}
#gallery .next {
  right: 0;
  background-position: -110px 0;
}
#gallery p i {
  display: block;
  width: 26px;
  height: 26px;
  margin: 140px 0 0 40px;
  background-position: -230px 0;
}
#gallery p:hover i {
  margin: 140px 0 0 32px;
}
#gallery .next i {
  margin-left: 44px;
  background-position: -230px -30px;
}
#gallery .next:hover i {
  margin-left: 52px;
}

/* CSS Programming */
#gallery #switch1:checked ~ .slideFrame ul {
  left: 90px;
}
#gallery #switch2:checked ~ .slideFrame ul {
  left: -450px;
}
#gallery #switch3:checked ~ .slideFrame ul {
  left: -990px;
}
#gallery #switch1:checked ~ .nav li label[for="switch1"],
#gallery #switch2:checked ~ .nav li label[for="switch2"],
#gallery #switch3:checked ~ .nav li label[for="switch3"] {
  opacity: 0;
}
#gallery input {
  display: none;
}
#gallery #switch1:checked ~ .prev label[for="switch3"],
#gallery #switch2:checked ~ .prev label[for="switch1"],
#gallery #switch3:checked ~ .prev label[for="switch2"],
#gallery #switch1:checked ~ .next label[for="switch2"],
#gallery #switch2:checked ~ .next label[for="switch3"],
#gallery #switch3:checked ~ .next label[for="switch1"] {
  z-index: 1;
}

/* transition  */
#gallery ul.nav li label  {
  transition: all 0.5s ease 0s;
  -webkit-transition: all 0.5s ease 0;
}
#gallery i  {
  transition: all 0.3s ease 0s;
  -webkit-transition: all 0.3s ease 0;
}
#gallery .slideFrame ul  {
  transition: all 1s cubic-bezier(0.85, 0.03, 0.15, 0.96) 0s;
  -webkit-transition: all 1s cubic-bezier(0.85, 0.03, 0.15, 0.96) 0;
}

目次に戻る

pointer-events: none;

こちらはGeckoTangさんの記事で紹介されていました。このプロパティは初見だったので、CSSの奥深さを感じました。

13日目 : CSS Programming Advent Calendar 2012 - < /gecko >(2012.12.13)

pointer-eventsプロパティ
マウスイベントを操作する事ができます。pointer-events: none;とすると、その要素のリンククリックイベント動的な疑似クラスを無効にします。
ブラウザの対応状況(pointer-events)

要素を消してしまうんじゃなく、機能しないようにするんですね。

display: none;にしていたところを、このプロパティに書き換えました。該当CSSは90行め。
こっちの方が理に適ってます:)!

  • HTML
  • CSS
  • PREVIEW
<div id="gallery">
  <input type="radio" id="switch1" name="gallery" checked="checked">
  <input type="radio" id="switch2" name="gallery">
  <input type="radio" id="switch3" name="gallery">
  <div class="slideFrame">
    <ul>
      <li><a href="#"><img src="img/gallery_visual1.jpg" alt="gallery_visual1" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual2.jpg" alt="gallery_visual2" width="520" height="280"></a></li>
      <li><a href="#"><img src="img/gallery_visual3.jpg" alt="gallery_visual3" width="520" height="280"></a></li>
    </ul>
  </div>
  <ul class="nav">
    <li><label for="switch1"></label></li>
    <li><label for="switch2"></label></li>
    <li><label for="switch3"></label></li>
  </ul>
  <p class="prev">
    <i></i>
    <label for="switch1"></label>
    <label for="switch2"></label>
    <label for="switch3"></label>
  </p>
  <p class="next">
    <i></i>
    <label for="switch1"></label>
    <label for="switch2"></label>
    <label for="switch3"></label>
  </p>
<!-- /#gallery --></div>
/* gallery items */
#gallery ul li,
#gallery ul li label,
#gallery p,
#gallery p i {
  background: url(../img/gallery_item.png);
}

/* gallery list button */
#gallery ul.nav {
  width: 62px;
  margin: 0 auto;
  padding: 0;
}
#gallery ul.nav li {
  float: left;
  margin-right: 16px;
  background-position: -260px 0;
}
#gallery ul.nav li:last-child {
  margin-right: 0;
}
#gallery ul.nav li label {
  display: block;
  width: 10px;
  height: 10px;
  background-position: -260px -20px;
}
#gallery ul.nav li label:hover { opacity: 0; }

/* slider arrow button */
#gallery p,
#gallery p label {
  position: absolute;
  top: 0;
  margin: 0;
  width: 110px;
  height: 320px;
  cursor: pointer;
}
#gallery .prev {
  left: 0;
}
#gallery .next {
  right: 0;
  background-position: -110px 0;
}
#gallery p i {
  display: block;
  width: 26px;
  height: 26px;
  margin: 140px 0 0 40px;
  background-position: -230px 0;
}
#gallery p:hover i {
  margin: 140px 0 0 32px;
}
#gallery .next i {
  margin-left: 44px;
  background-position: -230px -30px;
}
#gallery .next:hover i {
  margin-left: 52px;
}

/* CSS Programming */
#gallery #switch1:checked ~ .slideFrame ul {
  left: 90px;
}
#gallery #switch2:checked ~ .slideFrame ul {
  left: -450px;
}
#gallery #switch3:checked ~ .slideFrame ul {
  left: -990px;
}
#gallery #switch1:checked ~ .nav li label[for="switch1"],
#gallery #switch2:checked ~ .nav li label[for="switch2"],
#gallery #switch3:checked ~ .nav li label[for="switch3"] {
  opacity: 0;
}
#gallery input {
  display: none;
}
#gallery #switch1:checked ~ .prev label:not([for="switch3"]),
#gallery #switch2:checked ~ .prev label:not([for="switch1"]),
#gallery #switch3:checked ~ .prev label:not([for="switch2"]),
#gallery #switch1:checked ~ .next label:not([for="switch2"]),
#gallery #switch2:checked ~ .next label:not([for="switch3"]),
#gallery #switch3:checked ~ .next label:not([for="switch1"]) {
  pointer-events: none;
}

/* transition  */
#gallery ul.nav li label  {
  transition: all 0.5s ease 0s;
  -webkit-transition: all 0.5s ease 0;
}
#gallery i  {
  transition: all 0.3s ease 0s;
  -webkit-transition: all 0.3s ease 0;
}
#gallery .slideFrame ul  {
  transition: all 1s cubic-bezier(0.85, 0.03, 0.15, 0.96) 0s;
  -webkit-transition: all 1s cubic-bezier(0.85, 0.03, 0.15, 0.96) 0;
}

目次に戻る

:target

最後にもう一個。
Firefoxだと、同じ<label>連続でクリックすると暫くチェックできなくなっちゃうのが、ずっと気になってたんですよね…(※クリックする位置を変えれば連続クリックできるけど…)
解決方法が分からなかったので…、<input>じゃなくて、<a>を使って切り替える方法に変えてみます!
まずはその際の要「:target疑似クラス」について。

:target疑似クラス
id属性で指定した要素が、リンク(?)されてる時に、スタイルを適用します。
例えば、#switch2:targetと指定した時には、URLの末尾が「/sample.html#switch2」とかになってる場合に、<div id="switch2">にスタイルが適用されます。

この:target<a>を使ってスライドさせます。とは言っても基本的な仕組みは<input>のものと同じです。
まずは.slideFrameの上に並べてた<input>を、ターゲットとなるid属性の付いた要素に変えます。

<input type="radio" id="switch1" name="gallery" checked="checked">
<input type="radio" id="switch2" name="gallery">
<input type="radio" id="switch3" name="gallery">
	⇓
<div id="switch1" class="switch"></div>
<div id="switch2" class="switch"></div>
<div id="switch3" class="switch"></div>

チョボのところと、左右のボタンの<label><a>に変えて、href属性でid属性の付いた要素へリンクさせるようにします。

<label for="switch1"></label>
<label for="switch2"></label>
<label for="switch3"></label>
	⇓
<a href="#switch1"></a>
<a href="#switch2"></a>
<a href="#switch3"></a>

CSSもHTMLに倣って、下記のようにlabelfor:checkedだったところを→ahref:targetに書き換えます。

<div id="gallery">
  <div id="switch1" class="switch"></div>
  <div id="switch2" class="switch"></div>
  <div id="switch3" class="switch"></div>
  <div class="slideFrame">
    <ul>
      <li><img src="img/gallery_visual1.jpg" alt="gallery_visual1" width="520" height="280"></li>
      <li><img src="img/gallery_visual2.jpg" alt="gallery_visual2" width="520" height="280"></li>
      <li><img src="img/gallery_visual3.jpg" alt="gallery_visual3" width="520" height="280"></li>
    </ul>
  </div>
  <ul class="nav">
    <li><a href="#switch1"></a></li>
    <li><a href="#switch2"></a></li>
    <li><a href="#switch3"></a></li>
  </ul>
  <p class="prev">
    <i></i>
    <a href="#switch1"></a>
    <a href="#switch2"></a>
    <a href="#switch3"></a>
  </p>
  <p class="next">
    <i></i>
    <a href="#switch1"></a>
    <a href="#switch2"></a>
    <a href="#switch3"></a>
  </p>
<!-- /#gallery --></div>
/* gallery items */
#gallery ul li,
#gallery ul li a,
#gallery p,
#gallery p i {
  background: url(../img/gallery_item.png);
}

/* gallery list button */
#gallery ul.nav {
  width: 62px;
  margin: 0 auto;
  padding: 0;
}
#gallery ul.nav li {
  float: left;
  margin-right: 16px;
  background-position: -260px 0;
}
#gallery ul.nav li:last-child {
  margin-right: 0;
}
#gallery ul.nav li a {
  display: block;
  width: 10px;
  height: 10px;
  background-position: -260px -20px;
}
#gallery ul.nav li a:hover { opacity: 0; }

/* slider arrow button */
#gallery p,
#gallery p a {
  position: absolute;
  top: 0;
  margin: 0;
  width: 110px;
  height: 320px;
  cursor: pointer;
}
#gallery .prev {
  left: 0;
}
#gallery .next {
  right: 0;
  background-position: -110px 0;
}
#gallery p i {
  display: block;
  width: 26px;
  height: 26px;
  margin: 140px 0 0 40px;
  background-position: -230px 0;
}
#gallery p:hover i {
  margin: 140px 0 0 32px;
}
#gallery .next i {
  margin-left: 44px;
  background-position: -230px -30px;
}
#gallery .next:hover i {
  margin-left: 52px;
}

/* CSS Programming */
#gallery #switch1:target ~ .slideFrame ul {
  left: 90px;
}
#gallery #switch2:target ~ .slideFrame ul {
  left: -450px;
}
#gallery #switch3:target ~ .slideFrame ul {
  left: -990px;
}
#gallery #switch1:target ~ .nav li a[href="#switch1"],
#gallery #switch2:target ~ .nav li a[href="#switch2"],
#gallery #switch3:target ~ .nav li a[href="#switch3"] {
  opacity: 0;
}
#gallery .switch {
  display: none;
}
#gallery #switch1:target ~ .prev a:not([href="#switch3"]),
#gallery #switch2:target ~ .prev a:not([href="#switch1"]),
#gallery #switch3:target ~ .prev a:not([href="#switch2"]),
#gallery #switch1:target ~ .next a:not([href="#switch2"]),
#gallery #switch2:target ~ .next a:not([href="#switch3"]),
#gallery #switch3:target ~ .next a:not([href="#switch1"]) {
  pointer-events: none;
}

/* transition  */
#gallery ul.nav li a  {
  transition: all 0.5s ease 0s;
  -webkit-transition: all 0.5s ease 0;
}
#gallery i  {
  transition: all 0.3s ease 0s;
  -webkit-transition: all 0.3s ease 0;
}
#gallery .slideFrame ul  {
  transition: left 1s cubic-bezier(0.85, 0.03, 0.15, 0.96) 0s;
  -webkit-transition: left 1s cubic-bezier(0.85, 0.03, 0.15, 0.96) 0;
}

連続でクリックできるようになりました:)。
scrollTopもそこへ移動しちゃうんじゃないかって懸念してたんですが、移動しなかったです:D!よかった。けど、ハッシュで履歴が残っちゃうので、ブラウザの戻るボタンする度にスライドします:(。(スライドショーでこれは面倒な事だけれど、何か別のページものとかだったら便利かもですね。)

できあがり!

Lopan cafeのサイトに設置したらできあがり:)。

JavaScriptのにもイージングを付けたものを用意したので、見比べてみてください(イージングはeaseInOutExpoです:)

スライドショーのeasingをeaseInOutExpoにした | カフェ&ベーカリー「Lopan cafe」


以下からサンプルをダウンロードできますX)。:checkedで作ったタイプと:targetで作ったタイプが入ってます。

:checked擬似クラスを使ったタイプと、:target擬似クラスを使ったタイプのサンプル

目次に戻る

あとがき

ちょっとCSS Programmingになってるかどうか不安ですが、一応Pure CSSなので。
他の方々が作ったものと比べると俄然物足りないかと思いますが、一応Pure CSSなので…XO。

今までCSS3は、使ってもborder-radiuslinear-gradientくらいだったんですが、CSS Programmingを知っていろんな凄コードを見てるうちに「~」を知って、「<label>:checkedの使い方」を知って、そこから一気に面白くなりました。状態を変化させて、それを別の要素にも反映できるようになればこっちのもんですよね!
今度はもっと突っ込んだもの作ってみたいです:D。

以上、最後まで読んで頂きありがとうございました!CSS Programmingに興味を持って頂けたら幸いです。

明日(23日目)は、tech.kayac.com Advent Calendar 2012でみごとっぱいを動かしてくれたdamele0nさんです!
よろしくお願いします!

  • このエントリーをはてなブックマークに追加
  • ツイート

Comment & Pingback

10 Comments! for CSSだけでスライドショーはつくれるよ。

  1. アシベ

    こんにちは、ネット上で人気のカービィカフェのサイトを覗いてみるとGoods紹介の箇所でスライドショー形式で画像がスクロール可能な箇所がいくつかあったので、これとてもいいなぁと思い探していたところlopanさんのこの記事を見つけました。

    試しにDLしてみてなんで動いているのかを本記事と照らし合わせながら試しています。

    そこでCSSコード内の最後にレスポンシブ用の箇所をみかけまして(残念ながらコードは記述されてませんでしたが・・・)、
    最適化できれば利用できる場面がかなりありそうだと思いました。

    これからもがんばってください!!

    ※個人的にローディング画面のうさぎがすごくかわいくて好みです。ローディング作成の記事があるといいなぁと

    Reply

    • _watercolor

      > アシベさん
      こんにちは、コメントありがとうございます!
      ですねー、レスポンシブできたらいいですよねーX)。
      (サンプルの最後のところは、initializrの名残なのです…。)
      今度はレスポンシブの記事とローディングの記事、書いてみようと思います!
      がんばりますー!

      Reply

  2. kunikane

    うまく設置できました。ありがとうございます!!
    しかしながらスライドのイメージを4枚目以降も増やしたい為
    色々試してみましたがうまくいきません。
    ヒントをいただけませんか???

    Reply

    • _watercolor

      > kunikaneさん
      コメントありがとうございます!
      3枚スライドショーに4枚めを増設したいとのこと、以下にちょこっと解説しますねー;D。

      まずはHTMLの、ラジオボタンとチョボと矢印を、それぞれひとつずつ追加します。
      あとはCSSを修正します。修正するポイントは以下の4か所です:)。

      1. イメージが4枚横並びになるように、.slideFrameの中の<ul>の横幅を広げる。

      2. チョボが4つ横に並ぶように、.navの中の<ul>の横幅を広げる。

      3. 4つめがチェックされた時の、.slideFrameの中の<ul>の位置を追加する。

      4. <label>の切り替えに、4つめがチェックされた時の状態を追加する。

      ううむ、けっこう面倒臭いですけれど…、以下にサンプルを作ってみましたのでご参考までにどうぞ!
      詳しくはCSSファイルの中のコメントを見てみてくださいませー。

      Reply

  3. jude

    自動スライドジョーとラジオボタンの併用で自動スライドが動いたら、動いたスライドに合わせて、ラジオボタンがチェックされることができますか。さらに自動スライドがスライドしたら、対応のラジオボタンの色も変わることができますでしょうか、ご教授よろしくお願いします。

    Reply

    • _watercolor

      > judeさん
      コメントありがとうございますー!

      さっそくご質問の内容ですが、
      CSSだけで作るスライドショーで「自動」にスライドさせるには、animationプロパティを使う方法があります。
      ※詳しくは動くCSSのためのメモという記事の「6秒おきに切り替わる」の項をご参照くださいませー;D。
      けれど、これはラジオボタンを使って動かしているわけではなくて、画像を順番にスライドするように登録して、その通りに動かしているだけなんですよね…。

      ラジオボタンを使って自動でスライドさせるためには、「動的」にラジオボタンをチェックしなくちゃいけないです。そういう場合には、CSSだけじゃできなくて、JavaScriptを使わなきゃいけないです…。

      試しにJavaScriptを使って動的にラジオボタンをチェックして、自動でスライドするサンプルを作ってみましたX)!
      ご参考までにどうぞー!

      ではでは、今後ともLopan.jpをよろしくです;)!

      Reply

  4. スズキ

    cssのみで背景画像をスクロールする上記の方法を、コピペして試したのですが、うまくいきません。
    コピペしたので、何が原因かわからないので教えて下さい。
    一応、記述した画像やhtmlファイルとcssファイルを送りたいのですが、確認して頂けると幸いです。

    Reply

    • _watercolor

      > スズキさん
      い…一年近くも返事が遅れてしまって申し訳ありません!
      すごく遅いと思いますが、、こちらにサンプルをご用意しましたので、ダウンロードしてみてください…!
      よろしくお願いいたしますーX)。

      Reply

      • アオイ

        横からですが、私もコピペで試したのですがうまくいかず悩んでいたので、サンプルでもう少し勉強します。
        ありがとうございます。

        Reply

        • _watercolor

          > アオイさん
          コメントありがとうございますー!
          記事中のコードは、説明してないところをハショっちゃってて、分かりづらくてすみません…X(。
          サンプルのコードもごちゃごちゃしてて読みにくいかもですが、、。
          サンプルの「slideshow.css」について補足しときます;D!
          1行め〜75行めまではスライドショー以外の部分のスタイルなので、スライドショーとは関係なくて、
          81行め以降がスライドショーのためのスタイルになってます。
          そこから182行めくらいまでは、背景とかボタンとか装飾に関するスタイルで、
          184行め〜223行めくらいまでが、動きに関するスタイルになってます!
          どうぞよろしくですX)!

          Reply

コメントを残す

*がついている欄は必須項目です。