Pageanchor 網頁錨點

網頁中的定位器,幫助瀏覽者快速跳轉至某個節點。

網頁錨點類型

適用平台:官網、網銀

pc版


M版

  • 使用情境:當產品說明頁(例如:官網L3)項目/分類大於一個時,則可使用
  • 預設底線:1px #ACACAC
  • Active時,底部線條會以企業色#00a19b與文字等寬呈現
  • 項目置左排列,若有按鈕則置右
  • 在M版上寬度受限時,則用淡化方式讓使用者知道還有其他項目

網頁錨點類型

SAMPLE


HTML


                                             
<nav class="subnav-sections">
    <ul class="subnav-menu row justify-content-between align-items-center">
        <div class="col-9 col-md-8 subnav-menu--contentLeft">
            <li class="subnav-menu-item"><a class="subnav-menu-item-link active"
                    href="#a1">熱門卡片</a></li>
            <li class="subnav-menu-item"><a class="subnav-menu-item-link"
                    href="#a2">世界卡/無限卡</a></li>
            <li class="subnav-menu-item"><a class="subnav-menu-item-link"
                    href="#a3">銀行卡</a></li>
            <li class="subnav-menu-item"><a class="subnav-menu-item-link"
                    href="#a4">聯名卡</a></li>
            <li class="subnav-menu-item"><a class="subnav-menu-item-link"
                    href="#a5">國民旅遊卡/政府採購卡</a></li>
            <li class="subnav-menu-item"><a class="subnav-menu-item-link"
                    href="#a6">簽帳金融卡</a></li>
            <div class="active-line"
                style="transform: translateX(15px); width: 96px;"></div>
        </div>
        <div class="col-lg-4 col-md-2 col-3 subnav-menu--contentRight">
            <div class="row d-flex btnWrapper">
                <a class="btnLine color-primary mx-2 clear" href="#">清除篩選</a>
                <a class="btn bg-primary mx-2" data-fancybox="cardFilter"
                    data-src="#cardFilter" href="javascript:;">篩選</a>
            </div>
        </div>
    </ul>
</nav>
                                               
                                                                                                                                          
複製

CSS


                                                 
:root {
--space: 1rem;
--border: 4px;
--page-width: 120ch;
--color-link: #595959;
--color-active: #00a19b;
--ease: cubic-bezier(0.23, 1, 0.32, 1);
--duration: 350ms;
--section-offset: 0;
}

.subnav-sections {
top: 0px;
width: 100%;
background-color: white;
-webkit-box-shadow: inset lightgrey 0 0px 0, rgba(0, 0, 0, 0.1) 0 1px 1px 0;
        box-shadow: inset lightgrey 0 0px 0, rgba(0, 0, 0, 0.1) 0 1px 1px 0;
}
@media (min-width: 1200px) {
.subnav-sections {
    top: 0;
}
}
.subnav-sections .subnav-menu {
max-width: 1200px;
margin: 0 auto;
list-style: none;
padding: 0;
}
.subnav-sections .subnav-menu .btn {
max-width: 8.5rem;
}
.subnav-sections .subnav-menu .btnLine {
max-width: 8.5rem;
}
.subnav-sections .subnav-menu--contentLeft {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: nowrap;
    flex-wrap: nowrap;
overflow: scroll;
-ms-scroll-chaining: none;
    overscroll-behavior: none;
scrollbar-width: none;
-ms-overflow-style: none;
max-width: var(--page-width);
-webkit-transform: translateZ(0);
        transform: translateZ(0);
-webkit-transition: -webkit-transform var(--ease) var(--duration);
transition: -webkit-transform var(--ease) var(--duration);
transition: transform var(--ease) var(--duration);
transition: transform var(--ease) var(--duration), -webkit-transform var(--ease) var(--duration);
}
@media (min-width: 576px) {
.subnav-sections .subnav-menu--contentLeft {
    margin: 0 auto;
}
}
@media (min-width: 992px) {
.subnav-sections .subnav-menu--contentLeft {
    margin: initial;
}
}
.subnav-sections .subnav-menu--contentLeft::-webkit-scrollbar {
display: none;
}
.subnav-sections .subnav-menu--contentLeft .subnav-menu-item-link {
display: block;
padding: 16px;
text-decoration: none;
white-space: nowrap;
color: #00a19b;
-webkit-transition: color var(--ease) var(--duration);
transition: color var(--ease) var(--duration);
}
.subnav-sections .subnav-menu--contentLeft .subnav-menu-item-link.active {
color: #00a19b;
}
.subnav-sections .subnav-menu--contentRight {
width: 100%;
}
.subnav-sections .subnav-menu--contentRight .btnWrapper {
-webkit-box-pack: end !important;
-ms-flex-pack: end !important;
justify-content: flex-end !important;
}
.subnav-sections .subnav-menu--contentRight .btn {
width: 150px;
height: auto;
padding: 4px 0;
position: relative;
}
@media (min-width: 992px) {
.subnav-sections .subnav-menu--contentRight .btn {
    height: auto;
}
}
.subnav-sections .subnav-menu--contentRight .btn::before {
content: "";
width: 20px;
height: 100%;
position: absolute;
left: -21px;
top: 0;
/* FF3.6-15 */
/* Chrome10-25,Safari5.1-6 */
background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), color-stop(52%, white), to(white));
background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, white 52%, white 100%);
/* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#00ffffff", endColorstr="#ffffff", GradientType=1);
/* IE6-9 */
background-size: 100% auto;
}
@media (min-width: 576px) {
.subnav-sections .subnav-menu--contentRight .btn {
    padding: 10px 0;
}
}
.subnav-sections .subnav-menu--contentRight .btnLine {
width: 150px;
height: auto;
position: relative;
display: none;
}
@media (min-width: 1200px) {
.subnav-sections .subnav-menu--contentRight .btnLine {
    padding: 12px 0;
    display: block;
}
}
.subnav-sections::before {
content: "";
width: 20px;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 1;
-webkit-transform: rotate(180deg);
        transform: rotate(180deg);
/* FF3.6-15 */
/* Chrome10-25,Safari5.1-6 */
background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), color-stop(52%, white), to(white));
background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, white 52%, white 100%);
/* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#00ffffff", endColorstr="#ffffff", GradientType=1);
/* IE6-9 */
background-size: 100% auto;
}

