Bootstrap
Bootstrap5
Dashboard
Admin
Widgets
Html
Template Bootstrap 5 de page produits 360 avec différents widgets et graphiques.
<!DOCTYPE html>
<html lang="fr" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="UTF-8" />
<meta name="copyright" content="AngularForAll" />
<meta name="author" content="AngularForAll" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Cache-Control" content="public, max-age=604800" />
<title>Product Detail 360 Bootstrap 5 01 | AngularForAll</title>
<!-- Bootstrap 5 + Icons -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Inter', sans-serif;
background: #f5f7fc;
color: #1e293b;
overflow-x: hidden;
}
/* Header */
.navbar-product {
background: white;
box-shadow: 0 4px 20px rgba(0,0,0,0.03);
padding: 1rem 2rem;
border-bottom: 1px solid rgba(0,0,0,0.05);
}
.breadcrumb {
margin: 0;
font-size: 0.9rem;
}
.breadcrumb a {
color: #64748b;
text-decoration: none;
}
/* Layout principal */
.product-main {
padding: 2rem 1.5rem;
max-width: 1400px;
margin: 0 auto;
}
/* Zone 3D */
.viewer-3d-container {
background: linear-gradient(145deg, #0f172a, #1e293b);
border-radius: 32px;
padding: 16px;
box-shadow: 0 25px 40px -12px rgba(0,0,0,0.3);
position: relative;
overflow: hidden;
margin-bottom: 20px;
}
#canvas-wrapper {
width: 100%;
aspect-ratio: 1 / 1;
border-radius: 24px;
overflow: hidden;
background: #0b1120;
box-shadow: inset 0 0 30px #00000040;
}
canvas {
display: block;
width: 100%;
height: 100%;
outline: none;
}
.viewer-badge {
position: absolute;
bottom: 30px;
left: 30px;
background: rgba(20,30,50,0.7);
backdrop-filter: blur(12px);
color: white;
padding: 6px 18px;
border-radius: 40px;
font-size: 0.8rem;
border: 1px solid rgba(255,255,255,0.2);
z-index: 5;
pointer-events: none;
}
.rotate-hint {
position: absolute;
bottom: 30px;
right: 30px;
background: rgba(0,0,0,0.4);
backdrop-filter: blur(8px);
color: #ccd6f6;
padding: 6px 16px;
border-radius: 30px;
font-size: 0.8rem;
z-index: 5;
pointer-events: none;
}
/* Infos produit */
.product-title {
font-size: 2.4rem;
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 0.25rem;
}
.product-sub {
color: #64748b;
font-weight: 400;
margin-bottom: 1rem;
}
.price {
font-size: 2.2rem;
font-weight: 700;
color: #0b1e33;
}
.old-price {
text-decoration: line-through;
color: #94a3b8;
font-size: 1.2rem;
margin-left: 12px;
}
.stock-badge {
background: #dcfce7;
color: #15803d;
padding: 4px 14px;
border-radius: 30px;
font-weight: 500;
font-size: 0.9rem;
display: inline-block;
}
.color-options {
display: flex;
gap: 16px;
margin: 20px 0;
}
.color-dot {
width: 40px;
height: 40px;
border-radius: 40px;
cursor: pointer;
border: 3px solid transparent;
transition: all 0.15s;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.color-dot.active {
border-color: #1e293b;
transform: scale(1.1);
box-shadow: 0 6px 14px rgba(0,0,0,0.2);
}
.color-dot:hover { transform: scale(1.05); }
.storage-select {
background: white;
border: 1px solid #e2e8f0;
border-radius: 16px;
padding: 12px 18px;
margin: 20px 0;
}
.btn-cart {
background: #0f172a;
color: white;
border: none;
padding: 16px 24px;
border-radius: 50px;
font-weight: 600;
font-size: 1.1rem;
width: 100%;
transition: 0.2s;
box-shadow: 0 10px 20px -5px rgba(15,23,42,0.3);
}
.btn-cart:hover {
background: #1e293b;
transform: translateY(-2px);
}
.btn-like {
background: white;
border: 1px solid #e2e8f0;
padding: 16px 20px;
border-radius: 50px;
font-weight: 500;
transition: 0.2s;
color: #475569;
}
.btn-like:hover {
background: #fee2e2;
border-color: #f87171;
color: #b91c1c;
}
.btn-like.active {
background: #fecaca;
border-color: #ef4444;
color: #b91c1c;
}
.description-box {
background: white;
border-radius: 24px;
padding: 24px;
margin-top: 24px;
box-shadow: 0 8px 24px rgba(0,0,0,0.04);
}
.feature-icon {
width: 48px;
height: 48px;
background: #eef2ff;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
color: #1e3a8a;
}
@media (max-width: 992px) {
.product-main { padding: 1rem; }
.product-title { font-size: 2rem; }
}
</style>
<!-- Three.js -->
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.128.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.128.0/examples/jsm/"
}
}
</script>
</head>
<body>
<!-- Navigation simple -->
<nav class="navbar-product d-flex align-items-center justify-content-between">
<div class="d-flex align-items-center gap-3">
<i aria-hidden="true" class="bi bi-phone" style="font-size: 1.8rem; color: #1e293b;"></i>
<span style="font-weight: 600; font-size: 1.4rem; letter-spacing: -0.5px;">Galaxy Neo</span>
</div>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">Accueil</a></li>
<li class="breadcrumb-item"><a href="#">Smartphones</a></li>
<li class="breadcrumb-item active" aria-current="page">Galaxy Neo 5G</li>
</ol>
</nav>
</nav>
<!-- Contenu principal -->
<div class="product-main">
<div class="row g-4">
<!-- COLONNE GAUCHE : Visualisation 3D -->
<div class="col-lg-7">
<div class="viewer-3d-container">
<div id="canvas-wrapper">
<canvas id="phone-canvas"></canvas>
</div>
<div class="viewer-badge">
<i aria-hidden="true" class="bi bi-badge-3d me-1"></i> Vue 360° · Drag & zoom
</div>
<div class="rotate-hint">
<i aria-hidden="true" class="bi bi-arrow-repeat me-1"></i> Faites glisser pour tourner
</div>
</div>
<!-- Miniatures / variantes (optionnelles) -->
<div class="d-flex gap-3 mt-3 justify-content-center">
<div class="text-center">
<div class="rounded-3 bg-white p-2 shadow-sm" style="width: 70px; height: 70px; cursor: pointer;" onclick="setPhoneColor(0x2c2c36)">
<div style="background: #2c2c36; width: 100%; height: 100%; border-radius: 12px;"></div>
</div>
<small class="mt-1 d-block">Graphite</small>
</div>
<div class="text-center">
<div class="rounded-3 bg-white p-2 shadow-sm" style="width: 70px; height: 70px; cursor: pointer;" onclick="setPhoneColor(0xc0b7a8)">
<div style="background: #c0b7a8; width: 100%; height: 100%; border-radius: 12px;"></div>
</div>
<small class="mt-1 d-block">Argent</small>
</div>
<div class="text-center">
<div class="rounded-3 bg-white p-2 shadow-sm" style="width: 70px; height: 70px; cursor: pointer;" onclick="setPhoneColor(0x4a6fa5)">
<div style="background: #4a6fa5; width: 100%; height: 100%; border-radius: 12px;"></div>
</div>
<small class="mt-1 d-block">Bleu Océan</small>
</div>
</div>
</div>
<!-- COLONNE DROITE : Infos, config, panier -->
<div class="col-lg-5">
<div class="ps-lg-3">
<h1 class="product-title">Galaxy Neo 5G</h1>
<div class="product-sub d-flex align-items-center gap-3">
<span><i aria-hidden="true" class="bi bi-star-fill text-warning me-1"></i> 4.8 (234 avis)</span>
<span><i aria-hidden="true" class="bi bi-chat me-1"></i> 128 questions</span>
</div>
<div class="d-flex align-items-baseline flex-wrap">
<span class="price">899 €</span>
<span class="old-price">999 €</span>
<span class="ms-3 stock-badge"><i aria-hidden="true" class="bi bi-check-circle me-1"></i> En stock</span>
</div>
<!-- Sélecteur de couleur -->
<div class="mt-4">
<label class="fw-semibold mb-2">Couleur</label>
<div class="color-options">
<div class="color-dot active" style="background: #2c2c36;" onclick="setPhoneColor(0x2c2c36); setActiveColor(this)"></div>
<div class="color-dot" style="background: #c0b7a8;" onclick="setPhoneColor(0xc0b7a8); setActiveColor(this)"></div>
<div class="color-dot" style="background: #4a6fa5;" onclick="setPhoneColor(0x4a6fa5); setActiveColor(this)"></div>
</div>
</div>
<!-- Stockage -->
<div class="storage-select d-flex justify-content-between align-items-center">
<span><i aria-hidden="true" class="bi bi-memory me-2"></i>Stockage</span>
<select class="form-select w-auto border-0 bg-transparent fw-semibold"
style="width: auto;" aria-label="Sélecteur">
<option selected>256 Go</option>
<option>512 Go (+120 €)</option>
<option>1 To (+280 €)</option>
</select>
</div>
<!-- Boutons actions -->
<div class="d-flex gap-3 mt-3">
<button class="btn-cart" onclick="addToCart()"><i aria-hidden="true" class="bi bi-cart-plus me-2"></i>Ajouter au panier</button>
<button class="btn-like" id="likeButton" onclick="toggleLike()"><i aria-hidden="true" class="bi bi-heart me-2"></i>Aimer</button>
</div>
<!-- Livraison / Retour -->
<div class="d-flex gap-4 mt-4 text-secondary small">
<span><i aria-hidden="true" class="bi bi-truck me-1"></i> Livraison gratuite</span>
<span><i aria-hidden="true" class="bi bi-arrow-return-left me-1"></i> Retour 30j</span>
<span><i aria-hidden="true" class="bi bi-shield-check me-1"></i> Garantie 2 ans</span>
</div>
<!-- Description -->
<div class="description-box">
<h5 class="fw-bold mb-3">Description</h5>
<p>Le Galaxy Neo 5G redéfinit les standards avec son écran AMOLED 6.7" 120Hz, son triple capteur photo 50MP et sa batterie longue durée. Design premium en titane, résistance à l'eau IP68.</p>
<hr class="my-3">
<div class="row g-3">
<div class="col-4 text-center">
<div class="feature-icon mx-auto mb-2"><i aria-hidden="true" class="bi bi-cpu fs-4"></i></div>
<small class="fw-semibold">Snapdragon 8 Gen 3</small>
</div>
<div class="col-4 text-center">
<div class="feature-icon mx-auto mb-2"><i aria-hidden="true" class="bi bi-battery-charging fs-4"></i></div>
<small class="fw-semibold">5000 mAh</small>
</div>
<div class="col-4 text-center">
<div class="feature-icon mx-auto mb-2"><i aria-hidden="true" class="bi bi-droplet-half fs-4"></i></div>
<small class="fw-semibold">IP68</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// --- Références globales pour changer couleur ---
let phoneBodyMaterial;
let scene, camera, renderer, controls;
let phoneGroup;
// Initialisation Three.js
const canvas = document.getElementById('phone-canvas');
function initThree() {
scene = new THREE.Scene();
scene.background = new THREE.Color('#0b1120');
camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(3, 2, 5);
renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: false });
renderer.setSize(canvas.clientWidth, canvas.clientHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.autoRotate = true;
controls.autoRotateSpeed = 1.5;
controls.enableZoom = true;
controls.enablePan = false;
controls.target.set(0, 0.5, 0);
controls.maxPolarAngle = Math.PI / 1.8;
controls.minDistance = 2.2;
controls.maxDistance = 7.0;
// Lumières
scene.add(new THREE.AmbientLight(0x404060, 0.55));
const mainLight = new THREE.DirectionalLight(0xfff5e6, 1.2);
mainLight.position.set(4, 6, 3);
mainLight.castShadow = true;
mainLight.receiveShadow = true;
mainLight.shadow.mapSize.width = 1024;
mainLight.shadow.mapSize.height = 1024;
scene.add(mainLight);
const fill1 = new THREE.PointLight(0x4466cc, 0.7);
fill1.position.set(-3, 2, 4);
scene.add(fill1);
const fill2 = new THREE.PointLight(0xccaa88, 0.5);
fill2.position.set(2, 1, -5);
scene.add(fill2);
// Sol réfléchissant
const planeGeo = new THREE.CircleGeometry(4, 20);
const planeMat = new THREE.MeshStandardMaterial({ color: 0x1a2332, roughness: 0.4, metalness: 0.1, side: THREE.DoubleSide });
const plane = new THREE.Mesh(planeGeo, planeMat);
plane.rotation.x = -Math.PI/2;
plane.position.y = -0.01;
plane.receiveShadow = true;
scene.add(plane);
// Grille
const grid = new THREE.GridHelper(6, 20, 0x88aaff, 0x334466);
grid.position.y = 0;
scene.add(grid);
// --- Construction du téléphone (identique à l'exemple précédent) ---
phoneGroup = new THREE.Group();
const bodyMat = new THREE.MeshStandardMaterial({ color: 0x2c2c36, roughness: 0.25, metalness: 0.4 });
phoneBodyMaterial = bodyMat;
const mainBody = new THREE.Mesh(new THREE.BoxGeometry(1.6, 3.2, 0.32), bodyMat);
mainBody.castShadow = true; mainBody.receiveShadow = true; mainBody.position.y = 0.5;
phoneGroup.add(mainBody);
const screenMat = new THREE.MeshStandardMaterial({ color: 0x0a0e14, roughness: 0.15, emissive: new THREE.Color(0x112233), emissiveIntensity: 0.3 });
const screen = new THREE.Mesh(new THREE.BoxGeometry(1.45, 2.95, 0.05), screenMat);
screen.castShadow = true; screen.position.set(0, 0.5, 0.165);
phoneGroup.add(screen);
const frameMat = new THREE.MeshStandardMaterial({ color: 0xccccdd, roughness: 0.2, metalness: 0.8 });
const frontFrame = new THREE.Mesh(new THREE.BoxGeometry(1.58, 3.18, 0.02), frameMat);
frontFrame.position.set(0, 0.5, 0.19);
phoneGroup.add(frontFrame);
// Caméras / détails (simplifié)
const camMod = new THREE.Mesh(new THREE.CylinderGeometry(0.25,0.25,0.04), new THREE.MeshStandardMaterial({color:0x333338}));
camMod.rotation.y = 0.3; camMod.position.set(0.3,1.35,-0.18); phoneGroup.add(camMod);
scene.add(phoneGroup);
// Redimensionnement
window.addEventListener('resize', () => {
const width = document.getElementById('canvas-wrapper').clientWidth;
const height = width; // carré
renderer.setSize(width, height);
camera.aspect = 1;
camera.updateProjectionMatrix();
});
// Lancer animation
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Ajuster taille initiale
setTimeout(() => {
const w = document.getElementById('canvas-wrapper').clientWidth;
renderer.setSize(w, w);
camera.aspect = 1;
camera.updateProjectionMatrix();
}, 10);
}
initThree();
// Fonction globale pour changer couleur
window.setPhoneColor = (hexColor) => {
if (phoneBodyMaterial) {
phoneBodyMaterial.color.setHex(hexColor);
}
};
window.setActiveColor = (element) => {
document.querySelectorAll('.color-dot').forEach(d => d.classList.remove('active'));
element.classList.add('active');
};
// Panier / like
window.addToCart = () => {
alert('📱 Galaxy Neo ajouté au panier !');
};
window.toggleLike = () => {
const btn = document.getElementById('likeButton');
btn.classList.toggle('active');
const icon = btn.querySelector('i');
if (btn.classList.contains('active')) {
icon.classList.remove('bi-heart');
icon.classList.add('bi-heart-fill');
btn.innerHTML = '<i aria-hidden="true" class="bi bi-heart-fill me-2"></i>Aimé';
} else {
icon.classList.remove('bi-heart-fill');
icon.classList.add('bi-heart');
btn.innerHTML = '<i aria-hidden="true" class="bi bi-heart me-2"></i>Aimer';
}
};
// Désactiver auto-rotate après interaction
canvas.addEventListener('mousedown', () => controls.autoRotate = false);
canvas.addEventListener('touchstart', () => controls.autoRotate = false);
let idleTimer;
window.addEventListener('mousemove', () => {
controls.autoRotate = false;
clearTimeout(idleTimer);
idleTimer = setTimeout(() => controls.autoRotate = true, 4000);
});
</script>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Télécharger le fichier source
Questions fréquentes
Template Bootstrap 5 de page produits 360 avec différents widgets et graphiques.
Oui. Le code de « Page produits 360 style 01 - Bootstrap 5 » est libre de réutilisation : copiez-collez le HTML/CSS/JS dans votre projet et adaptez-le à vos besoins. Il est fourni gratuitement sur AngularForAll.