You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止移动端切换至桌面端断点时的CSS过渡动画触发

导航栏过渡动画问题修复方案

我用SASS和JavaScript实现了一个简易导航栏,整体效果达标,但存在两个亟待解决的问题:

  1. 页面加载时所有过渡动画都会自动触发。曾尝试用空<script>标签修复但无效,目前临时通过将CSS引入移至body标签内解决,但这并非最佳实践。
  2. 更严重的问题:每当视口宽度达到响应式断点时,移动端菜单或子菜单的显示/隐藏过渡动画会被意外触发。希望优先采用CSS方案解决,JavaScript方案也可接受,但需保证断点和过渡时长仍在CSS中定义。

HTML代码

<body>
    <link rel="stylesheet" href="assets/css/style.min.css">

    <nav class="
        navbar
        nav-bg-primary nav-bg-expanded-red nav-text-white
        nav-bg-desktop-secondary nav-text-desktop-purple
        submenu-bg-desktop-primary
        bs sticky-top"
    >
        <div class="container">
            <a href="#" class="nav-brand h1">Inc.</a>
            <ul class="nav-menu " id="navMenu1">
                <li class="nav-item subitems active">
                    <a href="#" class="nav-link">Products</a>
                    <ul class="nav-submenu submenu-bg-desktop-white bs-sm">
                        <li class="nav-subitem">
                           <div class="nav-link">Wormgear</div>
                        </li>
                        <li class="nav-subitem">
                            <div class="nav-link">Planetarygear</div>
                        </li>
                        <li class="nav-subitem">
                            <div class="nav-link">Spurgear</div>
                        </li>
                    </ul>
                </li>
                <li class="nav-item">
                    <a href="#" class="nav-link">Company</a>
                    <ul class="nav-submenu submenu-bg-desktop-info">
                        <li class="nav-subitem">
                            <div class="nav-link">About</div>
                        </li>
                        <li class="nav-subitem">
                            <div class="nav-link">Contact</div>
                        </li>
                        <li class="nav-subitem">
                            <div class="nav-link">Jobs</div>
                        </li>
                    </ul>
                </li>
                <li class="nav-item subitems">
                    <a href="#" class="nav-link">Service</a>
                    <ul class="nav-submenu text-white">
                        <li class="nav-subitem">
                            <div class="nav-link">FAQ</div>
                        </li>
                        <li class="nav-subitem active">
                            <div class="nav-link">Downloads</div>
                        </li>
                    </ul>
                </li>
            </ul>
            <div class="nav-desktop-only">
                <button class="btn-outlined-primary pt-05 pb-05 pl-1 pr-1">search...</button>
            </div>
            <div class="nav-hamburger" toggles="navMenu1">
                <span class="hamburger-bar"></span>
                <span class="hamburger-bar"></span>
                <span class="hamburger-bar"></span>
            </div>
        </div>
    </nav>
    
    <script src="assets/js/style.js"></script>
</body>

SCSS代码

// mobile first
.navbar {
    z-index: 9999;
    position: relative;
    display: flex;
    align-items: stretch;
    justify-content: space-between;

    .nav-desktop-only {
        display: none;
    }

    [class^=container]{
        padding: 0;
        position: relative;
        display: flex;
        align-items: stretch;
        box-sizing: border-box;
        justify-content: space-between;
    }

    ul {
        padding: 0;
        margin: 0;
        list-style-type: none;
    }

    .nav-brand {
        display: inline-block;
        font-size: $navbar-brand-font-size;
        text-decoration: none;
        white-space: nowrap;
        padding: $padding $padding * 2;
    }

    .nav-hamburger{
        padding-right: $padding;
        margin: auto 0;
    }

    .nav-menu {
        box-sizing: border-box;
        display: flex;
        flex-direction: row;
        justify-content: center;
        position: absolute;
        width: 100%;
        left: 0;
        top: 100%;
        border-radius: 0 0 $border-radius $border-radius;
        transform-origin: 50% 0;
        -webkit-transform: scaleY(0);
        -moz-transform: scaleY(0);
        -o-transform: scaleY(0);
        transform: scaleY(0);
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        padding-left: $padding * 2;
        padding-bottom: $padding;
        padding-top: $padding;
        -webkit-transition: -webkit-transform 0.1s;
        -moz-transition: -moz-transform 0.1s;
        -o-transition: -o-transform 0.1s;
        transition: transform 0.1s ease-in-out;

        &.expanded{
            -webkit-transform: scaleY(1);
            -moz-transform: scaleY(1);
            -o-transform: scaleY(1);
            transform: scaleY(1);
        }
        
        &.collapsed{
            -webkit-transform: scaleY(0);
            -moz-transform: scaleY(0);
            -o-transform: scaleY(0);
            transform: scaleY(0);
        }

        .nav-item{
            font-weight: $font-weight-bold;
            padding-bottom: $padding * 2;

            .nav-link {
                display: flex;
                align-items: center;
                height: 100%;
                cursor: pointer;
            }
        }

        .nav-submenu{
            box-shadow: none;
            display: block;
        }

        .nav-subitem{
            padding-bottom: $padding;
            padding-top: $padding;
            font-weight: $font-weight;
            opacity: $nav-text-opacity;
        }

    }

    // more or less padding
    &.nav-space-sm{
        .nav-brand{
            padding: $padding*0.5 $padding;
        }
        .nav-hamburger{
            padding-right: $padding * 0.5;
        }
        .nav-menu{
            padding-left: $padding;
            padding-bottom: $padding;
        }
        .nav-item{
            padding-bottom: $padding ;
        }
        .nav-subitem{
            padding-bottom: $padding * 0.5;
            padding-top: $padding * 0.5;
        }
    }

    &.nav-space-lg{
        .nav-brand{
            padding: $padding * 2 $padding * 4;
        }
        .nav-hamburger{
            padding-right: $padding * 2;
        }
        .nav-menu{
            padding-left: $padding * 4;
            padding-bottom: $padding * 4;
        }
        .nav-item{
            padding-bottom: $padding * 4;
        }
        .nav-subitem{
            padding-bottom: $padding * 1.5;
            padding-top: $padding * 1.5;
        }
    }

}

