弹窗Modal实现和有滚动条偏移解决方法
弹窗Modal实现和有滚动条偏移解决方法
弹窗也叫modal(模态)在网页设计中是一个常见的功能。实现方法也不会太复杂,可以通过css实现居中(bootstrap 的modal是使用靠上边距来实现),然后JS控制点击显示和消失。在弹窗中也许你会发现一个问题,就是当页面有滚动条时,点击弹窗可能需要隐藏滚动条,这时内容会变宽,本文来自于江水提供了三种解决方法,收益匪浅,感谢。
弹窗的实现原理和方法
弹窗通常就是两部分,一部分是半透明的背景遮罩,另一部分就是承载主体内容的区域。当点击某个按钮或者某个地方触发,将隐藏的遮罩和内容通过某种动画效果显示出来。然后点击内容中的关闭或者遮罩区域,就会将遮罩和内容通过某种动画效果隐藏起来。
所以,实现弹窗第一步,就是要写结构和CSS。
弹窗的html 结构和CSS
既然知道实现方法,一般的结构主要有下面两种(分情况使用):
第一种,将内容块独立出来,再声明一个.overlay 结构用来做背景遮罩。结构如下:
...这样的话,就可以为.overlay 结构设置半透明的背景
图片或者使用rgba 的背景,然后为.box-login 应用绝对居中的布局模式或者使用js 动态计算宽高或者位置。(当然,这种方法的兼容性IE8+ 特别在乎的,可以使用JS 来计算位置,以及用半透明的gif 图片当背景)。
这种结构的优势是,遮罩层可以被复用,任何需要弹窗的场景,都可以直接用overlay 这个遮罩层,twitter 等用的就是这种,也推荐这种。
具体代码直接看下面的用jsfiddle 做的Demo
第二种,将内容块包裹进.overlay 结构中。结构如下:...
这种结构更加独立一些与其他结构相区别,用JS 来控制也比较统一比较简单,也比较方便用JS 等插件生成。fancybox 就是生成这种结构来实现弹窗。
但是这里需要注意,由于内容块是被包裹在overlay 层的,所以要实现点击overlay 层取消弹窗的效果,需要在内容块中阻止单击或者其他有关事件的冒泡,这样在内容块中的操
作,就不会触发取消弹窗的效果了。
具体代码如下,或者打开Demo
通常还会为弹窗层中添加一个“关闭”按钮,点击关闭按钮就关掉当前弹窗,一般使用下面代码,因为还需要图标等,就不再上传图片做Demo 了:
$('.close-it').on('click',function(event) {
$(this).parents('.overlay').fadeOut(200,function(){
$(this).removeAttr('style');
});
});
还需要注意一个细节,在用jQuery 做动画的时候,尽量用回调函数清除jQuery 为其添加的style 属性,这样可以避免一些意外的问题,流过血的教训。
注意弹窗的内容
其实对于弹窗效果的内容块,初始的时候为其应用display: none; 是非常简单而合理的,但实际应用还会出现一些意外情况,你需要注意弹窗的内容。
前段时间的项目中,弹窗里面的内容比较复杂,有幻灯片、图表之类的插件,结果出现了问题,幻灯片和图表区域内容会出现错位、变形等情况。后来测试了一下发现了原因,因
为这些插件在初始化的时候,需要计算外框或者相关元素的尺寸位置等,如果你为其设置了display: none; 之后,插件初始化就获取不到正确的数据,就错位或者失效了。
所以使用display: none; 来隐藏弹窗也是需要分情况讨论的,有些情况下,使用z-index: -1; 的方式隐藏会更加合理,如果需要做动画,可以设置opacity 或者当页面加载完之后,相关插件已经获取相关结构的尺寸等之后,使用setTimeout 函数为其增加display: none; 相关的类也可以。
提升弹窗的用户体验
上面的弹窗还是比较基础和笼统的,一般来说,根据弹窗内容块的布局,还可以分两类:
弹窗后允许页面滚动
这种方式通常使用position: absolute; ,可以看看我做的这个Demo。主要用来应对弹窗内容很大很多的情况,超过了屏幕的宽高需要产生滚动条来方便浏览者查看。有一些图片弹窗插件使用这种方式,使用JS 动态计算弹窗内容块的位置,这样即便是内容块很大,也不会造成信息缺失。
但是居中往往需要JS 配合或者进行位置、尺寸处理,会稍微麻烦一些。
弹窗后不允许页面滚动
你可以通过为内容块设置position: fixed; 使其虽然滚动了,但内容块仍然居中显示,给人一种没有滚动的感觉,还是刚
刚的Demo 注释掉然后修改一下就可以看到。
也可以为html、body 标签设置overflow-y: hidden; 属性,使其滚动条消失,无法滚动。
通常来说,一般都要使用hidden 来隐藏滚动条禁止滚动,然后使用absolute 或者fixed 就看你自己的需求来选择。但是,对html 或body 设置overflow-y: hidden; 之后,由于滚动条没有了,宽度变宽,页面内容会整体偏移一点,虽然只是一点,但是很明显。这简直太影响用户体验了!!
去掉滚动条但是避免页面内容偏移
知乎上前段时间也提到了这个问题:如何禁止浏览器滚动条滚动,但是又不让它消失?。其中比较简单方便的就是TQ 学长的回答,但是实际测试并不完美,因为chrome 浏览器的滚动条是15px 像素宽,而firefox 浏览器是17px 像素。如果统一设置成17px 的话,chrome 等浏览器中显然还会偏移2px ,虽然尽力完善了,但还是有点小偏移,受不了。既然不同浏览器里面滚动条宽度不同,那可否先用JS 检测操作系统和浏览器,然后再根据判断的浏览器等设置不同的偏移量?大体思路是对的,但是方法是错的。检测操作系统和浏览器,要判断的情况太多,代码太过于复杂。于是这个问题就暂时放在这里了。
偶然刷twitter 的时候,触发弹窗效果的时候,偶然看到了他们也是采用这种方式隐藏滚动条并且保证不会偏移,经过
测试各个浏览器中效果完美。于是分析了一下他们的代码,下面是他们的函数:
function ScrollbarWidth() {
jquery滚动条滚动到底部this.calculateScrollbarWidth = function() {
if ($("#scrollbar-width").length > 0) return;
var a = $('').prependTo($("body")),
b = $('').appendTo(a),
c = a.width() - b.width();
a.remove(),
$("head").append(' pensate-for-scrollbar,
.modal-enabled, .modal-enabled .global-nav-inner, .profile-editing, .profile-editing .global-nav-inn er, .overlay-enabled, .overlay-enabled .global-nav-inner, .grid-enabled, .grid-enabled .global -nav-inner, .gallery-enabled, .gallery-enabled .global-nav-inner { margin-right: ' + c + "px } ")
}
}
精简一下主要代码就是
var a = $('').prependTo($("body")),
b = $('').appendTo(a),
c = a.width() - b.width();
a.remove();
$("head").append(' pensate-for-scrollbar{ margin-right:' + c + 'px } ');
大体意思就是新建了一个包裹的结构,然后两个宽度相减得到滚动条的宽度,然后输出到head 中。当有弹窗发生之后,就为html 标签赋予相应的类来margin-right 一下,避免滚动条消失引起的内容偏移。
Great!这才是正解,显然这两个结构需要赋予一定的CSS,目的要使.modal-measure-scrollbar 产生滚动条,而.inner
是不包括滚动条的全宽,他们的差值正好就是滚动条的宽度!
twitter 中对它们应用的样式如下:
.modal-measure-scrollbar{
position: absolute;
height: 100px;
width: 100px;
top: -300px;
left: -300px;
overflow: scroll;
z-index: 1000;
overflow-y: scroll;
}
.modal-measure-scrollbar .inner{
height: 200px;
}
不需要解释了吧。
后来又测试了fancybox 插件,它的方法更加简单通用,具体代码如下:
w1 = $(window).width();
H.addClass('fancybox-lock-test');
w2 = $(window).width();
H.removeClass('fancybox-lock-test');
$(".fancybox-margin{margin-right:" + (w2 - w1) + "px;}").appendTo("head");
其中H 变量是$('html') ,大意就是先检测现有宽度,然后再为html 增加一个类,再检测,然后复原去掉类得到滚动条宽度。大体想一下也可以知道.fancybox-lock-test 类的代码是这样的:
.fancybox-lock-test {
overflow-y: hidden !important;
}
这种方法更加巧妙简单,不需要创建临时的DOM 结构,所以强烈推荐在项目中使用这种方式判断。
此外,还有第三种方法,是来自QQ 空间的。QQ 空间的相册之类的,也是采用弹窗的,查看了一下他们的实现方式,就是使用的固定的17px 的偏移值,在其他浏览器中也是17px 像素。但是使用中很难看到内容的偏移,原因是背景遮罩层太黑了,透明度不高,所以很多细节就忽略掉了。如果你的背景遮罩不是很透明,显然也就不需要处理这了~

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。