イラストアルバムだけをご覧になりたい方は目次に★マークが付いている部分をタップしてください。
すぐにジャンプできますよ!

個人サイト制作:サイトマップへ戻る

JavaScriptでイラストアルバムを作成する

フェードアウト効果の草花写真

昨今のAI学習に伴う騒動は、多くの人に個人でWebサイトを持つ可能性について議論を呼び起こしました。
ただ、AI学習から逃げるためだけではなく、せっかくなら楽しいデザインを盛り込めると良いと思います。

このJavaScriptによる画像アルバムはイラストや画像化された小説などを綺麗に陳列できることに加えて、クローラーも避けやすいです。
JavaScriptを理解するのが難しいクローラーもいるので、多少なら検索除けの効果も期待できるということです。
でも見る人にとっては楽しいものですから、一石二鳥かもしれない。

説明は実際のイラストアルバムを見ながら

フェードアウト効果の草花写真

ここでは、実際のイラストアルバムをお見せしつつ、html・css・JavaScriptの順番でコードをお見せします。
同時にコードの解説も加えていきます。
イラストを並べると言ってもいろんな形があると思うんですよね。
1枚1枚掲示してギャラリー風にしても良いでしょう。
その一方で、こうやってアルバムを陳列すれば、多数の画像を省スペースに並べることができます。

では、そろそろ本題に移りますね。

★Kyabia様のイラストアルバム:vol.1

まずは完成品の提示です。
これはイラストレーターのKyabia様による画像をアルバム化したものです。

illustration of kyabia
illustration of kyabia
illustration of kyabia
illustration of kyabia
illustration of kyabia
illustration of kyabia
illustration of kyabia
illustration of kyabia
illustration of kyabia

「前のページ」と「次のページ」を押すと、アニメーションとともに画像が切り替わるようになっています。
アニメーションの見せ方はいろいろありますが、あまり凝ったものにしても煩わしさを感じさせてしまいます。
気付くか気付かないか程度に、さらりと動かす方が私は好きかな。

イラストアルバムを作るhtml

このHTML構造は画像をページ単位で切り替えるアルバムを作成するための土台です。
ボタンをタップすると、JavaScriptによって表示される画像が切り替わります。
そんなに難しいものではないので、ちょっとhtmlコードをご覧ください。

イラストアルバムを作るhtml


<div class="feinalbum-container" id="feinalbum3">
   <div class="feinalbum">
    <div class="feinalbum-page">
     <img src="/paint/フィーネa.jpg" alt="Image 3">
    </div>
    <div class="feinalbum-page">
     <img src="/paint/フィーネb.jpg" alt="Image 4">
    </div>
    <div class="feinalbum-page">
     <img src="/paint/フィーネc.jpg" alt="Image 4">
    </div>
   </div>
   <button class="feinalbum-prev">前のページ</button>
   <button class="feinalbum-next">次のページ</button>
</div>
    

このコードが何を意味しているのか、簡単にHTMLの説明をしてみます。

全体の構造
feinalbum-containerというクラス名がついた外枠の<div>がアルバム全体を包んでいます。
この外枠は、一つのアルバム全体をまとめる役割を持っています。
アルバムの内容
feinalbumというクラス名がついた<div>があり、その中に複数のfeinalbum-pageというクラス名がついた<div>があります。
feinalbum-pageには<img>タグが入っていて画像を表示します。
今回は3つの画像がそれぞれ異なるfeinalbum-pageに入っています。
ページ移動のボタン
feinalbum-prevとfeinalbum-nextというクラス名がついた<button>タグがあります。
それぞれ「前のページ」「次のページ」に移動するためのボタンです。
フェードアウト効果の草花写真

一つのアルバムに格納するイラスト数はどれくらいでしょうね?
感覚的なものも大きいですが、私としては多くても10枚くらいが適切かと思います。
それでも10冊のアルバムを並べれば、100枚のイラストを1つのWebページに展示できるのですよ。
そして個人サイトのページ数を10とするなら、合計で1000枚のイラストを、いとも簡単にAI除けしつつ展示できることになります。

手間を惜しまないのであれば、全ての画像にウォーターマークを付けてあげればさらに良いですね。

個人サイトは閲覧数が少ない問題

これはSEOとも深く関わってくるので、すぐに回答が出るようなものではないでしょう。
でも、次のような工夫をすることで、イラストを守りつつ検索エンジンに対処することも、可能かと思いますよ?

フェードアウト効果の草花写真