// color variations

@each $key, $val in $all-colors {

    .navbar.nav-bg-expanded-#{$key}{
        &.expanded{
            background-color: $val;
        }

        .nav-menu.expanded{
            background-color: $val;
        }
    }

    .navbar.nav-bg-#{$key}{
        background-color: $val;

        .nav-menu{
            background-color: $val;
        }
    }

    .navbar.nav-text-#{$key}{
        color: $val;

        .nav-hamburger .hamburger-bar{
            background-color: $val;
        }
    }

}

// desktop version

@media (min-width: $nav-toggle-breakpoint) {

    .navbar {

        .nav-desktop-only {
            display: flex;
            align-items: center;
            box-sizing: border-box;
        }

        .nav-mobile-only {
            display: none;
        }

        .navbar .nav-menu.nav-menu.collapsed{
            transform: scaleY(1);
            -webkit-transform: scaleY(1);
            -moz-transform: scaleY(1);
            -o-transform: scaleY(1);
        }

        .nav-hamburger {
            display: none;
        }

        .nav-menu{
            all: unset;
            flex-grow: 1;
            display: flex;
            flex-direction: row;
            align-items: stretch;
            justify-content: center;
            height: 100%;

            &.nav-menu.expanded {
                transform: unset;
                -webkit-transform: unset;
                -moz-transform: unset;
                -o-transform: unset;
                transition: none;
                -moz-transition: none;
                -webkit-transition: none;
                -o-transition: none;
            }

            &.nav-menu.collapsed {
                transform: unset;
                -webkit-transform: unset;
                -moz-transform: unset;
                -o-transform: unset;
                transition: none;
                -moz-transition: none;
                -webkit-transition: none;
                -o-transition: none;
            }

            .nav-item {
                font-weight: $font-weight;
                padding: 0 $padding;
                display: flex;
                align-items: center;
                box-sizing: border-box;
                border-bottom: 2px solid transparent;

                .nav-submenu {
                    //display: none;                //prototype
                    display: flex;                  //prototype
                    flex-direction: row;
                    justify-content: center;
                    position: absolute;
                    width: 100vw;
                    top: 100%;
                    //left: 50%;
                    left: calc(50% - 50vw);   //Prototyp
                    transform: unset;
                    -webkit-transform: unset;
                    -moz-transform: unset;
                    -o-transform: unset;
                    //transform: translateX(-50%);                  //prototype
                    //-webkit-transform: translateX(-50%);
                    //-moz-transform: translateX(-50%);
                    //-o-transform: translateX(-50%);
                    transform: scaleY(0);           //prototype
                    transition: transform 0.1s ease-in-out;          //prototype
                    transform-origin: 50% 0;                         //prototype

                    &.bs{
                        box-shadow: $box-shadow;
                    }

                    &.bs-sm{
                        box-shadow: $box-shadow-sm;
                    }

                    &.bs-lg{
                        box-shadow: $box-shadow-lg;
                    }

                    .nav-subitem{
                        padding: $padding $padding ;
                        border-bottom: 2px solid transparent;
                        
                        &:hover{
                            border-bottom-color: initial;
                        }
                    }
                }

                &.subitems:hover{
                    .nav-submenu{
                        display: flex;
                        transform: scaleY(1);           //prototype
                    }
                }
                

                &:hover{
                    border-bottom-color: initial;
                }

            }

            .nav-item .nav-submenu .nav-subitem.active{
                border-bottom-color: initial;
            }

            .nav-item{
                &.active{
                    border-bottom-color: initial;
                }
            }

        }

        // more or less padding
        &.nav-space-sm{
            .nav-item{
                padding: 0 $padding * 0.5;
            }
        }

        &.nav-space-lg{
            .nav-item{
                padding: 0 $padding * 2;
            }
        }
    }
}

JavaScript代码

document.body.addEventListener('click', (evt) => {
    if( evt.target.classList.contains('nav-hamburger') || evt.target.parentElement.classList.contains('nav-hamburger') ){
        const toggler = evt.target.classList.contains('nav-hamburger') ? evt.target : evt.target.parentElement
        const navbar = toggler.closest('.navbar')
        console.log(navbar)
        if(toggler.hasAttribute('toggles')){
            const menu = document.getElementById(toggler.getAttribute('toggles'))
            if(menu && !menu.classList.contains('expanded') && !menu.classList.contains('collapsed')){
                menu.classList.toggle('expanded')
                toggler.classList.toggle('expanded')
                navbar && navbar.classList.toggle('expanded')
            }else if(menu){
                menu.classList.toggle('collapsed')
                menu.classList.toggle('expanded')
                toggler.classList.toggle('expanded')
                navbar && navbar.classList.toggle('expanded')
            }
        }
    }

})

内容的提问来源于stack exchange,提问作者hilrol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 14:00:58