CSSとJSで作る、反射がきれいなガラスの輪っか

アニメーション

CSSとJSで作る、反射がきれいなガラスの輪っか

投稿日2026/02/06

更新日2026/2/2

透明感のあるガラス表現や、光を反射する3Dオブジェクトは、それだけで画面の印象をぐっと引き締めてくれます。

このデモでは、反射がきれいなガラスの輪っかと立体的な文字を組み合わせた演出を、できるだけシンプルな構成で作っています。
画面サイズに合わせて自動でレイアウトが調整されるため、PCでもスマホでも破綻しません。

Preview プレビュー

Code コード

<canvas class="webgl"></canvas>
body {
	margin: 0;
	overflow: hidden;
	background-color: #000;
}
.webgl {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	outline: none;
}
import * as THREE from "https://esm.sh/three@0.173.0";
import {
	FontLoader
} from "https://esm.sh/three@0.173.0/examples/jsm/loaders/FontLoader.js";
import {
	TextGeometry
} from "https://esm.sh/three@0.173.0/examples/jsm/geometries/TextGeometry.js";
// --- シーン設定 ---
const scene = new THREE.Scene();
const canvas = document.querySelector(".webgl");
const renderer = new THREE.WebGLRenderer({
	canvas,
	antialias: true
});
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
let torus, textMesh;
// --- フォント読み込み ---
const fontLoader = new FontLoader();
fontLoader.load("https://raw.githubusercontent.com/danielyl123/person/refs/heads/main/fonts/helvetiker_regular.typeface.json",
	(font) => {
		// 文字を「KUMONOSU」に変更
		const textGeometry = new TextGeometry("KUMONOSU", {
			font,
			size: 1,
			depth: 0.2,
			curveSegments: 5,
			bevelEnabled: true,
			bevelThickness: 0.03,
			bevelSize: 0.02,
			bevelSegments: 4,
		});
		textGeometry.center();
		textMesh = new THREE.Mesh(textGeometry, new THREE.MeshBasicMaterial({
			color: 0xffffff
		}));
		scene.add(textMesh);
		handleResize(); // テキスト生成後に位置を確定
	});
// --- トーラス(虹色・透過) ---
const torusGeometry = new THREE.TorusGeometry(0.7, 0.4, 100, 60);
const torusMaterial = new THREE.MeshPhysicalMaterial({
	metalness: 0,
	roughness: 0,
	iridescence: 1,
	iridescenceIOR: 1.5,
	iridescenceThicknessRange: [100, 324],
	transmission: 1,
	ior: 1.2,
	thickness: 0.8,
});
torus = new THREE.Mesh(torusGeometry, torusMaterial);
torus.position.z = 1; // 文字より手前に配置
scene.add(torus);
// --- ライト ---
scene.add(new THREE.AmbientLight(0xffffff, 1));
const addLight = (x, y, z) => {
	const light = new THREE.PointLight(0xffffff, 20);
	light.position.set(x, y, z);
	scene.add(light);
};
addLight(-2, 3, 2);
addLight(2, -3, 2);
// --- レスポンシブ対応 ---
function handleResize() {
	const width = window.innerWidth;
	const height = window.innerHeight;
	const aspect = width / height;
	renderer.setSize(width, height);
	renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
	camera.aspect = aspect;
	// 表示したいコンテンツの想定幅
	const contentWidth = 9;
	const fovInRadians = (camera.fov * Math.PI) / 180;
	if (aspect < 1) {
		// 縦長:横幅に合わせる
		camera.position.z = (contentWidth / aspect) / (2 * Math.tan(fovInRadians / 2));
	} else {
		// 横長:固定距離
		camera.position.z = contentWidth / (2 * Math.tan(fovInRadians / 2));
	}
	camera.updateProjectionMatrix();
}
window.addEventListener("resize", handleResize);
handleResize();
// --- アニメーションループ ---
const clock = new THREE.Clock();
const tick = () => {
	const elapsedTime = clock.getElapsedTime();
	if (torus) {
		torus.rotation.x = elapsedTime * 0.5;
		torus.rotation.y = elapsedTime * 0.1;
	}
	renderer.render(scene, camera);
	requestAnimationFrame(tick);
};
tick();

Explanation 詳しい説明

このデモでできること

このサンプルでは、以下のような表現を行っています。

  • ガラスのような透明感を持つ輪っか形状の表示
  • 光を受けて変化する反射・質感表現
  • 立体的な3Dテキストの表示
  • 画面サイズに応じた自動スケーリング(レスポンシブ対応)

特別な操作はなく、ページを開くだけで常に画面に収まるバランスで3D演出が表示されます。

ガラスの輪っかを使っている理由

輪っか形状は、

  • 光が当たる部分
  • 反射が強く出る部分
  • 透過して背景が見える部分

が同時に存在するため、ガラス表現の違いがとても分かりやすい形です。

そのためこのデモでは、「ガラスっぽさ」「反射の気持ちよさ」を確認するためのモチーフとしてあえてシンプルな輪っかを使っています。

レスポンシブ対応について

画面の縦横比に応じて、

  • カメラの距離
  • 表示サイズ

を自動で調整しています。

そのため、

  • 横長のPC画面
  • 縦長のスマートフォン画面

どちらでも、文字や輪っかが切れずに自然なサイズで表示されます。

カスタムしやすいポイント

コード内を少し調整するだけで、次のような変更が可能です。

  • 表示する文字の内容
  • 輪っかのサイズや太さ
  • ガラスの透明感や反射の強さ
  • 回転スピード
  • 背景色

ファーストビュー演出や、ポートフォリオ・デモページの装飾としても使いやすい構成です。

注意点

  • 3D描画のため、古い端末では動作が重くなる場合があります
  • 背景演出向けのサンプルのため、UI用途には向いていません
  • 実案件で使う場合は、負荷や表示環境の確認をおすすめします