Vue 2.7中Bootstrap 5 CSS与JS滚动逻辑冲突问题求助
问题:Vue2.7 + Bootstrap5.3 滚动动画异常(Chrome/Edge 114)
问题现象
- 在Vue2.7项目中引入Bootstrap5.3后,使用
vue-scrollto指令或自定义scrollToElement方法实现带时长和缓动的元素滚动时,出现异常:滚动先按设置时长缓慢启动,之后无缓动直接跳至目标元素。 - 注释掉main.js中的
import 'bootstrap/dist/css/bootstrap.css'后,滚动恢复正常。
排查结果
- 冲突仅来自Bootstrap CSS,禁用Bootstrap JS、BootstrapVue或自定义CSS均无改善,通过CDN引入Bootstrap也存在该问题。
- 仅Bootstrap4.6.2版本无此问题;该异常仅出现在Chrome和Edge 114版本,Firefox 114.0.1无异常。
代码示例
vue-scrollto使用示例
<button type="button" class="btn btn-secondary" v-scroll-to="'#scroll-test'">v-scroll-to</button>
或
<button type="button" class="btn btn-secondary" v-scroll-to="{ el: '#scroll-test', duration: 1000, easing: 'ease-in-out', offset: 0 }">v-scroll-to 2</button>
main.js相关代码
let Bootstrap = require('bootstrap') import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' import 'bootstrap/dist/css/bootstrap.css' // 注释此行后冲突消失 import 'bootstrap/dist/js/bootstrap.js' import 'bootstrap-vue/dist/bootstrap-vue.css' import '/public/media/css/layout.css'; import '/public/media/css/mobile.css'; import Vue from 'vue' import VueMeta from 'vue-meta' import App from './App.vue' import router from './router' import Vuex from 'vuex' import store from './store' import VueI18n from 'vue-i18n' Vue.use(Bootstrap) Vue.use(BootstrapVue) Vue.use(IconsPlugin) const VueScrollTo = require('vue-scrollto') Vue.use(VueScrollTo, { duration: 1000, easing: 'ease-in-out', offset: -50, })
自定义滚动mixin代码
export default { methods: { scrollToElement(element, duration) { let start = null; const target = element && element? element.getBoundingClientRect().top : 0; const firstPos = window.scrollY || document.documentElement.scrollTop; let pos = 0; (function() { var browser = ['ms', 'moz', 'webkit', 'o']; for(let x = 0, length = browser.length; x < length && !window.requestAnimationFrame; x++) { window.requestAnimationFrame = window[browser[x]+'RequestAnimationFrame']; window.cancelAnimationFrame = window[browser[x]+'CancelAnimationFrame'] || window[browser[x]+'CancelRequestAnimationFrame']; } }()); function showAnimation (timestamp) { if(!start) { start = timestamp || new Date().getTime(); } let elapsed = timestamp - start; let progress = elapsed / duration; const inOutQuad = function(n){ n *= 2; if (n < 1) return 0.5 * n * n; return - 0.5 * (--n * (n - 2) - 1); }; let easeInPercentage = +(inOutQuad(progress)).toFixed(2); pos = (target === 0)? (firstPos - (firstPos * easeInPercentage)) : (firstPos + (target * easeInPercentage)); window.scrollTo(0, pos); if(target !== 0 && pos >= (firstPos + target) || target === 0 && pos <= 0) { cancelAnimationFrame(start); if(element) { element.setAttribute("tabindex", -1); element.focus(); } pos = 0; } else { window.requestAnimationFrame(showAnimation); } } window.requestAnimationFrame(showAnimation); }, }, }
解决方案
方案1:覆盖Bootstrap的原生平滑滚动设置
Bootstrap5.3的CSS默认给html元素设置了scroll-behavior: smooth,这会导致Chrome/Edge 114中浏览器原生平滑滚动与自定义滚动动画冲突。在自定义CSS文件中添加以下代码覆盖该设置:
html, body { scroll-behavior: auto !important; }
方案2:临时禁用原生平滑滚动(针对自定义滚动方法)
如果需要保留Bootstrap的其他样式且方案1无效,可以在自定义滚动方法中临时禁用原生平滑滚动,完成后恢复:
修改scrollToElement方法:
scrollToElement(element, duration) { // 临时禁用原生平滑滚动 const originalHtmlScrollBehavior = document.documentElement.style.scrollBehavior; const originalBodyScrollBehavior = document.body.style.scrollBehavior; document.documentElement.style.scrollBehavior = 'auto'; document.body.style.scrollBehavior = 'auto'; let start = null; const target = element && element? element.getBoundingClientRect().top : 0; const firstPos = window.scrollY || document.documentElement.scrollTop; let pos = 0; // ... 原有的浏览器兼容代码 ... function showAnimation (timestamp) { // ... 原有的动画逻辑 ... if(target !== 0 && pos >= (firstPos + target) || target === 0 && pos <= 0) { cancelAnimationFrame(start); if(element) { element.setAttribute("tabindex", -1); element.focus(); } pos = 0; // 动画结束后恢复原生平滑滚动设置 document.documentElement.style.scrollBehavior = originalHtmlScrollBehavior; document.body.style.scrollBehavior = originalBodyScrollBehavior; } else { window.requestAnimationFrame(showAnimation); } } window.requestAnimationFrame(showAnimation); }
方案3:改用浏览器原生平滑滚动
如果可以接受原生平滑滚动的效果,直接移除vue-scrollto和自定义滚动mixin,使用锚点链接,并确保Bootstrap的scroll-behavior: smooth生效即可。
内容的提问来源于stack exchange,提问作者GUIJS
相关产品推荐
相关产品推荐