これらに加えて、相互リンクなどもやっていただければ。
ただ検索エンジンに引っかかっては困る二次創作もあるでしょうから、一概には言えませんよね。

★Kyabia様のイラストアルバム:vol.2

こちらもイラストレーターのKyabia様による画像をアルバム化したものです。

illustration of kyabia
illustration of kyabia
illustration of kyabia
illustration of kyabia
illustration of kyabia

他に画像の展示はどんなアイデアがありますかね?
マジでリアルの個展会場のような室内を演出するという手もあり、それはCSSで実現可能です。
ただ、レスポンシブデザインにする必要があるので、横への広がりに工夫が必要かと。
同じイラストギャラリーでも、見せ方がひと味違うと、それだけでも注目を集めることができるでしょう。

イラストアルバムを作るcss

フェードアウト効果の草花写真

このCSSが既に長い…いきなりチャレンジするというより、個人のポートフォリオサイトや簡単なブログを作ることから始めてみると良いですよね。
「ハンズオンプロジェクト」などと呼ばれるのですが、実際にコーディングしてみることが最も効果的です。
簡単な文字装飾から始め、徐々に難易度を上げていくと挫折を防げます。
デザインの模写も素晴らしい練習方法です。
好きなサイトやインスピレーションを得たデザインを自分で再現してみるのです。
この過程で、実際のWeb制作で使われているテクニックを学ぶことができます。

って…あれ?
これはイラスト上達への道と似たような側面があるかも…

とりあえず、このアルバムのCSSを見てみましょうか。

イラストアルバムを作るalbum.css


.feinalbum-container {
 margin: 20px;
 text-align: center;
}

.feinalbum {
 width: 100%;
 max-width: 600px;
 height: 0;
 padding-bottom: 75%;
 perspective: 1000px;
 position: relative;
 overflow: hidden;
 margin: auto;
 box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
 border: 1px solid #dcdcdc;
 border-radius: 5px;
 background-color: #f8f8f8;
}

.feinalbum-page {
 width: 100%;
 height: 100%;
 position: absolute;
 backface-visibility: hidden;
 transition: transform 0.8s ease-in-out, box-shadow 0.8s ease-in-out;
 display: flex;
 align-items: center;
 justify-content: center;
 transform-style: preserve-3d;
 background-color: #ffffff;
 border: 1px solid #e0e0e0;
 box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
 border-radius: 5px;
 transform-origin: center;
}

.feinalbum-page-hidden {
 transform: rotateY(-150deg) scale(0.98);
 box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}

.feinalbum-page img {
 width: 95%;
 height: auto;
 object-fit: contain;
}

button {
 margin: 10px;
 padding: 8px 12px;
 border: none;
 background-color: #7FDBB6;
 color: #4B3E3E;
 font-size: 14px;
 cursor: pointer;
 border-radius: 5px;
 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
 transition: background-color 0.3s, transform 0.3s;
}

button:hover {
 background-color: #65C9A9;
 transform: translateY(-2px);
}

button:active {
 background-color: #4CB38B;
 transform: translateY(0);
}

.feinalbum-hidden {
 display: none;
}
    

.feinalbumcontainer
このクラスはアルバム全体を包む外枠に適用されています。

margin: 20px
外側の余白を20ピクセルに設定し、要素にスペースを与えています。
textalign: center
内側の要素を中央に揃えています。

.feinalbum
アルバムの本体部分に適用されます。

フェードアウト効果の草花写真
perspective: 1000px
3D効果を付けるための視点の深さを設定します。
position: relative
要素の位置を相対的に配置します。
overflow: hidden
コンテナ外の内容を隠します。
margin: auto
中央揃えのために自動で余白を設定します。
boxshadow: 0 10px 20px rgba(0, 0, 0, 0.2)
軽い影を追加し、立体感を出します。
border: 1px solid #dcdcdc
境界線を追加し、アルバムの枠を作ります。
borderradius: 5px
角を少し丸めます。
backgroundcolor: #f8f8f8
アルバムの背景色をオフホワイトに設定します。

.feinalbumpage
各ページに適用されるクラスです。
まずはwidth 100%height 100%でページの幅と高さを設定します。

