<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Eternal</title>
<style>
body {
font-family: sans-serif;
background: #f5f5f5;
margin: 0;
padding: 0;
}
header {
background: #e60023;
color: white;
padding: 1em;
text-align: center;
font-size: 1.8em;
}
.controls {
padding: 1em;
background: #fff;
text-align: center;
}
.controls input, .controls button {
margin: 0.5em;
padding: 0.5em;
font-size: 1em;
}
.grid {
column-count: 4;
column-gap: 1em;
padding: 1em;
}
.pin {
background: white;
display: inline-block;
margin-bottom: 1em;
width: 100%;
box-sizing: border-box;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
overflow: hidden;
position: relative;
}
.pin img {
width: 100%;
cursor: pointer;
}
.description, .tags {
padding: 0.5em;
}
.favorite {
position: absolute;
top: 8px;
right: 8px;
font-size: 22px;
color: gray;
cursor: pointer;
user-select: none;
}
.favorite.active {
color: gold;
}
.likes {
font-size: 0.9em;
text-align: right;
padding: 0 0.5em 0.5em 0;
color: #888;
}
.tag {
display: inline-block;
background: #eee;
padding: 0.2em 0.5em;
border-radius: 5px;
margin: 0.2em;
cursor: pointer;
}
.tag:hover {
background: #ccc;
}
@media screen and (max-width: 1024px) {
.grid {
column-count: 3;
}
}
@media screen and (max-width: 768px) {
.grid {
column-count: 2;
}
}
@media screen and (max-width: 480px) {
.grid {
column-count: 1;
}
}
#modal {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.7);
display: none;
justify-content: center;
align-items: center;
z-index: 1000;
}
#modal img {
max-width: 90%;
max-height: 80vh;
border-radius: 10px;
}
</style>
</head>
<body>
<header>Pintorrest 完全版</header>
<div class="controls">
<input type="file" id="imageInput" accept="image/*">
<input type="text" id="descInput" placeholder="説明">
<input type="text" id="tagInput" placeholder="タグ(カンマ区切り)">
<button onclick="addPin()">投稿</button>
<br>
<input type="text" id="searchBox" placeholder="検索..." oninput="filterPins()">
</div>
<div class="grid" id="grid"></div>
<div id="modal" onclick="this.style.display='none'">
<img id="modalImg" src="">
</div>
<script>
let pins = JSON.parse(localStorage.getItem("pins") || "[]");
function renderPins() {
const grid = document.getElementById("grid");
grid.innerHTML = '';
pins.forEach((pin, index) => {
const pinElem = document.createElement("div");
pinElem.className = "pin";
pinElem.innerHTML = `
<span class="favorite ${pin.favorited ? 'active' : ''}" onclick="toggleFavorite(${index}, this)">★</span>
<img src="${pin.image}" onclick="showModal('${pin.image}')">
<div class="description">${pin.desc}</div>
<div class="tags">${pin.tags.map(tag => `<span class="tag" onclick="filterByTag('${tag}')">${tag}</span>`).join(' ')}</div>
<div class="likes">♥ ${pin.likes}</div>
`;
grid.appendChild(pinElem);
});
}
function addPin() {
const imageInput = document.getElementById("imageInput");
const desc = document.getElementById("descInput").value.trim();
const tags = document.getElementById("tagInput").value.split(',').map(t => t.trim()).filter(Boolean);
const file = imageInput.files[0];
if (!file || !desc) return alert("画像と説明を入力してください");
const reader = new FileReader();
reader.onload = function(e) {
pins.unshift({
image: e.target.result,
desc: desc,
tags: tags,
likes: 0,
favorited: false
});
savePins();
renderPins();
document.getElementById("descInput").value = '';
document.getElementById("tagInput").value = '';
document.getElementById("imageInput").value = '';
};
reader.readAsDataURL(file);
}
function showModal(src) {
document.getElementById("modalImg").src = src;
document.getElementById("modal").style.display = 'flex';
}
function toggleFavorite(index, elem) {
pins[index].favorited = !pins[index].favorited;
pins[index].likes += pins[index].favorited ? 1 : -1;
savePins();
renderPins();
}
function savePins() {
localStorage.setItem("pins", JSON.stringify(pins));
}
function filterPins() {
const keyword = document.getElementById("searchBox").value.toLowerCase();
document.querySelectorAll(".pin").forEach(pin => {
const text = pin.textContent.toLowerCase();
pin.style.display = text.includes(keyword) ? "inline-block" : "none";
});
}
function filterByTag(tag) {
document.getElementById("searchBox").value = tag;
filterPins();
}
renderPins();
</script>
</body>
</html>
カテゴリー: HTML
RSSreader.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>超RSSニュースリーダー</title>
<style>
body {
font-family: "Segoe UI", sans-serif;
background: #f4f4f4;
margin: 0;
padding: 20px;
}
h1 {
text-align: center;
color: #222;
}
#search {
display: block;
margin: 10px auto;
padding: 10px;
width: 80%;
font-size: 16px;
border-radius: 8px;
border: 1px solid #ccc;
}
#feeds {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
}
.feed-card {
background: white;
border-radius: 12px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
width: 320px;
padding: 12px;
box-sizing: border-box;
}
.feed-card img {
width: 100%;
height: auto;
border-radius: 8px;
margin-bottom: 10px;
}
.feed-card h2 {
font-size: 16px;
margin: 0 0 5px;
}
.feed-card p {
font-size: 14px;
color: #555;
}
.feed-card time {
display: block;
font-size: 12px;
color: #999;
margin-top: 5px;
}
</style>
</head>
<body>
<h1>超RSSニュースリーダー</h1>
<input type="text" id="search" placeholder="記事を検索...">
<div id="feeds"></div>
<script>
const rssUrls = [
"https://news.yahoo.co.jp/rss/topics/top-picks.xml",
"https://b.hatena.ne.jp/hotentry/it.rss",
"https://www.nhk.or.jp/rss/news/cat0.xml",
"http://tyosuke20xx.com/rss"
];
const proxy = "https://api.allorigins.win/get?url=";
const feedsContainer = document.getElementById("feeds");
const searchInput = document.getElementById("search");
let allCards = [];
function formatDate(pubDateStr) {
const date = new Date(pubDateStr);
return isNaN(date) ? "" : `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}`;
}
function extractImageFromDescription(desc) {
const match = desc.match(/<img.*?src="(.*?)"/);
return match ? match[1] : null;
}
async function fetchAndDisplayFeeds() {
feedsContainer.innerHTML = "🔄 更新中…";
allCards = [];
for (const url of rssUrls) {
try {
const res = await fetch(proxy + encodeURIComponent(url));
const data = await res.json();
const parser = new DOMParser();
const xml = parser.parseFromString(data.contents, "text/xml");
const items = xml.querySelectorAll("item");
items.forEach((item, i) => {
if (i >= 5) return;
const title = item.querySelector("title")?.textContent || "";
const link = item.querySelector("link")?.textContent || "#";
const desc = item.querySelector("description")?.textContent || "";
const pubDate = item.querySelector("pubDate")?.textContent || "";
const dateFormatted = formatDate(pubDate);
const img = extractImageFromDescription(desc);
const card = document.createElement("div");
card.className = "feed-card";
card.innerHTML = `
${img ? `<img src="${img}" alt="thumbnail">` : ""}
<h2><a href="${link}" target="_blank">${title}</a></h2>
<p>${desc.replace(/<[^>]+>/g, '').slice(0, 100)}...</p>
<time>${dateFormatted}</time>
`;
allCards.push({ title, desc, element: card });
feedsContainer.appendChild(card);
});
} catch (e) {
console.error("RSS取得失敗:", url, e);
}
}
}
searchInput.addEventListener("input", () => {
const keyword = searchInput.value.toLowerCase();
feedsContainer.innerHTML = "";
allCards.forEach(({ title, desc, element }) => {
if (title.toLowerCase().includes(keyword) || desc.toLowerCase().includes(keyword)) {
feedsContainer.appendChild(element);
}
});
});
fetchAndDisplayFeeds();
setInterval(fetchAndDisplayFeeds, 60000); // 60秒ごと自動更新
</script>
</body>
</html>
Github風サイト
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>GitHub風 - SampleRepo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap & FontAwesome -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet">
<style>
body {
background: #f6f8fa;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
.repo-header { background: #fff; padding: 20px; border: 1px solid #ddd; margin-bottom: 10px; }
.nav-tabs .nav-link.active { border-color: #ddd #ddd #fff; background: #fff; }
.file-list li { border-bottom: 1px solid #eee; padding: 8px 0; display: flex; align-items: center; }
.file-list i { margin-right: 10px; }
.readme-box, .issues-box, .commits-box { background: #fff; padding: 20px; border: 1px solid #ddd; margin-top: 10px; }
#editor { height: 400px; width: 100%; border: 1px solid #ccc; }
</style>
</head>
<body>
<!-- ヘッダー -->
<nav class="navbar navbar-dark bg-dark px-3">
<a class="navbar-brand" href="#"><i class="fab fa-github"></i> GitHub風サイト</a>
<span class="text-white"><i class="fas fa-user-circle"></i> yuhei</span>
</nav>
<div class="container mt-3">
<!-- リポジトリヘッダー -->
<div class="repo-header">
<h3><i class="fas fa-book"></i> yuhei / <strong>SampleRepo</strong></h3>
<p class="text-muted">最終更新: 2025年5月26日</p>
<button class="btn btn-sm btn-outline-secondary"><i class="fas fa-star"></i> Star</button>
<button class="btn btn-sm btn-outline-secondary"><i class="fas fa-code-branch"></i> Fork</button>
</div>
<!-- タブ -->
<ul class="nav nav-tabs" id="repoTabs">
<li class="nav-item"><a class="nav-link active" href="#" onclick="switchTab('code')"><i class="fas fa-code"></i> Code</a></li>
<li class="nav-item"><a class="nav-link" href="#" onclick="switchTab('issues')"><i class="fas fa-exclamation-circle"></i> Issues</a></li>
<li class="nav-item"><a class="nav-link" href="#" onclick="switchTab('commits')"><i class="fas fa-history"></i> Commits</a></li>
</ul>
<!-- Codeタブ -->
<div id="tab-code" class="tab-content">
<ul class="file-list list-unstyled bg-white p-3 border">
<li><i class="fas fa-folder"></i> src/</li>
<li><i class="fas fa-file-code"></i> index.js</li>
<li><i class="fas fa-file-alt"></i> README.md</li>
<li><i class="fas fa-file-alt"></i> LICENSE</li>
</ul>
<div class="readme-box">
<h4><i class="fas fa-book-open"></i> README.md</h4>
<hr>
<div id="readme-content"></div>
</div>
<div class="mt-4">
<h5><i class="fas fa-code"></i> コード編集 (Monaco Editor)</h5>
<div id="editor"></div>
<button id="saveCode" class="btn btn-success mt-2"><i class="fas fa-save"></i> 保存</button>
<button id="themeToggle" class="btn btn-secondary mt-2"><i class="fas fa-adjust"></i> テーマ切替</button>
</div>
</div>
<!-- Issuesタブ -->
<div id="tab-issues" class="tab-content" style="display:none;">
<div class="issues-box">
<h4><i class="fas fa-exclamation-circle"></i> Open Issues</h4>
<ul class="list-group">
<li class="list-group-item">
<strong>#1</strong> READMEの翻訳が必要です<br>
<small class="text-muted">posted by yuhei - 1日前</small>
</li>
<li class="list-group-item">
<strong>#2</strong> index.jsにテストコードを追加してください<br>
<small class="text-muted">posted by yuhei - 2日前</small>
</li>
</ul>
</div>
</div>
<!-- Commitsタブ -->
<div id="tab-commits" class="tab-content" style="display:none;">
<div class="commits-box">
<h4><i class="fas fa-history"></i> Commits</h4>
<ul class="list-group">
<li class="list-group-item">
<strong>Initial commit</strong> - 2025-05-25<br>
<small class="text-muted">by yuhei</small>
</li>
<li class="list-group-item">
<strong>README updated</strong> - 2025-05-26<br>
<small class="text-muted">by yuhei</small>
</li>
</ul>
</div>
</div>
</div>
<!-- ライブラリ -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs/loader.min.js"></script>
<!-- タブ切替・Markdown表示・Monaco起動 -->
<script>
const markdown = `
# SampleRepo
ようこそ!これはGitHub風サイトのデモです。
## 特徴
- Monaco Editorでコード編集
- Markdown表示(README)
- ダークモード対応
- Issue・コミットのUI
## 技術
- HTML/CSS/JS
- Bootstrap5
- Monaco Editor
- Marked.js
`;
document.getElementById('readme-content').innerHTML = marked.parse(markdown);
function switchTab(tab) {
['code', 'issues', 'commits'].forEach(id => {
document.getElementById('tab-' + id).style.display = (id === tab) ? 'block' : 'none';
});
document.querySelectorAll('#repoTabs .nav-link').forEach(link => link.classList.remove('active'));
document.querySelector(`#repoTabs .nav-link[onclick*="${tab}"]`).classList.add('active');
}
// Monaco起動
require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs' }});
require(['vs/editor/editor.main'], function () {
window.editor = monaco.editor.create(document.getElementById('editor'), {
value: localStorage.getItem('savedCode') || `function hello() {\n console.log("Hello from Monaco Editor!");\n}`,
language: 'javascript',
theme: 'vs-light',
automaticLayout: true
});
document.getElementById('saveCode').onclick = function () {
const code = editor.getValue();
localStorage.setItem('savedCode', code);
alert('保存しました!');
};
document.getElementById('themeToggle').onclick = function () {
const theme = monaco.editor.getTheme() === 'vs-dark' ? 'vs-light' : 'vs-dark';
monaco.editor.setTheme(theme);
};
});
</script>
</body>
</html>
NeuroLink VR
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>フルダイブVR - 仮想世界体験</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
.vr-container {
width: 95vw;
height: 95vh;
background: #000;
border-radius: 20px;
position: relative;
overflow: hidden;
box-shadow: 0 20px 50px rgba(0,0,0,0.3);
}
.boot-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, #0f0f23, #1a1a2e);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 100;
transition: opacity 1s ease-out;
}
.boot-screen.hidden {
opacity: 0;
pointer-events: none;
}
.logo {
font-size: 3rem;
color: #00d4ff;
margin-bottom: 30px;
text-shadow: 0 0 20px #00d4ff;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
.loading-bar {
width: 300px;
height: 4px;
background: #333;
border-radius: 2px;
overflow: hidden;
margin-bottom: 20px;
}
.loading-progress {
height: 100%;
background: linear-gradient(90deg, #00d4ff, #ff006e);
width: 0%;
animation: loading 3s ease-out forwards;
}
@keyframes loading {
to { width: 100%; }
}
.boot-text {
color: #00d4ff;
font-size: 1.2rem;
margin-top: 20px;
}
#canvas {
width: 100%;
height: 100%;
display: block;
}
.hud {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 10;
}
.status-panel {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 212, 255, 0.1);
border: 1px solid #00d4ff;
border-radius: 10px;
padding: 15px;
color: #00d4ff;
font-family: 'Courier New', monospace;
backdrop-filter: blur(10px);
}
.controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 15px;
pointer-events: all;
}
.control-btn {
background: rgba(0, 212, 255, 0.2);
border: 2px solid #00d4ff;
color: #00d4ff;
padding: 12px 20px;
border-radius: 25px;
cursor: pointer;
font-size: 14px;
font-weight: bold;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.control-btn:hover {
background: rgba(0, 212, 255, 0.4);
box-shadow: 0 0 20px rgba(0, 212, 255, 0.5);
transform: translateY(-2px);
}
.neural-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle at center, transparent 30%, rgba(0, 212, 255, 0.05) 100%);
pointer-events: none;
z-index: 5;
}
.dive-complete {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #00d4ff;
font-size: 2rem;
text-align: center;
opacity: 0;
animation: fadeInOut 4s ease-in-out;
z-index: 50;
text-shadow: 0 0 20px #00d4ff;
}
@keyframes fadeInOut {
0%, 100% { opacity: 0; }
20%, 80% { opacity: 1; }
}
</style>
</head>
<body>
<div class="vr-container">
<div class="boot-screen" id="bootScreen">
<div class="logo">NeuroLink VR</div>
<div class="loading-bar">
<div class="loading-progress"></div>
</div>
<div class="boot-text">Neural Interface Initializing...</div>
</div>
<canvas id="canvas"></canvas>
<div class="neural-overlay"></div>
<div class="hud">
<div class="status-panel">
<div>Neural Sync: <span id="sync">98.7%</span></div>
<div>Reality Index: <span id="reality">VIRTUAL</span></div>
<div>Immersion Level: <span id="immersion">MAXIMUM</span></div>
<div>Connected Users: <span id="users">1,247</span></div>
</div>
</div>
<div class="controls">
<button class="control-btn" onclick="changeWorld('cyber')">サイバー都市</button>
<button class="control-btn" onclick="changeWorld('forest')">森林世界</button>
<button class="control-btn" onclick="changeWorld('space')">宇宙ステーション</button>
<button class="control-btn" onclick="disconnect()">ログアウト</button>
</div>
<div class="dive-complete" id="diveComplete">
フルダイブ完了<br>
<small>仮想世界へようこそ</small>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
let scene, camera, renderer, world = 'cyber';
let particles = [];
let buildings = [];
let stars = [];
let trees = [];
// 起動シーケンス
setTimeout(() => {
document.getElementById('bootScreen').classList.add('hidden');
initVR();
setTimeout(() => {
document.getElementById('diveComplete').style.display = 'block';
}, 1000);
}, 3500);
function initVR() {
// Three.js セットアップ
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('canvas'), antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x000011);
// 初期世界を構築
buildCyberWorld();
// カメラ位置
camera.position.set(0, 5, 10);
// アニメーションループ
animate();
// HUD更新
updateHUD();
}
function buildCyberWorld() {
// クリア
clearWorld();
scene.fog = new THREE.Fog(0x000033, 10, 100);
// ネオンビル群
for (let i = 0; i < 50; i++) {
const height = Math.random() * 20 + 5;
const geometry = new THREE.BoxGeometry(
Math.random() * 3 + 1,
height,
Math.random() * 3 + 1
);
const material = new THREE.MeshBasicMaterial({
color: Math.random() > 0.5 ? 0x00ffff : 0xff00ff,
transparent: true,
opacity: 0.8
});
const building = new THREE.Mesh(geometry, material);
building.position.set(
(Math.random() - 0.5) * 100,
height / 2,
(Math.random() - 0.5) * 100
);
scene.add(building);
buildings.push(building);
}
// パーティクル効果
createParticles(0x00ffff);
// 地面
const floorGeometry = new THREE.PlaneGeometry(200, 200);
const floorMaterial = new THREE.MeshBasicMaterial({
color: 0x001122,
transparent: true,
opacity: 0.5
});
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
scene.add(floor);
}
function buildForestWorld() {
clearWorld();
scene.fog = new THREE.Fog(0x228B22, 5, 50);
// 木々
for (let i = 0; i < 100; i++) {
// 幹
const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.5, 8);
const trunkMaterial = new THREE.MeshBasicMaterial({ color: 0x8B4513 });
const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
// 葉
const leavesGeometry = new THREE.SphereGeometry(3);
const leavesMaterial = new THREE.MeshBasicMaterial({ color: 0x228B22 });
const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial);
leaves.position.y = 6;
const tree = new THREE.Group();
tree.add(trunk);
tree.add(leaves);
tree.position.set(
(Math.random() - 0.5) * 80,
4,
(Math.random() - 0.5) * 80
);
scene.add(tree);
trees.push(tree);
}
createParticles(0x90EE90);
// 地面
const floorGeometry = new THREE.PlaneGeometry(200, 200);
const floorMaterial = new THREE.MeshBasicMaterial({ color: 0x2F4F2F });
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
scene.add(floor);
}
function buildSpaceWorld() {
clearWorld();
scene.fog = null;
renderer.setClearColor(0x000000);
// 星々
for (let i = 0; i < 1000; i++) {
const starGeometry = new THREE.SphereGeometry(0.1);
const starMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
const star = new THREE.Mesh(starGeometry, starMaterial);
star.position.set(
(Math.random() - 0.5) * 200,
(Math.random() - 0.5) * 200,
(Math.random() - 0.5) * 200
);
scene.add(star);
stars.push(star);
}
// 宇宙ステーション
const stationGeometry = new THREE.TorusGeometry(10, 3, 8, 20);
const stationMaterial = new THREE.MeshBasicMaterial({
color: 0x888888,
wireframe: true
});
const station = new THREE.Mesh(stationGeometry, stationMaterial);
station.position.set(0, 0, -20);
scene.add(station);
createParticles(0xffffff);
}
function createParticles(color) {
for (let i = 0; i < 200; i++) {
const particleGeometry = new THREE.SphereGeometry(0.05);
const particleMaterial = new THREE.MeshBasicMaterial({
color: color,
transparent: true,
opacity: 0.6
});
const particle = new THREE.Mesh(particleGeometry, particleMaterial);
particle.position.set(
(Math.random() - 0.5) * 50,
Math.random() * 20,
(Math.random() - 0.5) * 50
);
particle.velocity = {
x: (Math.random() - 0.5) * 0.02,
y: Math.random() * 0.01,
z: (Math.random() - 0.5) * 0.02
};
scene.add(particle);
particles.push(particle);
}
}
function clearWorld() {
buildings.forEach(b => scene.remove(b));
trees.forEach(t => scene.remove(t));
stars.forEach(s => scene.remove(s));
particles.forEach(p => scene.remove(p));
buildings = [];
trees = [];
stars = [];
particles = [];
// シーン全体をクリア
while(scene.children.length > 0) {
scene.remove(scene.children[0]);
}
}
function animate() {
requestAnimationFrame(animate);
// カメラの自動回転
const time = Date.now() * 0.0005;
camera.position.x = Math.cos(time) * 20;
camera.position.z = Math.sin(time) * 20;
camera.lookAt(scene.position);
// パーティクルアニメーション
particles.forEach(particle => {
particle.position.add(particle.velocity);
if (particle.position.y > 25) {
particle.position.y = -5;
}
if (particle.position.x > 25) particle.position.x = -25;
if (particle.position.x < -25) particle.position.x = 25;
if (particle.position.z > 25) particle.position.z = -25;
if (particle.position.z < -25) particle.position.z = 25;
});
// ビルの光る効果
buildings.forEach(building => {
if (Math.random() > 0.98) {
building.material.opacity = Math.random() * 0.5 + 0.5;
}
});
renderer.render(scene, camera);
}
function changeWorld(newWorld) {
world = newWorld;
switch(world) {
case 'cyber':
buildCyberWorld();
break;
case 'forest':
buildForestWorld();
break;
case 'space':
buildSpaceWorld();
break;
}
}
function updateHUD() {
setInterval(() => {
document.getElementById('sync').textContent = (98 + Math.random() * 2).toFixed(1) + '%';
document.getElementById('users').textContent = (1200 + Math.floor(Math.random() * 100)).toLocaleString();
}, 2000);
}
function disconnect() {
document.querySelector('.vr-container').style.opacity = '0';
setTimeout(() => {
document.body.innerHTML = `
<div style="display: flex; justify-content: center; align-items: center; height: 100vh; color: #00d4ff; font-size: 2rem; text-align: center;">
<div>
<div>Neural Link Disconnected</div>
<div style="font-size: 1rem; margin-top: 20px; opacity: 0.7;">現実世界へ戻りました</div>
</div>
</div>
`;
}, 1000);
}
// リサイズ対応
window.addEventListener('resize', () => {
if (camera && renderer) {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
});
</script>
</body>
</html>
求人掲示板サイト.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>JobFinder - 求人掲示板</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: sans-serif; background: #f4f4f4; margin: 0; }
header { background: #007bff; color: white; padding: 1rem; text-align: center; }
main { padding: 2rem; max-width: 900px; margin: auto; }
.search-bar, .post-form { background: white; padding: 1rem; border-radius: 8px; margin-bottom: 2rem; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.job-card {
background: white; padding: 1rem; margin-bottom: 1rem;
border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.job-card h2 { margin-top: 0; }
.job-card button {
background: #007bff; color: white;
border: none; padding: 0.5rem 1rem;
border-radius: 4px; cursor: pointer;
}
.job-card button:hover { background: #0056b3; }
.modal {
display: none; position: fixed; z-index: 999;
left: 0; top: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.5);
justify-content: center; align-items: center;
}
.modal-content {
background: white; padding: 2rem;
border-radius: 8px; max-width: 500px;
}
label, input, textarea, select {
display: block; width: 100%; margin-bottom: 10px;
}
button[type="submit"] {
background: #28a745;
color: white;
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
}
</style>
</head>
<body>
<header>
<h1>JobFinder - 求人掲示板</h1>
</header>
<main>
<!-- 🔍 検索バー -->
<div class="search-bar">
<h3>🔍 求人検索</h3>
<input type="text" id="searchLocation" placeholder="勤務地で検索(例: 東京)">
<button onclick="filterJobs()">検索</button>
</div>
<!-- 📋 求人一覧 -->
<div id="jobList"></div>
<!-- 📝 求人投稿フォーム -->
<div class="post-form">
<h3>📝 新しい求人を投稿</h3>
<input type="text" id="jobTitle" placeholder="職種(例: Webエンジニア)">
<input type="text" id="jobCompany" placeholder="会社名">
<input type="text" id="jobLocation" placeholder="勤務地(例: 東京)">
<textarea id="jobDescription" rows="3" placeholder="仕事内容を入力..."></textarea>
<button onclick="addJob()">求人を投稿</button>
</div>
</main>
<!-- 📄 モーダル -->
<div class="modal" id="jobModal">
<div class="modal-content" id="modalContent"></div>
</div>
<script>
let jobs = [
{
title: "Webエンジニア",
company: "株式会社テック",
location: "東京",
description: "ReactやVueを用いた開発。経験者優遇。"
},
{
title: "営業職",
company: "セールス株式会社",
location: "大阪",
description: "法人営業経験者歓迎。"
}
];
function displayJobs(filteredJobs = jobs) {
const jobList = document.getElementById("jobList");
jobList.innerHTML = "";
filteredJobs.forEach((job, index) => {
const card = document.createElement("div");
card.className = "job-card";
card.innerHTML = `
<h2>${job.title}</h2>
<p><strong>会社:</strong> ${job.company}</p>
<p><strong>勤務地:</strong> ${job.location}</p>
<button onclick="showDetails(${index})">詳細を見る</button>
`;
jobList.appendChild(card);
});
}
function showDetails(index) {
const job = jobs[index];
const modal = document.getElementById("jobModal");
const modalContent = document.getElementById("modalContent");
modalContent.innerHTML = `
<h2>${job.title}</h2>
<p><strong>会社:</strong> ${job.company}</p>
<p><strong>勤務地:</strong> ${job.location}</p>
<p>${job.description}</p>
<button onclick="alert('応募完了しました!')">応募する</button>
<button onclick="document.getElementById('jobModal').style.display='none'">閉じる</button>
`;
modal.style.display = "flex";
}
function addJob() {
const title = document.getElementById("jobTitle").value;
const company = document.getElementById("jobCompany").value;
const location = document.getElementById("jobLocation").value;
const description = document.getElementById("jobDescription").value;
if (title && company && location && description) {
jobs.push({ title, company, location, description });
displayJobs();
document.getElementById("jobTitle").value = "";
document.getElementById("jobCompany").value = "";
document.getElementById("jobLocation").value = "";
document.getElementById("jobDescription").value = "";
} else {
alert("すべての項目を入力してください");
}
}
function filterJobs() {
const keyword = document.getElementById("searchLocation").value.trim();
const filtered = jobs.filter(job => job.location.includes(keyword));
displayJobs(filtered);
}
// 初期表示
displayJobs();
window.onclick = function(event) {
const modal = document.getElementById("jobModal");
if (event.target === modal) {
modal.style.display = "none";
}
}
</script>
</body>
</html>
note風WEBサービス
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>MiniNote - Note風ブログ with フィルタ・いいね・検索機能</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body { font-family: sans-serif; background: #f9f9f9; margin: 0; }
header { background: #2c3e50; color: white; padding: 1em; text-align: center; }
nav { background: #34495e; text-align: center; padding: 0.5em; }
nav button { margin: 0 8px; padding: 8px 20px; cursor: pointer; background: #ecf0f1; border: none; border-radius: 5px; }
#main { max-width: 900px; margin: 2em auto; padding: 1em; background: white; border-radius: 10px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); }
article { padding: 1em; border-bottom: 1px solid #ddd; }
h2 { margin: 0.5em 0; }
.meta { font-size: 0.9em; color: #999; margin-bottom: 0.5em; }
textarea, input[type="text"] { width: 100%; padding: 10px; margin: 10px 0; border-radius: 5px; border: 1px solid #ccc; }
button.submit {
background: #3498db; color: white; border: none;
padding: 10px 20px; border-radius: 6px;
cursor: pointer; font-weight: bold;
}
.hidden { display: none; }
.tag { color: #3498db; margin-right: 5px; font-size: 0.9em; cursor: pointer; }
.actions button { margin-right: 10px; }
.like { color: #e74c3c; cursor: pointer; margin-left: 10px; }
</style>
</head>
<body>
<header><h1>📘 MiniNote - あなたのNote風ブログ</h1></header>
<nav>
<button onclick="showView('home')">🏠 ホーム</button>
<button onclick="showView('new')">✍ 新規投稿</button>
<input type="text" id="searchInput" placeholder="検索" oninput="renderPosts()" style="padding:5px; width: 200px;">
</nav>
<div id="main">
<div id="homeView">
<div id="postList"></div>
</div>
<div id="newView" class="hidden">
<h2>新しい投稿を作成</h2>
<input type="text" id="titleInput" placeholder="タイトル">
<textarea id="contentInput" rows="8" placeholder="本文"></textarea>
<input type="text" id="tagInput" placeholder="タグ(カンマ区切り)">
<button class="submit" onclick="addPost()">投稿する</button>
</div>
<div id="detailView" class="hidden">
<article>
<h2 id="detailTitle"></h2>
<div class="meta" id="detailDate"></div>
<p id="detailContent"></p>
<div id="detailTags"></div>
<div class="like" id="likeDisplay" onclick="likePost(currentIndex)">❤️ <span id="likeCount">0</span></div>
</article>
<div class="actions">
<button onclick="editPost(currentIndex)">✏ 編集</button>
<button onclick="deletePost(currentIndex)">🗑 削除</button>
<button onclick="showView('home')">← 戻る</button>
</div>
</div>
</div>
<script>
let posts = JSON.parse(localStorage.getItem("posts") || "[]");
let currentIndex = null;
let filterTag = null;
function showView(view) {
document.querySelectorAll('#main > div').forEach(div => div.classList.add('hidden'));
document.getElementById(view + "View").classList.remove("hidden");
if (view === "home") renderPosts();
}
function addPost() {
const title = document.getElementById("titleInput").value;
const content = document.getElementById("contentInput").value;
const tags = document.getElementById("tagInput").value.split(',').map(tag => tag.trim()).filter(Boolean);
if (!title || !content) return alert("タイトルと本文を入力してください");
const date = new Date().toLocaleString();
posts.unshift({ title, content, date, tags, likes: 0 });
localStorage.setItem("posts", JSON.stringify(posts));
clearForm();
showView("home");
}
function renderPosts() {
const list = document.getElementById("postList");
const search = document.getElementById("searchInput").value.toLowerCase();
list.innerHTML = "";
posts.filter(post => {
const inSearch = post.title.toLowerCase().includes(search) || post.content.toLowerCase().includes(search);
const inTag = !filterTag || post.tags.includes(filterTag);
return inSearch && inTag;
}).forEach((post, index) => {
const el = document.createElement("article");
el.innerHTML = `
<h2>${post.title}</h2>
<div class="meta">${post.date}</div>
<p>${post.content.substring(0, 80)}...</p>
<div>${post.tags.map(tag => `<span class='tag' onclick='filterByTag("${tag}")'>#${tag}</span>`).join(' ')}</div>
<div class="like">❤️ ${post.likes}</div>
<button onclick="showDetail(${index})">📖 詳細</button>
`;
list.appendChild(el);
});
}
function filterByTag(tag) {
filterTag = tag;
renderPosts();
}
function showDetail(index) {
const post = posts[index];
currentIndex = index;
document.getElementById("detailTitle").innerText = post.title;
document.getElementById("detailDate").innerText = post.date;
document.getElementById("detailContent").innerText = post.content;
document.getElementById("detailTags").innerHTML = post.tags.map(tag => `<span class='tag'>#${tag}</span>`).join(' ');
document.getElementById("likeCount").innerText = post.likes;
showView("detail");
}
function likePost(index) {
posts[index].likes++;
localStorage.setItem("posts", JSON.stringify(posts));
document.getElementById("likeCount").innerText = posts[index].likes;
renderPosts();
}
function editPost(index) {
const post = posts[index];
document.getElementById("titleInput").value = post.title;
document.getElementById("contentInput").value = post.content;
document.getElementById("tagInput").value = post.tags.join(', ');
posts.splice(index, 1);
localStorage.setItem("posts", JSON.stringify(posts));
showView("new");
}
function deletePost(index) {
if (!confirm("本当に削除しますか?")) return;
posts.splice(index, 1);
localStorage.setItem("posts", JSON.stringify(posts));
showView("home");
}
function clearForm() {
document.getElementById("titleInput").value = "";
document.getElementById("contentInput").value = "";
document.getElementById("tagInput").value = "";
}
showView("home");
</script>
</body>
</html>
MyCSSGrid
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My CSS Grid</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<ul>
<li>item 1</li>
<li>item 2 item 2 item 2 item 2 item 2</li>
<li>item 3</li>
<li>item 4</li>
</ul>
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3 item 3 item 3 item 3</li>
<li>item 4</li>
</ul>
</div>
</body>
</html>
style.css
@charset "utf-8";
.container {
display: grid;
grid-template-columns: 200px 200px;
grid-template-rows: repeat(4, auto);
}
ul {
grid-row: span 4;
display: grid;
grid-template-rows: subgrid;
}
ドメイン検索&購入(フロントエンド)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>ドメイン検索&購入</title>
<style>
body {
font-family: sans-serif;
background: #f9f9f9;
padding: 2rem;
margin: 0;
display: flex;
justify-content: center;
}
.container {
max-width: 600px;
width: 100%;
background: white;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
}
h1 {
color: #e60033;
text-align: center;
margin-bottom: 1.5rem;
}
.form {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
}
input {
flex: 1;
padding: 0.8rem;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 1rem;
}
button {
padding: 0.8rem 1rem;
background-color: #e60033;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
}
.result {
margin-top: 1rem;
}
.item {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eee;
padding: 0.5rem 0;
}
.available {
color: green;
font-weight: bold;
}
.unavailable {
color: red;
font-weight: bold;
}
.buy-btn {
background-color: #0070f3;
color: white;
padding: 0.3rem 0.7rem;
border-radius: 6px;
text-decoration: none;
font-size: 0.9rem;
}
</style>
</head>
<body>
<div class="container">
<h1>ドメイン検索</h1>
<div class="form">
<input type="text" id="domainInput" placeholder="例: mydomain" />
<button onclick="search()">検索</button>
</div>
<div class="result" id="resultArea"></div>
</div>
<script>
const takenDomains = ["example.com", "mydomain.net", "taken.jp"];
const tlds = [".com", ".net", ".jp"];
function search() {
const name = document.getElementById("domainInput").value.trim().toLowerCase();
const area = document.getElementById("resultArea");
area.innerHTML = "";
if (!name) {
area.innerHTML = "<p>⚠ ドメイン名を入力してください。</p>";
return;
}
tlds.forEach(tld => {
const domain = name + tld;
const available = !takenDomains.includes(domain);
const item = document.createElement("div");
item.className = "item";
item.innerHTML = `
<span>${domain}</span>
${available
? `<span class="available">取得可能</span>
<a href="https://buy.stripe.com/test_checkout_link" class="buy-btn" target="_blank">購入する</a>`
: `<span class="unavailable">登録済み</span>`}
`;
area.appendChild(item);
});
}
</script>
</body>
</html>
ゲームBGM自動生成サービス.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>🎮 ゲームBGM自動生成サービス</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root {
--bg: #121212;
--card: #1e1e2e;
--text: #ffffff;
--accent: #ffd700;
--shadow: rgba(0, 0, 0, 0.3);
--button: #ffd700;
}
[data-theme='light'] {
--bg: #f5f5f5;
--card: #ffffff;
--text: #111;
--accent: #ff9800;
--shadow: rgba(0, 0, 0, 0.1);
--button: #ff9800;
}
body {
margin: 0;
font-family: 'Segoe UI', sans-serif;
background: var(--bg);
color: var(--text);
transition: 0.3s;
padding: 1rem;
}
header {
text-align: center;
margin-bottom: 1rem;
}
h1 {
color: var(--accent);
font-size: 2rem;
}
.container {
max-width: 600px;
margin: auto;
background: var(--card);
border-radius: 12px;
box-shadow: 0 0 10px var(--shadow);
padding: 1.5rem;
}
label {
font-weight: bold;
display: block;
margin-top: 1rem;
}
select, button {
width: 100%;
padding: 0.6rem;
margin-top: 0.5rem;
border-radius: 8px;
border: none;
font-size: 1rem;
}
button {
background: var(--button);
color: #000;
font-weight: bold;
cursor: pointer;
transition: 0.3s;
}
button:disabled {
background: #999;
cursor: not-allowed;
}
button:hover:enabled {
opacity: 0.85;
}
.desc, .msg {
margin-top: 1rem;
font-size: 0.9rem;
color: #ccc;
}
.result, .history {
margin-top: 2rem;
}
audio {
width: 100%;
margin-top: 0.5rem;
}
.visualizer {
width: 100%;
height: 4px;
background: linear-gradient(90deg, #ffd700, #ff9800);
animation: pulse 2s infinite linear;
opacity: 0;
}
.playing .visualizer {
opacity: 1;
}
@keyframes pulse {
0% { transform: scaleX(1); }
50% { transform: scaleX(1.05); }
100% { transform: scaleX(1); }
}
.toggle-theme {
text-align: right;
margin-bottom: 0.5rem;
}
.accordion {
background: transparent;
color: var(--accent);
border: none;
font-weight: bold;
cursor: pointer;
margin-top: 1rem;
width: 100%;
text-align: left;
font-size: 1rem;
}
.accordion-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.accordion.open + .accordion-content {
max-height: 600px;
}
</style>
</head>
<body>
<header>
<h1>🎮 ゲームBGM自動生成</h1>
</header>
<div class="toggle-theme">
<button onclick="toggleTheme()">🌓 テーマ切替</button>
</div>
<div class="container">
<label for="genre">🎼 ジャンル</label>
<select id="genre" onchange="updateDescription()">
<option value="fantasy">ファンタジー</option>
<option value="cyberpunk">サイバーパンク</option>
<option value="horror">ホラー</option>
<option value="symphonic">シンフォニック</option>
</select>
<label for="mood">🎭 雰囲気</label>
<select id="mood" onchange="updateDescription()">
<option value="mysterious">神秘的</option>
<option value="sad">悲しい</option>
<option value="heroic">勇ましい</option>
<option value="fun">楽しい</option>
</select>
<div class="desc" id="descText">選択内容に応じてBGMを生成します。</div>
<button id="generateBtn" onclick="generateBGM()">🎶 BGMを生成する</button>
<div class="msg" id="msg"></div>
<div class="result" id="result" style="display:none;">
<h3>🎧 再生中のBGM</h3>
<audio controls id="player" onplay="startVisualizer()" onpause="stopVisualizer()"></audio>
<div class="visualizer" id="visualizer"></div>
</div>
<button class="accordion" onclick="toggleAccordion(this)">📜 再生履歴</button>
<div class="accordion-content" id="historyList"></div>
</div>
<script>
const descMap = {
fantasy: "魔法の世界、冒険と伝説の音楽",
cyberpunk: "近未来都市とテクノ感の融合",
horror: "不安と恐怖を煽るBGM",
symphonic: "壮大で感動的なオーケストラ風",
mysterious: "謎解き、探検にぴったり",
sad: "涙や喪失感を表現する旋律",
heroic: "勇ましさ、戦い、勝利の象徴",
fun: "軽快で明るいリズム"
};
const history = [];
const maxHistory = 5;
function updateDescription() {
const g = document.getElementById('genre').value;
const m = document.getElementById('mood').value;
document.getElementById('descText').textContent = `🧠 ${descMap[g]} × ${descMap[m]}`;
}
function generateBGM() {
const genre = document.getElementById('genre').value;
const mood = document.getElementById('mood').value;
const btn = document.getElementById('generateBtn');
const player = document.getElementById('player');
const msg = document.getElementById('msg');
const result = document.getElementById('result');
btn.disabled = true;
msg.textContent = "⏳ BGMを生成中...";
const url = `https://example.com/bgm/${genre}_${mood}_${Math.floor(Math.random()*3)+1}.mp3`;
setTimeout(() => {
msg.textContent = "✅ BGM生成完了!再生できます。";
player.src = url;
result.style.display = 'block';
// 保存履歴
history.unshift({ genre, mood, url });
if (history.length > maxHistory) history.pop();
renderHistory();
btn.disabled = false;
}, 1500);
}
function renderHistory() {
const list = document.getElementById('historyList');
list.innerHTML = "";
history.forEach(item => {
const div = document.createElement('div');
div.innerHTML = `<strong>${item.genre} × ${item.mood}</strong><br><audio controls src="${item.url}"></audio><hr>`;
list.appendChild(div);
});
}
function toggleTheme() {
const theme = document.documentElement.getAttribute("data-theme");
document.documentElement.setAttribute("data-theme", theme === "light" ? "dark" : "light");
}
function toggleAccordion(el) {
el.classList.toggle('open');
}
function startVisualizer() {
document.getElementById('visualizer').style.opacity = '1';
}
function stopVisualizer() {
document.getElementById('visualizer').style.opacity = '0';
}
// 初期設定
document.documentElement.setAttribute("data-theme", "dark");
updateDescription();
</script>
</body>
</html>
MyAOS.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Site</title>
<link rel="stylesheet" href="https://unpkg.com/aos@next/dist/aos.css" />
<link rel="stylesheet" href="style.css">
</head>
<body>
<section>
<h1>記事一覧</h1>
<article>
<img src="forest.png" width="240" height="160" data-aos="my-animation">
<div class="text">
<h2>タイトル</h2>
<p>こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。</p>
</div>
</article>
<article>
<img src="forest.png" width="240" height="160">
<div class="text">
<h2>タイトル</h2>
<p>こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。</p>
</div>
</article>
<article>
<img src="forest.png" width="240" height="160">
<div class="text">
<h2>タイトル</h2>
<p>こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。</p>
</div>
</article>
</section>
<section>
<h1>お客様の声</h1>
<div class="voices">
<section data-aos="fade-up">
<h2>すばらしい</h2>
<p>素晴らしいです。素晴らしいです。</p>
</section>
<section data-aos="fade-up" data-aos-delay="300">
<h2>すばらしい</h2>
<p>素晴らしいです。素晴らしいです。</p>
</section>
<section data-aos="fade-up" data-aos-delay="600">
<h2>すばらしい</h2>
<p>素晴らしいです。素晴らしいです。</p>
</section>
</div>
</section>
<footer id="footer">
(c) dotinstall.com
</footer>
<a href="#" class="to-top" data-aos="fade-up" data-aos-anchor="#footer" data-aos-offset="0">先頭へ</a>
<script src="https://unpkg.com/aos@next/dist/aos.js"></script>
<script>
AOS.init();
</script>
</body>
</html>
style.css
@charset "utf-8";
body {
margin: 0;
}
body>section {
margin: 0 32px;
}
h1 {
text-align: center;
padding: 160px 0;
}
article {
display: flex;
gap: 16px;
align-items: center;
}
article .text {
flex: 1;
}
article h2 {
margin: 0;
font-size: 22px;
}
article+article {
margin-top: 32px;
}
article:nth-child(even) {
flex-direction: row-reverse;
}
.voices {
display: flex;
gap: 16px;
}
.voices>section {
border-radius: 8px;
border: 1px solid #ccc;
padding: 16px 32px;
text-align: center;
}
footer {
margin-top: 160px;
text-align: center;
padding: 80px 0;
background: #eee;
}
.to-top {
position: fixed;
bottom: 16px;
right: 16px;
}
