:where(section.knd-arc-section, section.knd-arc-section *){ box-sizing: border-box; margin: 0; padding: 0; } section.knd-arc-section{ --ink: #243A34; --clay: #c9a95e; --clay-dark: #a9843a; padding: 64px 0; width: 100%; } .knd-arc-wrap{ width: 100%; max-width: 100%; position: relative; } .knd-arc-slider{ position: relative; width: 100%; height: 400px; overflow: hidden; cursor: grab; user-select: none; touch-action: pan-y; } .knd-arc-slider.is-dragging{ cursor: grabbing; } .knd-arc-track{ position: absolute; left: 0; top: 0; height: 100%; display: flex; align-items: stretch; gap: 24px; will-change: transform; } .knd-arc-item{ position: relative; flex: 0 0 auto; width: 300px; height: 100%; border-radius: 20px; overflow: hidden; box-shadow: 0 18px 45px rgba(0, 0, 0, 0.16); } .knd-arc-item a{ display: block; position: relative; width: 100%; height: 100%; text-decoration: none; } .knd-arc-item img{ display: block; width: 100%; height: 100%; object-fit: cover; -webkit-user-drag: none; pointer-events: none; } .knd-arc-overlay{ position: absolute; left: 0; right: 0; bottom: 0; padding: 24px 20px 22px; background: linear-gradient(to top, rgba(10,16,14,.96) 0%, rgba(10,16,14,.82) 45%, rgba(10,16,14,.35) 80%, rgba(10,16,14,0) 100%); pointer-events: none; } .knd-arc-overlay h4{ font-size: 18px; font-weight: 600; text-transform: uppercase; line-height: 1.3; margin-bottom: 8px; color: #FFFFFF; text-shadow: 0 1px 3px rgba(0,0,0,.55), 0 2px 14px rgba(0,0,0,.35); } .knd-arc-price{ display: flex; align-items: baseline; flex-wrap: wrap; gap: 7px; } .knd-arc-price .old{ font-size: 12px; color: #FFFFFF; opacity: .75; text-decoration: line-through; text-shadow: 0 1px 3px rgba(0,0,0,.5); } .knd-arc-price .sale{ font-size: 17px; font-weight: 700; color: var(--clay); text-shadow: 0 1px 3px rgba(0,0,0,.5); } .knd-arc-price .unit{ font-size: 12px; color: #FFFFFF; opacity: .9; text-shadow: 0 1px 3px rgba(0,0,0,.5); } /* Tablet */ @media (max-width: 991px){ .knd-arc-slider{ height: 320px; } .knd-arc-track{ gap: 18px; } .knd-arc-item{ width: 240px; border-radius: 16px; } .knd-arc-overlay h4{ font-size: 16px; } .knd-arc-price .sale{ font-size: 15px; } } /* Mobile */ @media (max-width: 767px){ .knd-arc-slider{ height: 260px; } .knd-arc-track{ gap: 14px; } .knd-arc-item{ width: 190px; border-radius: 14px; } .knd-arc-overlay{ padding: 14px 14px 16px; } .knd-arc-overlay h4{ font-size: 14px; margin-bottom: 5px; } .knd-arc-price .sale{ font-size: 14px; } .knd-arc-price .old, .knd-arc-price .unit{ font-size: 11px; } }
Bỏ qua để đến Nội dung

Du lịch

We are a team of passionate people whose goal is to improve everyone's life.

Chưa có bài blog nào

(function(){ function init(){ var sliders = document.querySelectorAll('.knd-arc-slider'); if (!sliders.length) return; sliders.forEach(function(slider){ var track = slider.querySelector('.knd-arc-track'); if (!track) return; var originalItems = Array.prototype.slice.call(track.children); var count = originalItems.length; if (!count) return; var EAGER_COUNT = 3; originalItems.forEach(function(item, idx){ var img = item.querySelector('img'); if (!img) return; img.decoding = 'async'; img.loading = idx < EAGER_COUNT ? 'eager' : 'lazy'; var tries = 0; img.addEventListener('error', function retry(){ if (tries++ >= 3) return; var base = img.getAttribute('src').replace(/([?&])_r=\d+&?/, ''); img.src = base + (base.indexOf('?') > -1 ? '&' : '?') + '_r=' + Date.now(); }); }); var speed = parseFloat(slider.dataset.speed || '40'); // px/giây var offsetX = 0; var oneSetWidth = 0; var isPointerDown = false; var isDragging = false; var dragStartX = 0; var dragStartOffset = 0; var activePointerId = null; var lastTs = null; var DRAG_THRESHOLD = 6; // px - vượt ngưỡng này mới tính là kéo, dưới ngưỡng coi là click/tap function clearClones(){ Array.prototype.slice.call(track.children).forEach(function(child){ if (originalItems.indexOf(child) === -1) child.remove(); }); } function measureSetWidth(){ var gap = parseFloat(getComputedStyle(track).columnGap || getComputedStyle(track).gap || 0); var w = 0; originalItems.forEach(function(item){ w += item.getBoundingClientRect().width + gap; }); return w; } function buildLoop(){ clearClones(); oneSetWidth = measureSetWidth(); if (oneSetWidth <= 0) return; var containerWidth = slider.getBoundingClientRect().width; var neededWidth = containerWidth * 2 + oneSetWidth; while (track.getBoundingClientRect().width < neededWidth){ originalItems.forEach(function(item){ track.appendChild(item.cloneNode(true)); }); } normalizeOffset(); track.style.transform = 'translateX(' + offsetX + 'px)'; } function normalizeOffset(){ if (oneSetWidth <= 0) return; while (offsetX <= -oneSetWidth) offsetX += oneSetWidth; while (offsetX > 0) offsetX -= oneSetWidth; } function animate(ts){ if (lastTs === null) lastTs = ts; var dt = (ts - lastTs) / 1000; lastTs = ts; if (!isDragging && oneSetWidth > 0){ offsetX -= speed * dt; normalizeOffset(); track.style.transform = 'translateX(' + offsetX + 'px)'; } requestAnimationFrame(animate); } /** * ĐÃ VÁ: trước đây gọi setPointerCapture() ngay khi vừa nhấn xuống, * khiến trình duyệt không gửi sự kiện "click" tới thẻ bên trong * nữa -> bấm vào ảnh không bao giờ chạy link. Giờ chỉ coi là "kéo" * (và chỉ setPointerCapture) sau khi con trỏ đã di chuyển vượt * ngưỡng DRAG_THRESHOLD; nhấn/chạm thường (không di chuyển) sẽ được * trình duyệt xử lý click bình thường, đi tới href của . */ function suppressNextClick(){ var handler = function(ev){ ev.preventDefault(); ev.stopPropagation(); }; slider.addEventListener('click', handler, { capture: true, once: true }); } function onPointerDown(e){ isPointerDown = true; isDragging = false; dragStartX = e.clientX; dragStartOffset = offsetX; activePointerId = e.pointerId != null ? e.pointerId : null; } function onPointerMove(e){ if (!isPointerDown) return; var deltaX = e.clientX - dragStartX; if (!isDragging){ if (Math.abs(deltaX) < DRAG_THRESHOLD) return; isDragging = true; slider.classList.add('is-dragging'); if (slider.setPointerCapture && activePointerId != null){ try { slider.setPointerCapture(activePointerId); } catch (err){} } } offsetX = dragStartOffset + deltaX; track.style.transform = 'translateX(' + offsetX + 'px)'; } function endDrag(){ if (!isPointerDown) return; isPointerDown = false; if (isDragging){ normalizeOffset(); isDragging = false; slider.classList.remove('is-dragging'); suppressNextClick(); // vừa kéo xong thì chặn click "ảo" phát sinh ngay sau đó } } slider.addEventListener('pointerdown', onPointerDown); slider.addEventListener('pointermove', onPointerMove); slider.addEventListener('pointerup', endDrag); slider.addEventListener('pointercancel', endDrag); slider.addEventListener('pointerleave', function(){ if (isPointerDown) endDrag(); }); slider.addEventListener('dragstart', function(e){ e.preventDefault(); }); var resizeTimer = null; window.addEventListener('resize', function(){ clearTimeout(resizeTimer); resizeTimer = setTimeout(buildLoop, 150); }); buildLoop(); requestAnimationFrame(animate); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();