position: absolute
絶対配置し、親要素に対する位置を設定します。
backfacevisibility: hidden
3D回転時の背面表示を隠します。
transition: transform 0.8s easeinout, boxshadow 0.8s easeinout
ページの回転と影の変化にアニメーションを設定します。
display: flex、alignitems: center、justifycontent: center
画像を中央に配置します。
transformstyle: preserve3d
3D変換を保ちます。
backgroundcolor: #ffffff
ページの背景色を白に設定します。
border: 1px solid #e0e0e0
ページの境界線を追加します。
boxshadow: 0 4px 8px rgba(0, 0, 0, 0.1)
軽い影を追加し、立体感を出します。
borderradius: 5px
角を少し丸めます。
transformorigin: center
変換の中心を設定します。
フェードアウト効果の草花写真

.feinalbumpagehidden
このクラスはページが見えなくなるときに適用されます。

transform: rotateY(150deg) scale(0.98)
ページが150度回転し、わずかに縮小します。
boxshadow: 0 8px 16px rgba(0, 0, 0, 0.2)
深い影を追加します。

.feinalbumpage img
ページ内の画像に適用されるクラスです。

width: 95%
画像の幅をページの95%に設定します。
height: auto
画像の高さを自動調整します。
objectfit: contain
画像の比率を保ちつつページ内に収めます。

button
ページ移動ボタンに適用されるクラスです。

margin: 10px
ボタン外側の余白を設定します。
padding: 8px 12px
ボタン内側の余白を設定します。
border: none
ボタンの境界線をなくします。
backgroundcolor: #7FDBB6
ボタンの背景色を淡いグリーンに設定します。
color: #4B3E3E
ボタンのテキスト色をダークブラウンに設定します。
fontsize: 14px
フォントサイズを14ピクセルに設定します。
cursor: pointer
ポインタがホバー時に指アイコンに変わります。
borderradius: 5px
角を少し丸めます。
boxshadow: 0 4px 6px rgba(0, 0, 0, 0.1)
軽い影を追加します。
transition: backgroundcolor 0.3s, transform 0.3s
背景色と変形のアニメーションを設定します。

buttonhover
ボタンにマウスが乗ったときのスタイルを設定します。

backgroundcolor: #65C9A9
背景色を濃いグリーンに変更します。
transform: translateY(2px)
ボタンが少し浮き上がるように見せます。

buttonactive
ボタンがクリックされたときのスタイルを設定します。

backgroundcolor: #4CB38B
背景色をさらに濃いグリーンに変更します。
transform: translateY(0)
ボタンが元の位置に戻ります。

.feinalbumhidden
このクラスは表示されないページに適用されます。
display noneでページを非表示にします。

「perspective」プロパティ

フェードアウト効果の草花写真

3D効果を付けるために使われるCSSプロパティです。
このプロパティは、3D空間内の要素の視点の深さ、つまり「視覚的な距離」を設定します。
簡単に仕様を説明しましょうか。

用途
3D空間内での要素の深さや距離を設定します。
このプロパティを使うことで、3D変換(回転やスケーリングなど)がより現実的に見えるようになります。
単位
px(ピクセル)や、他の長さの単位が使えます。
例えば、1000pxや500pxなど。
適用対象
一般に親要素に適用され、子要素の3D変換に影響を与えます。

perspectiveの書き方


.container {
perspective: 1000px;
  }
    

この例では、containerクラスが持つ要素に3D効果を付けるための視点の深さを1000ピクセルに設定しています。
この視点の深さにより、要素が回転したときに奥行き感が強調されます。

イラストアルバムのperspective

フェードアウト効果の草花写真

前述のように「perspective: 1000px」というCSSプロパティは、3D効果を付けるために使われています。
この値は「視点の深さ」を設定していることも書きました。

1000pxという大きな数字にする理由は、視点の深さを広く取ることで、3D効果がより自然に見えるようにするためです。
視点の深さが大きいと、3D効果がやや控えめで、奥行き感が自然になります。
逆に、視点の深さを小さくすると、3D効果が強調され、オブジェクトが急激に遠近感を感じさせるようになります。

例えば、視点の深さを500pxに設定した場合、回転や移動がより極端に感じられ、ページの回転が強く見えるかも?
感じ方の違いかな…
とりあえず私は視点の深さを1000pxにすることが多いけど、これだと少し緩やかで自然な3D効果に見えるのです。

長いだけで難しくはないCSS
フェードアウト効果の草花写真

やたらと親子関係を作ったりすると難解になってきますが、1行1行でフォントやカラー、奥行きなどを順番に設定しているだけです。
英数字ばかりのプログラミングみたいな画面を見るとうんざりしちゃうかもしれないけど、一つ一つは単純なんですよ?

★御堂りく様のイラストアルバム:vol.1