.active-line {
position: absolute;
bottom: 0;
left: 0;
height: 4px;
background-color: var(--color-active);
-webkit-transition: width var(--ease) var(--duration), -webkit-transform var(--ease) var(--duration);
transition: width var(--ease) var(--duration), -webkit-transform var(--ease) var(--duration);
transition: width var(--ease) var(--duration), transform var(--ease) var(--duration);
transition: width var(--ease) var(--duration), transform var(--ease) var(--duration), -webkit-transform var(--ease) var(--duration);
}

.placeholder-section {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
    -ms-flex-align: center;
        align-items: center;
-webkit-box-pack: center;
    -ms-flex-pack: center;
        justify-content: center;
text-align: center;
height: 50vh;
background-color: lightgray;
}

.subnav-sections::before {
content: "";
width: 20px;
height: 100%;
position: absolute;
right: 0;
top: 0;
z-index: 100;
background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), color-stop(70%, white), to(white));
background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, white 70%, white 100%);
background-size: 100% auto;
}
.subnav-sections::after {
content: "";
width: 20px;
height: 100%;
position: absolute;
left: 0px;
top: 0;
z-index: 100;
background: -webkit-gradient(linear, right top, left top, from(rgba(255, 255, 255, 0)), color-stop(70%, white), to(white));
background: linear-gradient(to left, rgba(255, 255, 255, 0) 0%, white 70%, white 100%);
background-size: 100% auto;
}
@media (min-width: 992px) {
.subnav-sections::after {
    display: none;
}
}
                                                      
                                             
                                          
複製

JS


                                                 
const sectionsContainer = document.querySelector('.page-sections');
const sections = document.querySelectorAll('.page-section');
const nav = document.querySelector('.subnav-sections');
const menu = nav.querySelector('.subnav-menu--contentLeft');
const links = nav.querySelectorAll('.subnav-menu-item-link');
const activeLine = nav.querySelector('.active-line');
const sectionOffset = nav.offsetHeight;
const activeClass = 'active';
let activeIndex = 0;
let isScrolling = true;
let userScroll = true;


//加上active
const setActiveClass = () => {
    links[activeIndex].classList.add(activeClass);
};

//移除active
const removeActiveClass = () => {
    links[activeIndex].classList.remove(activeClass);
};

//底線移動
const moveActiveLine = () => {
    const link = links[activeIndex];
    const linkX = link.getBoundingClientRect().x;
    const menuX = menu.getBoundingClientRect().x;

    // activeLine.style.transform = `translateX(${menu.scrollLeft - menuX + linkX}px)`;
    // activeLine.style.width = `${link.offsetWidth}px`;
};

//
const setMenuLeftPosition = position => {
    menu.scrollTo({
        left: position,
        behavior: 'smooth'
    });

};


//確認導覽列是否overflow
const checkMenuOverflow = () => {
    const activeLink = links[activeIndex].getBoundingClientRect();
    const offset = 200;
    if (Math.floor(activeLink.right) > window.innerWidth) {
        setMenuLeftPosition(menu.scrollLeft + activeLink.right - window.innerWidth + offset);
    } else if (activeLink.left < 0) {
        setMenuLeftPosition(menu.scrollLeft + activeLink.left - offset);
    }
};

//手動active選項
const handleActiveLinkUpdate = current => {
    removeActiveClass();
    activeIndex = current;
    checkMenuOverflow();
    setActiveClass();
    moveActiveLine();
};


const init = () => {
    setActiveClass();
    moveActiveLine(links[0]);
    document.documentElement.style.setProperty('--section-offset', sectionOffset);
};

links.forEach((link, index) => link.addEventListener('click', () => {
    userScroll = false;
    handleActiveLinkUpdate(index);
}));



//監聽位置
window.addEventListener("scroll", () => {
    const currentIndex = sectionsContainer.getBoundingClientRect().top < 0 ? findIndexEx() : 0;

    if (userScroll && currentIndex == -1) {
        handleActiveLinkUpdate(activeIndex);
    }
    else if (userScroll && activeIndex !== currentIndex) {
        handleActiveLinkUpdate(currentIndex);
    } else {
        window.clearTimeout(isScrolling);
        isScrolling = setTimeout(() => userScroll = true, 100);
    }

    function findIndexEx() {
        let index = [...sections].reverse().findIndex(section => window.scrollY >= section.offsetTop - sectionOffset * 2);
        return index == -1 ? -1 : sections.length - 1 - index;
    }
});

init();


const element = document.querySelector('.subnav-menu--contentLeft');

element.addEventListener('wheel', (event) => {
    event.preventDefault();

    element.scrollBy({
        left: event.deltaY < 0 ? -30 : 30,

    });
});
//# sourceURL=scrollspy.js

                                                 
                                                 
複製