* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Arial', sans-serif;
}
.imgtip-container {
position: relative;
width: 100%;
aspect-ratio: 16 / 9;
background: url("https://coposports.com/wp-content/uploads/2026/08/ScreenShot_2026-08-13_104625_913-1.jpg") center / cover no-repeat;
overflow: hidden;
margin: 0 auto;
}
.imgtip-group {
position: absolute;
transform: translate(-50%, -50%);
z-index: 5;
}
.imgtip-group[data-pos="1"] {
top: 55%;
left: 52%;
}
.imgtip-group[data-pos="2"] {
top: 78%;
left: 52%;
}
.imgtip-group[data-pos="3"] {
top: 53%;
left: 30%;
}
.imgtip-group[data-pos="4"] {
top: 74%;
left: 68%
}
.imgtip-group:hover {
z-index: 99 !important;
}
.imgtip-point {
width: 18px;
height: 18px;
border-radius: 50%;
background: #f5a41c;
cursor: pointer;
transition: box-shadow 0.2s;
position: relative;
z-index: 6;
}
.imgtip-point::before,
.imgtip-point::after {
content: "";
position: absolute;
inset: -2px;
border-radius: 50%;
background: #f5a41c;
opacity: 0;
transform: scale(1);
pointer-events: none;
box-shadow: 0 0 0 0 rgba(245, 164, 28, 0.35);
}
.imgtip-point::before {
animation: ripple-1 1.8s ease-out infinite;
animation-delay: 0s;
}
.imgtip-point::after {
animation: ripple-1 1.8s ease-out infinite;
animation-delay: 0.9s;
}
@keyframes ripple-1 {
0% {
transform: scale(1);
opacity: 0.55;
box-shadow: 0 0 0 0 rgba(245, 164, 28, 0.35);
}
40% {
opacity: 0.25;
}
100% {
transform: scale(2.8);
opacity: 0;
box-shadow: 0 0 0 12px rgba(245, 164, 28, 0);
}
}
.imgtip-circle-preview {
position: absolute;
width: 130px;
height: 130px;
border-radius: 50%;
overflow: hidden;
pointer-events: none;
opacity: 0;
transform: scale(0.85);
transition: opacity 0.25s ease, transform 0.25s ease;
background: #eaeef3;
z-index: 10;
border: 3px solid #ffffff;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}
.imgtip-circle-preview img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.imgtip-text-desc {
position: absolute;
min-width: 220px;
max-width: 360px;
padding: 12px 18px;
background: rgba(255, 255, 255, 0.75);
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
color: #1f2a3a;
border-radius: 10px;
font-size: 14px;
line-height: 1.6;
pointer-events: none;
opacity: 0;
transform: translateY(6px);
transition: opacity 0.25s ease, transform 0.25s ease;
z-index: 11;
border: 1px solid rgba(255, 255, 255, 0.8);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
font-weight: 400;
letter-spacing: 0.01em;
width: 360px;
}
.imgtip-text-desc strong {
font-weight: 700;
display: block;
margin-bottom: 4px;
color: #0b1a2b;
font-size: 15px;
}
.imgtip-group:hover .imgtip-circle-preview {
opacity: 1;
transform: scale(1);
}
.imgtip-group:hover .imgtip-text-desc {
opacity: 1;
transform: translateY(0);
}
@media (max-width: 768px) {
.imgtip-circle-preview,
.imgtip-text-desc {
display: none;
}
.imgtip-point {
width: 24px;
height: 24px;
border-width: 2px;
}
}
@media (max-width: 600px) {
.imgtip-text-desc {
min-width: 140px;
max-width: 180px;
width: 180px;
font-size: 12px;
padding: 8px 14px;
}
.imgtip-circle-preview {
width: 100px;
height: 100px;
}
}
.imgtip-text-desc br {
display: none;
}
.imgtip-text-desc strong + br {
display: none;
}
Locking clasp
Simple, fast, cost-effective snap-fitassembly, no tools needed. Insert tosecurely fasten components together.
LVL Elastic Dual Keel
Uniform structure, high longitudinal strength, and good dimensional stability.
Engineered Hardwood Panel
Resistant to deformation and cracking, low expansion coefficient, and its moisture resistance is 8 times greater than that of solid wood flooring.
Hinge Fastener
Revolving axis in two sections connectedvia holes and pins, allows fan-shapedrotation, easy disassembly, ensuringconvenience and stability.
(function() {
const container = document.getElementById('imgtipContainer');
if (!container) return;
const groups = document.querySelectorAll('.imgtip-group');
const PADDING = 14;
const GAP = 10;
const TEXT_GAP = 16;
const DESC_HEIGHT = 0;
function getDescWidth(desc) {
const clone = desc.cloneNode(true);
clone.style.visibility = 'hidden';
clone.style.position = 'absolute';
clone.style.width = 'auto';
clone.style.maxWidth = '360px';
clone.style.minWidth = '220px';
clone.style.padding = '12px 18px';
clone.style.fontSize = '14px';
document.body.appendChild(clone);
let w = clone.offsetWidth;
document.body.removeChild(clone);
return Math.min(Math.max(w, 220), 360);
}
function overlaps(a, b) {
return !(
a.right = b.right ||
a.bottom = b.bottom
);
}
function positionFloaters(group) {
const containerRect = container.getBoundingClientRect();
const groupRect = group.getBoundingClientRect();
const preview = group.querySelector('.imgtip-circle-preview');
const desc = group.querySelector('.imgtip-text-desc');
if (!preview || !desc) return;
const previewSize = preview.offsetWidth || 130;
const descWidth = getDescWidth(desc);
desc.style.width = descWidth + 'px';
const descHeight = desc.offsetHeight || 80;
const pointX =
groupRect.left -
containerRect.left +
groupRect.width / 2;
const pointY =
groupRect.top -
containerRect.top +
groupRect.height / 2;
const cW = containerRect.width;
const cH = containerRect.height;
const candidates = [];
// 右侧
if (
pointX +
GAP +
previewSize +
TEXT_GAP +
descWidth =
PADDING
&&
pointY +
previewSize / 2 =
PADDING
&&
pointY -
previewSize / 2 >=
PADDING
&&
pointY +
previewSize / 2 =
PADDING
&&
pointX -
previewSize / 2 >=
PADDING
&&
pointX +
previewSize / 2 <=
cW - PADDING
) {
candidates.push('up');
}
// 下侧
if (
pointY +
GAP +
previewSize +
TEXT_GAP +
descHeight =
PADDING
&&
pointX +
previewSize / 2 0
? candidates[0]
: 'right';
let preTop = 0;
let preLeft = 0;
let descTop = 0;
let descLeft = 0;
switch (direction) {
case 'right':
preTop =
-previewSize / 2;
preLeft =
GAP;
descTop =
preTop + 8;
descLeft =
preLeft +
previewSize +
TEXT_GAP;
break;
case 'left':
preTop =
-previewSize / 2;
preLeft =
-previewSize -
GAP;
descTop =
preTop + 8;
descLeft =
preLeft -
descWidth -
TEXT_GAP;
break;
case 'up':
preTop =
-previewSize -
GAP;
preLeft =
-previewSize / 2;
descTop =
preTop -
descHeight -
TEXT_GAP;
descLeft =
preLeft +
previewSize / 2 -
descWidth / 2;
break;
case 'down':
preTop =
GAP;
preLeft =
-previewSize / 2;
descTop =
preTop +
previewSize +
TEXT_GAP;
descLeft =
preLeft +
previewSize / 2 -
descWidth / 2;
break;
}
function clamp(value, min, max) {
return Math.min(
Math.max(value, min),
max
);
}
const preMinX =
PADDING -
pointX;
const preMaxX =
cW -
PADDING -
previewSize -
pointX;
const preMinY =
PADDING -
pointY;
const preMaxY =
cH -
PADDING -
previewSize -
pointY;
preLeft =
clamp(
preLeft,
preMinX,
preMaxX
);
preTop =
clamp(
preTop,
preMinY,
preMaxY
);
const descMinX =
PADDING -
pointX;
const descMaxX =
cW -
PADDING -
descWidth -
pointX;
const descMinY =
PADDING -
pointY;
const descMaxY =
cH -
PADDING -
descHeight -
pointY;
descLeft =
clamp(
descLeft,
descMinX,
descMaxX
);
descTop =
clamp(
descTop,
descMinY,
descMaxY
);
const preRect = {
left:
pointX +
preLeft,
right:
pointX +
preLeft +
previewSize,
top:
pointY +
preTop,
bottom:
pointY +
preTop +
previewSize
};
const descRect = {
left:
pointX +
descLeft,
right:
pointX +
descLeft +
descWidth,
top:
pointY +
descTop,
bottom:
pointY +
descTop +
descHeight
};
if (overlaps(preRect, descRect)) {
// 右侧
if (
preRect.right +
TEXT_GAP +
descWidth =
PADDING
) {
descLeft =
preRect.left -
TEXT_GAP -
descWidth -
pointX;
// 下侧
} else if (
preRect.bottom +
TEXT_GAP +
descHeight =
PADDING
) {
descTop =
preRect.top -
TEXT_GAP -
descHeight -
pointY;
}
descLeft =
clamp(
descLeft,
descMinX,
descMaxX
);
descTop =
clamp(
descTop,
descMinY,
descMaxY
);
}
preview.style.top =
preTop + 'px';
preview.style.left =
preLeft + 'px';
desc.style.top =
descTop + 'px';
desc.style.left =
descLeft + 'px';
}
function refreshAllTips() {
groups.forEach(function(group) {
positionFloaters(group);
});
}
setTimeout(
refreshAllTips,
80
);
setTimeout(
refreshAllTips,
300
);
let resizeTimer;
window.addEventListener(
'resize',
function() {
clearTimeout(resizeTimer);
resizeTimer =
setTimeout(
refreshAllTips,
150
);
}
);
window.addEventListener(
'load',
function() {
setTimeout(
refreshAllTips,
200
);
setTimeout(
refreshAllTips,
600
);
}
);
window.repositionImgTips =
refreshAllTips;
})();