こちらはイラストレーターの御堂りく様による画像をアルバム化したものです。

illustration of 御堂りく
illustration of 御堂りく
illustration of 御堂りく
illustration of 御堂りく

ここだな…どうしようかな…
JavaScriptですよ。
私も学生時代はさんざん悩んだからね。
今でも悩むことはありますが、多くは学生時代に自分が残したコードを使っているから、大幅な時間短縮ができているだけです。
このサイトのコードを持って行っても良いですよ?
御自身のサイトのディレクトリに合わせてコードを変更して頂ければ、よほど独特な環境でない限りは動作すると思います。

イラストアルバムを作るJavaScript

フェードアウト効果の草花写真

このコードはイラストアルバムのページを切り替える仕組みを作っています。
とてもシンプルに説明すると、こんな感じですよ。
まずはコードを書かず、日本語での説明チャレンジです。

アルバムの準備
  • 最初に表示するページは0番目、つまり一番最初のページです。
  • アルバムを見つけて、その中のページや「前へ」「次へ」ボタンも見つけます。
ボタンがクリックされたときの動作
  • 「前へ」ボタンをクリックしたら、1つ前のページを表示します。
  • 「次へ」ボタンをクリックしたら、1つ次のページを表示します。
ページの表示・非表示
  • もし選んだページの番号が範囲外だったら、何もしません。
  • 現在のページを「隠す」動作を始めて、ちょっと待ってから次のページを「見せる」動作をします。
  • ページ内の画像をちょうどいいサイズに調整して、中央に配置します。
初期設定
最初のページだけを見せて、他のページを隠しておきます。
ページ全体を設定
ページが読み込まれたときに、この仕組みを動かします。全てのアルバムに対して、この準備を行います。
フェードアウト効果の草花写真

つまり、このコードはユーザーが「前へ」や「次へ」ボタンをクリックしたときに、アルバムのページをスムーズに切り替えるための仕組みを作っているということになります。
では、実際のJavaScriptをご覧ください。

イラストアルバムを作るalbum.js


function setupFeinalbum(albumId) {
 let currentPage = 0;
 const album = document.getElementById(albumId);
 const pages = album.querySelectorAll('.feinalbum-page');
 const prevButton = album.querySelector('.feinalbum-prev');
 const nextButton = album.querySelector('.feinalbum-next');

 prevButton.addEventListener('click', () => {
  showPage(currentPage - 1);
 });

 nextButton.addEventListener('click', () => {
  showPage(currentPage + 1);
 });

 function showPage(index) {
  if (index < 0 || index >= pages.length) return;

  pages[currentPage].classList.add('feinalbum-page-hidden');

  setTimeout(() => {
   pages[currentPage].classList.add('feinalbum-hidden');
   currentPage = index;
   pages[currentPage].classList.remove('feinalbum-hidden');

   setTimeout(() => {
    pages[currentPage].classList.remove('feinalbum-page-hidden');
    adjustImageSize(pages[currentPage]);
   }, 50);
  }, 600);
 }

 function adjustImageSize(page) {
  const img = page.querySelector('img');
  img.style.width = '100%';
  img.style.height = '100%';
  img.style.objectFit = 'contain';
  img.style.objectPosition = 'center';
 }

 pages.forEach((page, index) => {
  if (index !== currentPage) {
   page.classList.add('feinalbum-page-hidden');
   page.classList.add('feinalbum-hidden');
  } else {
   page.classList.remove('feinalbum-hidden');
   adjustImageSize(page);
  }
 });

 showPage(0);
}

document.addEventListener('DOMContentLoaded', () => {
 const albumContainers = document.querySelectorAll('.feinalbum-container');
 albumContainers.forEach((container, index) => {
  setupFeinalbum(`feinalbum${index + 1}`);
 });
});
    
フェードアウト効果の草花写真

ざざーっと、コードを説明しましょうか。
1行ずつ説明文を付けたつもりですが、ループ処理の部分はかえって分かりにくいかも?

