/* ========== PAGE TRANSITION ========== */ .w-page-transition { position: fixed; inset: 0; pointer-events: none; overflow: hidden; z-index: -9999; } /* --- Dark layer --- */ .w-page-transition-dark { position: absolute; height: 100vh; inset: 0; background: var(--bg-dark, #000); display: flex; align-items: center; justify-content: center; gap: 20px; opacity: 0; transition: opacity 0.8s cubic-bezier(0.77, 0, 0.175, 1); z-index: 1; } .w-page-transition-dark.active { opacity: 1; } /* --- Dark - Logo wrapper --- */ .w-page-transition-dark__logo-wrapper { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) translateY(50%); display: flex; flex-direction: row; justify-content: center; gap: 20px; opacity: 0; transition: transform 0.8s ease, opacity 0.8s ease; z-index: 2; } .w-page-transition-dark__logo-wrapper.active { transform: translate(-50%, -50%) translateY(0); opacity: 1; } .w-page-transition-dark__text { color: var(--text-title-contrast, #fff); font-size: clamp(32px, 4vw, 100px); } .w-page-transition-dark__favicon { opacity: 0; width: 80px; height: 80px; } /* --- Light layer --- */ .w-page-transition-light { position: absolute; height: 100vh; inset: 0; background: var(--bg-body, #fff); display: flex; align-items: center; justify-content: center; transform: translateY(100%); transition: transform 1s cubic-bezier(0.77, 0, 0.175, 1); z-index: 3; } .w-page-transition-light.active { transform: translateY(0); } /* --- Light - Logo wrapper --- */ .w-page-transition-light__logo-wrapper { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) translateY(0); display: flex; flex-direction: row; justify-content: center; gap: 20px; opacity: 0; transition: opacity 0.6s ease 0.3s, transform 0.6s ease 0.3s; z-index: 4; } .w-page-transition-light__logo-wrapper.active { opacity: 1; transform: translate(-50%, -50%) translateY(0); } .w-page-transition-light__text { color: var(--text-title, #000); font-size: clamp(32px, 4vw, 100px); } .w-page-transition-light__favicon { width: 80px; height: 80px; opacity: 0; transform: scale(0) rotate(-90deg); transition: all 0.6s ease 0.3s; } .w-page-transition-light__favicon.appear { opacity: 1; transform: scale(1) rotate(0); }
document.addEventListener("DOMContentLoaded", () => { const dark = document.querySelector(".w-page-transition-dark"); const darkWrapper = document.querySelector(".w-page-transition-dark__logo-wrapper"); const light = document.querySelector(".w-page-transition-light"); const lightWrapper = document.querySelector(".w-page-transition-light__logo-wrapper"); const favicon = document.querySelector(".w-page-transition-light__favicon"); const pageTransition = document.querySelector(".w-page-transition"); if (!dark || !light || !pageTransition) return; /** Helper delay */ function wait(ms) { return new Promise((res) => setTimeout(res, ms)); } /** PAGE LEAVE (trước khi chuyển trang) **/ function startLeave() { pageTransition.style.zIndex = "9999"; dark.classList.add("active"); } /** PAGE ENTER (hiệu ứng khi vào trang) **/ async function startEnter() { // Luôn đảm bảo z-index cao khi bắt đầu pageTransition.style.zIndex = "9999"; // Step 1: Dark layer fade in dark.classList.add("active"); await wait(600); // Step 2: Logo/text dark xuất hiện darkWrapper.classList.add("active"); await wait(800); // Step 3: Light layer trượt lên light.classList.add("active"); lightWrapper.classList.add("active"); await wait(1000); // Step 4: Logo favicon hiện ra favicon.classList.add("appear"); await wait(1200); // Step 5: Toàn bộ transition fade out nhanh pageTransition.style.transition = "opacity 0.6s ease"; pageTransition.style.opacity = "0"; await wait(1200); // Step 6: Reset trạng thái cho lần sau dark.classList.remove("active"); darkWrapper.classList.remove("active"); light.classList.remove("active"); lightWrapper.classList.remove("active"); favicon.classList.remove("appear"); // Reset style sau khi đã ẩn hẳn pageTransition.style.opacity = ""; pageTransition.style.transition = ""; // Đưa z-index xuống thấp để không che nội dung pageTransition.style.zIndex = "-9999"; } /** Run on initial load **/ startEnter(); /** Trigger transition khi click link **/ document.querySelectorAll("a[href]").forEach((link) => { link.addEventListener("click", (e) => { const url = link.href; if ( url.includes("#") || url.startsWith("mailto:") || url.startsWith("tel:") || link.target === "_blank" ) return; e.preventDefault(); startLeave(); setTimeout(() => { window.location.href = url; }, 600); }); }); });