ตัวอย่างโค้ด
สร้างเอฟเฟกต์ซูมภาพแบบ "Loupe" (แว่นขยาย) เมื่อ hover เมาส์บนภาพ ภาพขยายจะแสดงใน container ข้างเคียง
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Image Zoom</title>
<style>
* { box-sizing: border-box; }
body { font-family: 'Segoe UI', sans-serif; padding: 20px; }
.img-zoom-container {
position: relative;
display: inline-block;
max-width: 100%;
}
.img-zoom-container img {
max-width: 100%;
height: auto;
display: block;
}
/* แว่นขยาย (Lens) */
.img-zoom-lens {
position: absolute;
border: 2px solid #d4d4d4;
width: 100px;
height: 100px;
border-radius: 50%;
cursor: crosshair;
pointer-events: none; /* ให้ event ผ่านไปยังรูปภาพ */
display: none;
box-shadow: 0 0 0 9999px rgba(0,0,0,0.3); /* มืดบริเวณนอก */
}
/* ภาพผลลัพธ์ (Zoomed Result) */
.img-zoom-result {
display: inline-block;
border: 1px solid #d4d4d4;
width: 400px;
height: 400px;
background-repeat: no-repeat;
background-size: cover;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
border-radius: 8px;
margin-left: 20px;
vertical-align: top;
}
@media (max-width: 900px) {
.img-zoom-result {
width: 100%;
height: 300px;
margin-left: 0;
margin-top: 20px;
}
}
</style>
</head>
<body>
<h1>Image Zoom แบบ Hover (Loupe Effect)</h1>
<p>วางเมาส์บนภาพด้านซ้ายเพื่อดูภาพขยายทางขวา</p>
<div class="img-zoom-container">
<img class="myimage" src="https://picsum.photos/id/1015/600/400" alt="Sample Image">
<div class="img-zoom-result" id="zoomResult"></div>
</div>
<script>
const imgEle = document.querySelector('.myimage');
const resultEle = document.getElementById('zoomResult');
enlargeImage(imgEle, resultEle);
function enlargeImage(imgEle, resultEle) {
let zoomLens, xRatio, yRatio;
// สร้าง lens element
zoomLens = document.createElement('DIV');
zoomLens.className = 'img-zoom-lens';
imgEle.parentElement.insertBefore(zoomLens, imgEle);
// คำนวณอัตราส่วนการขยาย
function updateRatios() {
// รอให้รูปโหลดเสร็จ
if (imgEle.naturalWidth === 0) {
imgEle.addEventListener('load', updateRatios, { once: true });
return;
}
xRatio = resultEle.offsetWidth / zoomLens.offsetWidth;
yRatio = resultEle.offsetHeight / zoomLens.offsetHeight;
resultEle.style.backgroundImage = `url('${imgEle.src}')`;
resultEle.style.backgroundSize = `${imgEle.naturalWidth * xRatio}px ${imgEle.naturalHeight * yRatio}px`;
}
updateRatios();
// Event listeners
imgEle.addEventListener('mousemove', moveLens);
imgEle.addEventListener('touchmove', moveLens);
imgEle.addEventListener('mouseenter', () => zoomLens.style.display = 'block');
imgEle.addEventListener('mouseleave', () => {
zoomLens.style.display = 'none';
resultEle.style.backgroundPosition = 'center center';
});
function moveLens(e) {
e.preventDefault();
const pos = getCursorPos(e);
let x = pos.x - zoomLens.offsetWidth / 2;
let y = pos.y - zoomLens.offsetHeight / 2;
// จำกัดขอบเขต
x = Math.max(0, Math.min(x, imgEle.offsetWidth - zoomLens.offsetWidth));
y = Math.max(0, Math.min(y, imgEle.offsetHeight - zoomLens.offsetHeight));
zoomLens.style.left = x + 'px';
zoomLens.style.top = y + 'px';
// อัพเดท background-position ของผลลัพธ์
resultEle.style.backgroundPosition = `-${x * xRatio}px -${y * yRatio}px`;
}
function getCursorPos(e) {
const rect = imgEle.getBoundingClientRect();
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
const clientY = e.touches ? e.touches[0].clientY : e.clientY;
return {
x: clientX - rect.left - window.pageXOffset,
y: clientY - rect.top - window.pageYOffset
};
}
}
</script>
</body>
</html>
การทำงาน
- เมื่อ hover บนภาพ → แสดงวงกลม "แว่นขยาย" (Lens)
- เลื่อนเมาส์ → Lens ตามไปพร้อมอัพเดทภาพขยายใน container ข้างเคียง
- รองรับ Touch events สำหรับมือถือ/แท็บเล็ต
- Responsive: บนจอเล็ก ภาพขยายจะอยู่ด้านล่างแทน
หลักการทำงาน (Logic)
- คำนวณ Ratio:
xRatio = resultWidth / lensWidth- บอกว่า 1px ของ lens เท่ากับกี่ px ของภาพจริง - ตำแหน่ง Lens: ตามเมาส์ ลบครึ่งขนาด lens เพื่อให้เมาส์อยู่กึ่งกลาง
- Clamp ขอบเขต: ไม่ให้ lens ออกนอกขอบภาพ
- Background Position:
-x * xRatio, -y * yRatioเลื่อนพื้นหลังภาพขยาย
แนวทางปรับปรุง
- เพิ่ม
loading="lazy"ให้รูปภาพ - ใช้
IntersectionObserverเริ่มทำงานเฉพาะเมื่อ scroll มาเห็น - เพิ่มปุ่ม toggle zoom on/off
- รองรับ pinch-to-zoom บนมือถือ
- เพิ่ม gallery หลายรูป (click เปลี่ยนรูป)
CSS-only Alternative (Simple)
.zoom-container:hover img { transform: scale(2); }
.zoom-container { overflow: hidden; }
วิธีนี้ง่ายกว่าแต่ไม่มี "loupe" แยกต่างหาก