如何阻止移动端切换至桌面端断点时的CSS过渡动画触发
导航栏过渡动画问题修复方案
我用SASS和JavaScript实现了一个简易导航栏,整体效果达标,但存在两个亟待解决的问题:
- 页面加载时所有过渡动画都会自动触发。曾尝试用空
<script>标签修复但无效,目前临时通过将CSS引入移至body标签内解决,但这并非最佳实践。 - 更严重的问题:每当视口宽度达到响应式断点时,移动端菜单或子菜单的显示/隐藏过渡动画会被意外触发。希望优先采用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
相关产品推荐
相关产品推荐

