ギャラリー · ギャラリー
ネオン看板の夜景写真ギャラリー
黒に近い紺の地に、ネオン管のように光る見出しと、縦に詰めて並ぶ夜景写真のギャラリー。撮影地で絞り込めるボタンを付け、写真ごとに看板の色で縁を光らせる。光らせる場所を見出しと選択中の要素に絞り、写真を主役に保つ。
このブラウザー内に保存します。別の端末との同期はなく、サイトデータを消すと保存も消えます。
印刷時は見本を静止画にし、プロンプトと解説を出力します。PDF保存はブラウザーの印刷画面から選べます。
Vibehaus · デザイン資料
https://vibe.itlibra.com/design/neon-night-gallery/
完全無料・著作権フリー(CC0)· 料金¥0 · 商用利用・改変自由
プレビュー
指定幅で実際に組み替えて表示します。表示領域より広い場合は、この枠の中で横へスクロールできます。
AIへの指示文
ネオン看板を撮った夜景写真の、ギャラリーページを作ってください。 要件: - 地は #0a0a12、写真を載せる面は #12121d。文字は #eceaf6、補助の文字は #8e8aa6。 - 光の色はピンク #ff3d9a・水色 #22e4ff・橙 #ffb547・紫 #b36bff の4色。 - 見出し「NIGHT SIGNS」はネオン管の文字にする。text-shadow を4段重ね(白の芯と、ピンクの光を広さ違いで3つ)。 - 点滅はさせない。4秒かけて明るさがわずかに揺れるだけの動きに留め、prefers-reduced-motion では止める。 - 見出しの下に、撮影方針を1文。右側に等幅の文字で写真の枚数(絞り込みに合わせて変わる。aria-live="polite")。 - 「すべて・新宿・大阪・香港」の絞り込みボタン。aria-pressed で選択中を示し、選択中だけ水色の光る枠にする。 - 写真は columns で3列に並べ、縦横比の違う写真を列の中で縦に詰める。break-inside: avoid。 - 写真の縁は、ホバーしたときだけその写真の看板の色で光る。普段は暗い枠線。 - 写真の下に、撮影場所と時刻(等幅)を1行で。 - 写真がまだ無い段階では、暗い路地に色の塊と縦長の看板の光を CSS で描いて仮置きする。 - 本文の字間は 0、行間は 1.8。
バリエーション
大きく1枚を見せる版
写真をクリックすると画面いっぱいに拡大表示する。背景は #0a0a12 の90%不透明、 Esc と閉じるボタンで戻れるようにし、開いている間は背後のスクロールを止める。
昼の街版
地を #f4f2ee の明るい灰色に、見出しの光を消して太い黒の文字にする。 写真の縁の光もやめ、ホバーで写真を少し拡大するだけにする。
このプレビューのコード
HTML・CSS・JavaScriptの1ファイルです。外部依存・広告・解析コードはありません。CSSで描く6作品を3地域で絞り込む見本です。実件数と解除を確認できます。実際の写真・撮影記録・外部取得・送信・保存は含みません。演出は停止できます。
コードを表示
<!doctype html>
<!-- Vibehaus · CC0 · 架空の表示・操作見本。外部素材・送信・永続保存なし。 -->
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex" />
<title>ネオン看板の夜景写真ギャラリー — Vibehaus プレビュー</title>
<style>
:root {
--bg: #0a0a12;
--panel: #12121d;
--text: #eceaf6;
--muted: #8e8aa6;
--pink: #ff3d9a;
--cyan: #22e4ff;
--amber: #ffb547;
--gothic: "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic", "Meiryo", sans-serif;
--mono: "JetBrains Mono", Menlo, Consolas, "Hiragino Sans", "Yu Gothic", monospace;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: var(--gothic);
line-height: 1.8;
letter-spacing: 0;
color: var(--text);
background: var(--bg);
}
.wrap {
max-width: 78rem;
margin: 0 auto;
padding: clamp(2rem, 5vw, 4rem) clamp(1rem, 4vw, 2.5rem) 4rem;
}
/* ---- 見出し: ネオン管の文字。光は text-shadow を重ねるだけ ---- */
header {
display: flex;
flex-wrap: wrap;
align-items: end;
justify-content: space-between;
gap: 1.5rem;
margin-bottom: 2rem;
}
.title {
margin: 0;
font-size: clamp(2.2rem, 6vw, 4rem);
font-weight: 800;
line-height: 1.3;
color: #ffe6f3;
text-shadow:
0 0 4px #fff,
0 0 12px var(--pink),
0 0 28px var(--pink),
0 0 56px rgb(255 61 154 / 0.6);
/* 点滅はさせない。4秒かけてわずかに明るさが揺れるだけ */
animation: hum 4s ease-in-out infinite alternate;
}
@keyframes hum {
from { opacity: 1; }
to { opacity: 0.88; }
}
.sub {
margin: 0.4rem 0 0;
color: var(--muted);
font-size: 0.92rem;
}
.count {
font-family: var(--mono);
font-size: 0.8rem;
letter-spacing: 0.12em;
color: var(--cyan);
}
/* ---- 絞り込み ---- */
.filters {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin: 0 0 1.75rem;
padding: 0;
list-style: none;
}
.filters button {
padding: 0.45rem 1rem;
border: 1px solid #2c2a40;
border-radius: 999px;
background: transparent;
color: var(--muted);
font: inherit;
font-size: 0.85rem;
cursor: pointer;
transition: color 0.2s, border-color 0.2s, box-shadow 0.2s;
}
.filters button[aria-pressed="true"] {
color: var(--text);
border-color: var(--cyan);
box-shadow: 0 0 0 1px var(--cyan), 0 0 16px -2px var(--cyan);
}
.filters button:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }
/* ---- 写真の並び: 列の中で縦に詰める ---- */
.grid {
columns: 3 18rem;
column-gap: 1rem;
}
.shot {
break-inside: avoid;
margin: 0 0 1rem;
border-radius: 10px;
overflow: hidden;
background: var(--panel);
border: 1px solid #1f1d30;
transition: border-color 0.25s, box-shadow 0.25s, transform 0.25s;
}
.shot:hover {
border-color: var(--glow);
box-shadow: 0 0 0 1px var(--glow), 0 12px 40px -12px var(--glow);
transform: translateY(-2px);
}
.shot[hidden] { display: none; }
/* 写真の代わりに、夜の路地と看板を色の塊で描く。実案件ではここを <img> に差し替える */
.photo {
position: relative;
aspect-ratio: var(--ratio, 4 / 5);
background:
radial-gradient(18% 10% at var(--x1, 30%) var(--y1, 30%), var(--c1), transparent 70%),
radial-gradient(14% 22% at var(--x2, 70%) var(--y2, 45%), var(--c2), transparent 70%),
radial-gradient(40% 20% at 50% 100%, rgb(255 255 255 / 0.08), transparent 70%),
linear-gradient(180deg, #05050a 0%, #141427 60%, #0b0b14 100%);
}
/* 看板の縦長の光。濡れた路面への映り込みも添える */
.photo::before,
.photo::after {
content: "";
position: absolute;
left: var(--sx, 22%);
width: 9%;
border-radius: 3px;
background: var(--c1);
box-shadow: 0 0 18px 2px var(--c1);
}
.photo::before { top: 18%; height: 34%; }
.photo::after { bottom: 4%; height: 14%; opacity: 0.25; filter: blur(3px); }
figcaption {
display: flex;
justify-content: space-between;
gap: 1rem;
padding: 0.8rem 1rem;
font-size: 0.85rem;
}
figcaption span {
font-family: var(--mono);
font-size: 0.72rem;
letter-spacing: 0.08em;
color: var(--muted);
white-space: nowrap;
}
.p1 { --c1: #ff3d9a; --c2: #22e4ff; --glow: #ff3d9a; --ratio: 4 / 5; }
.p2 { --c1: #22e4ff; --c2: #ffb547; --glow: #22e4ff; --ratio: 1 / 1; --sx: 64%; }
.p3 { --c1: #ffb547; --c2: #ff3d9a; --glow: #ffb547; --ratio: 3 / 4; --x1: 70%; }
.p4 { --c1: #b36bff; --c2: #22e4ff; --glow: #b36bff; --ratio: 4 / 3; --sx: 40%; }
.p5 { --c1: #ff3d9a; --c2: #ffb547; --glow: #ff3d9a; --ratio: 2 / 3; --sx: 70%; }
.p6 { --c1: #22e4ff; --c2: #b36bff; --glow: #22e4ff; --ratio: 4 / 5; --x2: 25%; }
@media (prefers-reduced-motion: reduce) {
.title { animation: none; }
.shot, .filters button { transition: none; }
.shot:hover { transform: none; }
}
[hidden]{display:none!important}
a,button,input,summary{min-width:44px;min-height:44px}
a{touch-action:manipulation}
button{cursor:pointer}
button:disabled{cursor:default}
a:focus-visible,button:focus-visible,input:focus-visible{outline:3px solid currentColor;outline-offset:4px}
nav a{display:inline-flex;align-items:center;justify-content:center}
nav{flex-wrap:wrap}
header.bar{flex-wrap:wrap;gap:1rem}
input{max-width:100%}
.demo-notes{position:relative;z-index:10;box-sizing:border-box;max-width:1080px;width:calc(100% - 2rem);margin:2rem auto;padding:clamp(1rem,3vw,2rem);background:#0a0a12;color:#eceaf6;border:1px solid currentColor;text-align:left;font-family:"Hiragino Sans","Yu Gothic",Meiryo,sans-serif;font-size:13px;line-height:1.8;letter-spacing:0;overflow-wrap:anywhere}
.demo-notes h2{font-size:18px;line-height:1.5;margin:0 0 .75rem}
.demo-notes h3{font-size:15px;line-height:1.5;margin:0 0 .4rem}
.demo-notes p{font:inherit;color:inherit;opacity:1;margin:0 0 1rem;max-width:none;letter-spacing:0}
.demo-notes section{margin-top:1.25rem;scroll-margin-top:1rem}
.demo-notes button{font:inherit;color:inherit;background:transparent;border:1px solid currentColor;padding:.4rem .75rem}
.demo-notes a{color:inherit}
.demo-notes .demo-motion{margin-bottom:1rem}
.demo-notes section:focus{outline:3px solid currentColor;outline-offset:4px}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}
}
.shot[hidden]{display:none!important}
.filters{flex-wrap:wrap}
html[data-demo-paused] *,html[data-demo-paused] *::before,html[data-demo-paused] *::after{animation-play-state:paused!important}
html[data-demo-paused] .ticker p{animation:none!important;padding-left:8px;white-space:normal}
</style>
<noscript><style>*,*::before,*::after{animation:none!important}.ticker p{padding-left:8px;white-space:normal}</style></noscript>
</head>
<body>
<div class="wrap">
<header>
<div>
<h1 class="title">NIGHT SIGNS</h1>
<p class="sub">閉店後も灯り続ける看板を、雨の夜にだけ撮っています。</p>
</div>
<p class="count" aria-live="polite"><span id="n">6</span> PHOTOS</p>
</header>
<ul class="filters" aria-label="撮影地で絞り込む">
<li><button type="button" data-js-control disabled data-f="all" aria-pressed="true">すべて</button></li>
<li><button type="button" data-js-control disabled data-f="shinjuku" aria-pressed="false">新宿</button></li>
<li><button type="button" data-js-control disabled data-f="osaka" aria-pressed="false">大阪</button></li>
<li><button type="button" data-js-control disabled data-f="hongkong" aria-pressed="false">香港</button></li>
</ul>
<div class="grid">
<figure class="shot p1" data-area="shinjuku">
<div class="photo" role="img" aria-label="ピンクの縦看板が濡れた路面に映る路地"></div>
<figcaption>思い出横丁の奥 <span>23:48</span></figcaption>
</figure>
<figure class="shot p2" data-area="osaka">
<div class="photo" role="img" aria-label="水色の看板と橙色の提灯が並ぶ商店街"></div>
<figcaption>裏なんばの角 <span>01:12</span></figcaption>
</figure>
<figure class="shot p3" data-area="hongkong">
<div class="photo" role="img" aria-label="橙色の看板が張り出す雨の大通り"></div>
<figcaption>油麻地の交差点 <span>22:05</span></figcaption>
</figure>
<figure class="shot p4" data-area="shinjuku">
<div class="photo" role="img" aria-label="紫の光が差し込む高架下"></div>
<figcaption>大ガード下 <span>00:31</span></figcaption>
</figure>
<figure class="shot p5" data-area="hongkong">
<div class="photo" role="img" aria-label="ピンクと橙の看板が重なる細い坂道"></div>
<figcaption>廟街の坂 <span>02:40</span></figcaption>
</figure>
<figure class="shot p6" data-area="osaka">
<div class="photo" role="img" aria-label="水色の看板が川面に映る夜の橋"></div>
<figcaption>道頓堀の橋 <span>23:59</span></figcaption>
</figure>
</div>
</div>
<aside class="demo-notes" aria-label="この見本について">
<h2>この見本について</h2>
<p>CSSで描く架空の作品集です。写真の撮影実績や画像ファイルは含みません。作品リンクは構成の説明へ移動し、投稿・アップロード・保存は行いません。配布HTMLはCC0・利用料¥0。外部素材やライブラリの取得は不要です。</p>
<div class="demo-motion">
<button type="button" data-demo-motion data-js-control disabled aria-pressed="false">演出を止める</button>
</div>
<noscript>
<p>JavaScriptなしでも初期表示と説明リンクを利用できます。絞り込み・入力確認・演出の切替は無効です。</p>
</noscript>
</aside><script>
const filters=[...document.querySelectorAll('[data-f]')],tiles=[...document.querySelectorAll('.shot')];filters.forEach(button=>button.addEventListener('click',()=>{filters.forEach(b=>b.setAttribute('aria-pressed',String(b===button)));let count=0;tiles.forEach(tile=>{tile.hidden=button.dataset.f!=='all'&&tile.dataset.area!==button.dataset.f;if(!tile.hidden)count++});document.querySelector('#n').textContent=count}));const motion=matchMedia('(prefers-reduced-motion: reduce)'),toggle=document.querySelector('[data-demo-motion]');let paused=false;function syncMotion(){const stop=paused||motion.matches;document.documentElement.toggleAttribute('data-demo-paused',stop);toggle.setAttribute('aria-pressed',String(stop));toggle.disabled=motion.matches;toggle.textContent=motion.matches?'動きを減らす設定で停止中':stop?'演出を再開':'演出を止める'}toggle.addEventListener('click',()=>{paused=!paused;syncMotion()});motion.addEventListener('change',syncMotion);
document.querySelectorAll('[data-js-control]').forEach(el=>el.disabled=false);syncMotion();
</script>
</body>
</html>
2026年10月14日、Chromiumで320・390・768・1280pxの描画とキーボードのフォーカス表示を確認しました。他のブラウザは未確認です。利用先のブラウザと実データでも確認してください。
概要
ネオン看板は、夜の街でいちばん強い光です。そのネオンを撮った写真を並べるギャラリーで、画面まで光らせると写真と画面が同じ強さで光り合い、どちらも見えなくなります。このデザインは、光る場所を見出しと、選んでいるものだけに絞っています。
光らせる場所を3つに絞る
ネオン風のデザインは、光の効果を足すほどそれらしく見えます。ただしギャラリーでは、主役は写真の中の光です。
崩れる形すべての枠と文字を光らせる
画面全体が明るくなり、写真の中の看板が目立たなくなります。どこを押せるのかも光では分からなくなります。
効く形見出し・選択中・ホバー中だけ光らせる
光がいま注目している場所の合図になります。暗い地に写真だけが浮かび、看板の色が引き立ちます。
写真の縁が光る色は、その写真に写っている看板の色に合わせています。ピンクの看板の写真はピンクに、水色の看板は水色に。ホバーした写真の色がそのまま画面に広がるので、1枚ずつ見比べる楽しさが生まれます。
動きは、ゆっくり揺れるだけ
本物のネオン管は、古くなるとちらつきます。その再現は魅力的ですが、速い点滅は光に敏感な人に発作を引き起こすおそれがあります。
見出しは4秒かけて明るさが1割揺れるだけ。これでも、通電しているネオンの気配は十分に出ます。
仕上げの判断軸
写真が増えてきたら、絞り込みの項目を増やす前に並び順を見直してください。columns は上から下へ順に詰めるので、新しい写真を先頭に置くと左の列にばかり集まります。
見本で試せる範囲
CSSで描く6作品を3地域で絞り込む見本です。実件数と解除を確認できます。実際の写真・撮影記録・外部取得・送信・保存は含みません。演出は停止できます。 作品・記事・サービス名や数値は表示のための設定です。リンク先には、このHTMLに含まれる範囲と利用先で接続する処理を説明しています。配布HTMLはCC0・利用料¥0で、保存した1ファイルだけで表示できます。
ギャラリーの構成要素
使いどころ
- 写真家や映像作家のポートフォリオの作品一覧
- 夜の街・飲食店街・イベントの写真をまとめた特設ページ
- 音楽やゲームのビジュアル素材を並べるページ
- 撮影地や種類で絞り込みたい、枚数の多い写真集
このデザインの分類
背景と狙いどころ
よくある質問
ネオンの光を写真の上にも重ねたほうが雰囲気が出ませんか?
見出しをちらつかせるとネオンらしくなりませんか?
写真の並べ方に columns を使うのはなぜですか?
この画面を実装する
動くサンプルとコピペできるコードを、技術別にまとめています。
関連するデザイン
ベントーグリッドの写真ギャラリー
大小のタイルが噛み合うベントーグリッドで、作品の格を差でつける写真ギャラリー。主役を大きく、脇役を小さく——並べた瞬間に見る順番が決まるレイアウトです。
ポラロイド写真ボード風のギャラリー
コルクボードに押しピンとマスキングテープで留めたポラロイド写真コレクションを再構築したギャラリー。手書き風キャプション・微妙な傾き・付箋メモで「私的な記憶」を訴求する尖った設計。
ネオン発光のナイトライフ系ポートフォリオ
暗背景にホットピンクとシアンの発光色を重ねるネオン系ポートフォリオ。ナイトクラブ・音楽・ゲーム・メタバースの世界観を Web に持ち込む、夜の街の空気を持つ作品集。