function setupFeinalbum(albumId) {
let currentPage = 0;
現在表示されているページを初期化します。最初は0ページ目(最初のページ)です。
const album = document.getElementById(albumId);
指定されたIDのアルバム要素を取得します。
const pages = album.querySelectorAll('.feinalbum-page');
アルバム内の全てのページ要素を取得します。
const prevButton = album.querySelector('.feinalbum-prev');
「前のページへ」ボタンを取得します。
const nextButton = album.querySelector('.feinalbum-next');
「次のページへ」ボタンを取得します。
prevButton.addEventListener('click', () => { showPage(currentPage - 1); });
で「前のページへ」ボタンがクリックされたときに、現在のページを1つ前にする関数を呼び出します。
nextButton.addEventListener('click', () => { showPage(currentPage + 1); });
で「次のページへ」ボタンがクリックされたときに、現在のページを1つ次にする関数を呼び出します。
function showPage(index) {
if (index < 0 || index >= pages.length) return;
ページのインデックスが範囲外の場合、何もしないで関数を終了します。
pages[currentPage].classList.add('feinalbum-page-hidden');
現在のページに隠すためのクラスを追加します。
setTimeout(() => {
アニメーションを遅らせて実行します。まず、600ミリ秒後に現在のページを完全に非表示にし、次のページを表示します。
pages[currentPage].classList.add('feinalbum-hidden');
現在のページを完全に隠します。
currentPage = index;
現在のページのインデックスを更新します。
pages[currentPage].classList.remove('feinalbum-hidden');
新しいページを表示します。
setTimeout(() => {
新しいページのアニメーションを開始します。50ミリ秒後に新しいページの隠すクラスを削除します。
adjustImageSize(pages[currentPage]);
画像のサイズを調整します。
function adjustImageSize(page) {
const img = page.querySelector('img');
ページ内の画像要素を取得します。
img.style.width = '100%';
画像のスタイルを設定し、widthを100%、heightを100%、objectFitをcontainに設定して画像がページ内に収まるようにします。
img.style.height = '100%';
heightを100%に設定します。
img.style.objectFit = 'contain';
objectFitをcontainに設定して画像がページ内に収まるようにします。
img.style.objectPosition = 'center';
objectPositionをcenterに設定して画像を中央に配置します。
pages.forEach((page, index) => {
if (index !== currentPage) {
もしそのページが現在のページでない場合(index !== currentPage)、そのページを隠すクラスを追加します。
page.classList.add('feinalbum-page-hidden');
そのページを隠すクラスを追加します。
page.classList.add('feinalbum-hidden');
そのページを完全に隠します。
} else {
現在のページの場合、そのページの隠すクラスを削除し、画像のサイズを調整します。
page.classList.remove('feinalbum-hidden');
そのページの隠すクラスを削除します。
adjustImageSize(page);
画像のサイズを調整します。
showPage(0);
最初のページを表示します。
document.addEventListener('DOMContentLoaded', () => {
ページが読み込まれたときに実行するコードを設定します。
const albumContainers = document.querySelectorAll('.feinalbum-container');
全てのアルバムコンテナを取得します。
albumContainers.forEach((container, index) => {
全てのアルバムコンテナに対してループを実行し、各アルバムのセットアップを行います。
setupFeinalbum(`feinalbum${index + 1}`);
各アルバムに対してセットアップを実行します。
html・css・JavaScriptは関係しあっている
フェードアウト効果の草花写真

ここまで紹介してきたhtml・css・JavaScriptは、クラスやIDという目印みたいなものを使って、相互に連携して動いています。
htmlのクラスやIDを見て、cssはデザインを行い、JavaScriptは動きをコントロールしている。
それらがエラーなく動作してこそ、イラストアルバムが綺麗に動作します。

特にCSSの部分を調整して頂ければ、見た目の印象を大きく変えることもできますよ。
ボタンの大きさを変えるとかね?

最後に、これらのイラストを譲ってくださったKyabia様、御堂りく様、本当にありがとうございました。
この場を借りて、御礼申し上げます。


サイトマップ

アナザーエデン関連ページ・サイトマップ

アナザーエデンの強敵戦やストーリーコンテンツのリスト、お勧めバッジなどを掲載したコーナーです。
期間限定のない普通のRPGですので、初心者でも安心して続けていけるゲームとなっています。
もっとも重要なグラスタについては、場所別に網羅した表があります。

個人サイトのホスティングとコンテンツ作成

個人でウェブサイトを作るにはどうすればいいか。
HTML・CSS・JavaScriptの書き方はもちろん、無料かつ広告なしでホームページを作る方法を掲載したコーナーです。
Webデザインやレイアウトについても書いてあります。

魚釣りなどアウトドアのエリア

ゲームとパソコンだけじゃなく、アウトドアも趣味なんです。
このコーナーでは魚釣りの記録とか、魚料理のレシピ、はたまたサイクリングなどなど。
アウトドアに関連するコンテンツが詰め込まれています。