问题 如何确保CSS:hover应用于动态添加的元素
我有一个脚本,当您将鼠标悬停在缩略图上时,可以动态地添加完整图像。我还给出了完整的图像CSS:悬停样式,使它们扩展到更大的宽度(通常它们被约束到缩略图的尺寸)。如果图像快速加载或缓存,这可以正常工作,但是如果完整图像需要很长时间才能加载,并且在加载时不移动鼠标,那么一旦它出现,它通常会保持缩略图宽度(非:悬停样式),直到再次移动鼠标。我在所有我尝试过的浏览器中都会遇到这种情况。我想知道这是不是一个错误,如果有办法解决或解决它。
值得注意的是,我也尝试在Javascript中使用相同的功能 .on('mouseenter')
,并遇到了同样的问题。
由于问题的性质,可能很难重现,特别是如果您有快速连接。我从维基百科中选择了一张较大的照片进行演示,但要使其工作,您可能需要将其更改为特别大的或慢速域。另请注意,您可能必须清除缓存以进行连续重试。
如果仍然无法重现,可以添加一个人工延迟 fullimage.load
在打电话之前 anchor.show()
。
HTML:
<img id="image" src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Cairo_International_Stadium.jpg/220px-Cairo_International_Stadium.jpg" />
CSS:
.kiyuras-image {
position: absolute;
top: 8px;
left: 8px;
max-width: 220px;
}
.kiyuras-image:hover {
max-width: 400px;
}
JS:
$(function () {
var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';
var fullimage = $('<img/>')
.addClass('kiyuras-image')
.load(function () {
anchor.show();
});
var anchor = $('<a/>').hide().append(fullimage);
$('body').prepend(anchor);
$("#image").on('mouseenter', function () {
fullimage.attr('src',fullimageurl);
$(this).off('mouseenter');
});
});
JS Bin
更新了JS Bin,增加了1.5秒延迟(希望问题更清晰)
再次:重现问题涉及清除大图像的缓存,然后将鼠标悬停在原始图像上以初始加载大图像,然后在加载时不移动鼠标。预期的行为是大图像在最终加载时正确地采用:hover伪类。问题我看到加载时间超过~0.75秒的时间是它没有接受:悬停直到你稍微摇动鼠标。
编辑:有关我的用例的更多详细信息,请参阅我对@ LucaFagioli答案的评论。
编辑,续集:我以为我已经这样做了,但我只是试图在Firefox中重现这个问题而我不能。也许这是一个Chrome bug?
1148
2017-10-29 11:23
起源
答案:
大多数浏览器更新他们 hover
仅当光标在元素上移动至少一个像素时才处于状态。当光标进入缩略图时 img
它得到了 hover
申请并运行你的 mouseenter
处理程序。如果你将光标保持不动,直到加载完整尺寸的图像,那么你的光标就是旧的 img
(缩略图)将保留 hover
国家和新的不会得到它。
要让它在这些浏览器中运行,请移动 hover
伪类到CSS中的公共父元素;例如, 两者都包括在内 img
在一个 span
。
7
2017-11-06 20:41
如果选择器是正确的,CSS将应用于所有元素,动态或其他。这包括所有伪类,并将随着DOM中的属性的变化而变化。
2
2017-10-29 11:25
[编辑:虽然我的解释可能会引起关注, pozs上面的解决方案更好,所以如果可以,我建议使用它。]
该 hover
伪类规范是 很放松 关于什么时候应该激活:
CSS没有定义哪些元素可能处于上述状态,
或状态如何进入和离开。脚本可能会改变
元素是否对用户事件做出反应,并且不同
设备和UA可能有不同的指向方式,或
激活元素。
特别是,当您在加载时更新锚元素的可见性时,它不会被激活。
你可以很容易地解决这个问题:复制 hover
类的样式,拦截光标在最终将覆盖的元素上移动,并根据该元素添加或删除元素。
演示: JS Bin(基于您的延迟示例)。
使用Javascript:
$("#image")
.on('mouseenter', function () {
fullimage.attr('src',fullimageurl).toggleClass('mouseover',true);
$(this).off('mouseenter');
})
.mouseleave(function(){
fullimage.toggleClass('mouseover',false);
});
CSS:
.kiyuras-image:hover,.kiyuras-image.mouseover {
max-width: 400px;
}
1
2017-11-06 15:08
TL; DR:你不能依靠 :hover
应用于光标下方动态添加的元素。但是,纯CSS和Javascript都有可用的解决方法。
我赞同Jordan Gray和posz的答案,我希望我能给他们奖励。 Jordan Gray以一种有点结论的方式解决了这个问题:CSS规范并提供了(另一个)仍然允许的工作修复:悬停和其他CSS效果,如转换,除了加载。 posz提供了一个更好的解决方案,避免了任何悬停事件的Javascript;我在这里提供了基本相同的解决方案,但是使用div而不是span。我决定把它授予他,但我认为乔丹的投入是必不可少的。我正在添加并接受我自己的答案,因为我觉得有必要自己详细说明所有这些。 (编辑:改变了,我接受了posz')
Jordan引用了CSS2规范;我会转而使用CSS3。据我所知,他们在这一点上没有区别。
有问题的伪类是:hover,它指的是用户“使用指针设备指定”的元素。行为的确切定义是刻意留下的,以允许不同类型的交互和媒体,不幸的是,这意味着规范没有解决如下问题:“指针设备下面出现的新元素是否应用了这个伪类? “这是一个难以回答的问题。在大多数情况下,哪个答案将与用户意图一致?对用户正在与之交互的页面的动态改变通常是持续的用户交互或对其进行准备的结果。因此,我会说是,并且大多数当前的浏览器似乎都同意。通常,在光标下添加元素时:立即应用悬停。你可以在这里看到: 我最初发布的jsbin。 请注意,如果加载较大图像时出现延迟,您可能需要刷新页面才能使其正常工作,原因我将介绍。
现在,有一个类似的情况,用户激活浏览器本身,光标在具有:悬停规则的元素上保持静止;它应该适用于那种情况吗?在这种情况下,鼠标“悬停”不是直接用户交互的结果。但是指点设备正在指定它,对吧?此外,鼠标的任何移动肯定会导致明确的交互。这是一个难以回答的问题,浏览器会以不同的方式回答它。当您激活它们时,Chrome和Firefox不会更改:悬停状态直到您移动鼠标(即使您通过单击激活它们!)。另一方面,Internet Explorer更新:一旦激活就悬停状态。事实上,只要它是鼠标下的第一个可见窗口,即使它不活动,它也会更新它。您可以使用上面链接的jsbin自己查看。
让我们回到第一种情况,因为那是我当前问题出现的地方。在我的情况下,用户没有移动鼠标很长一段时间(超过一秒),并且直接在光标下添加一个元素。这可能更容易被认为是用户交互不明确的情况,以及不应该切换伪类的情况。就个人而言,我认为它仍应适用。但是,大多数浏览器似乎都不同意我的观点。当您第一次将鼠标悬停在图像上,然后不要移动鼠标 这个jsbin (我在我的问题中发布的那个用来演示问题的那个,和第一个一样,有一个简单的:悬停选择器),:hover类 不是 适用于当前的Chrome,Opera和IE。 (Safari也不会应用它,但有趣的是,如果你继续按下键盘上的键,它会发生。)但是在Firefox中,:hover类 是 立即申请。由于Chrome和Firefox是我最初测试的两个,我认为这是Chrome中的一个错误。但是,在这一点上,规范或多或少完全无声。大多数实现说不! Firefox和我说。
以下是相关部分 规范:
:hover伪类适用于用户使用指针设备指定元素,但不一定要激活它。例如,当光标(鼠标指针)悬停在元素生成的框上时,可视用户代理可以应用此伪类。不支持交互式媒体的用户代理不必支持此伪类。一些支持交互式媒体的符合要求的用户代理可能无法支持该伪类(例如,不检测悬停的笔设备)。
[...]
选择器不定义“:active”或“:hover”元素的父级是否也处于该状态。
[...]
注意:如果':hover'状态适用于元素,因为它的子节点由指针设备指定,则':hover'可以应用于不在指针设备下面的元素。
所以!关于解决方法!正如一些人在这个帖子中热切地指出的那样,Javascript和jQuery也为此提供了解决方案,依赖于'mouseover'和'mouseenter'DOM事件。在问这个问题之前和之后,我自己都探索了很多这样的解决方案。但是,它们有自己的问题,它们的行为略有不同,而且它们通常只涉及切换CSS类。此外,为什么使用Javascript,如果没有必要?
我有兴趣找到一个使用的解决方案:悬停,没有别的,和 这是它(jsbin)。我们不是将:悬停在要添加的元素上,而是将它放在包含该新元素的现有元素上,并占用相同的物理空间;在这种情况下,div包含缩略图和新的较大图像(当不悬停时,将与div和缩略图的大小相同)。这似乎对我的用例非常具体,但它通常可以使用与新元素大小相同的定位div来实现。
添加:在我完成这个答案后,pozs提供了与上面基本相同的解决方案!
这个和一个完整的Javascript解决方案之间的妥协是有一个一次性使用的类,它将有效地依赖Javascript / DOM悬停事件,同时添加新元素,然后删除所有这些并依赖于:hover继续。这是Jordan Gray提供的解决方案 (Jsbin)
这两种方法都适用于我尝试的所有浏览器:Chrome,Firefox,Opera,Safari和Internet Explorer。
1
2017-11-06 21:05
从你的问题的这一部分:“如果图像快速加载或缓存,这可以正常工作,但如果完整的图像加载需要很长时间,而且在加载时不移动鼠标,”
使用JavaScript首先“预加载”所有图像是否值得。这可以允许所有图像首先成功加载,并且对于具有较慢连接的人来说可能更加用户友好。
0
2017-10-29 11:30
你可以这样做: http://jsfiddle.net/jR5Ba/5/
总之,在图像前面附加一个加载布局,然后附加一个包含大图像的div .load()
回调以删除您的加载层。
由于时间不够,上面的小提琴没有被简化和清理,但如果需要,我可以继续在明天继续工作。
$imageContainer = $("#image-container");
$image = $('#image');
$imageContainer.on({
mouseenter: function (event) {
//Add a loading class
$imageContainer.addClass('loading');
$image.css('opacity',0.5);
//Insert div (for styling) containing large image
$(this).append('<div><img class="hidden large-image-container" id="'+this.id+'-large" src="'+fullimageurl+'" /></div>');
//Append large image load callback
$('#'+this.id+'-large').load(function() {
$imageContainer.removeClass('loading');
$image.css('opacity',1);
$(this).slideDown('slow');
//alert ("The image has loaded!");
});
},
mouseleave: function (event) {
//Remove loading class
$imageContainer.removeClass('loading');
//Remove div with large image
$('#'+this.id+'-large').remove();
$image.css('opacity',1);
}
});
编辑
这是小提琴的新版本,包括正确大小的加载图层,当显示大图片时带有动画: http://jsfiddle.net/jR5Ba/6/
希望它会有所帮助
0
2017-10-31 20:54
在有要下载的映像之前,不要让IMG标记添加到DOM。这样,在加载图像之前,Load事件不会触发。这是修改后的JS:
$(function () {
var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';
var fullimage = $('<img/>')
.addClass('kiyuras-image')
.load(function () {
anchor.show(); // Only happens after IMG src has loaded
});
var anchor = $('<a/>').hide();
$('body').prepend(anchor);
$("#image").on('mouseenter', function () {
fullimage.attr('src',fullimageurl); // IMG has source
$(this).off('mouseenter');
anchor.append(fullimage); // Append IMG to DOM now.
});
});
0
2017-11-02 22:52
我做到了,它适用于Chrome(版本22.0.1229.94米):
我改变了css:
.kiyuras-image{
position: absolute;
top: 8px;
left: 8px;
max-width: 400px;
}
.not-hovered{
max-width: 220px;
}
和脚本这样:
$(function(){
var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';
var fullimage = $('<img/>')
.addClass('kiyuras-image')
.load(function () {
anchor.show();
});
var anchor = $('<a/>').hide().append(fullimage);
$('body').prepend(anchor);
$('.kiyuras-image').on('mouseout',function(){
$(this).addClass('not-hovered');
});
$('.kiyuras-image').on('mouseover',function(){
$(this).removeClass('not-hovered');
});
$("#image").one('mouseover', function(){
fullimage.attr('src',fullimageurl);
});
});
基本上我认为这是检测/渲染'悬停'状态的Chrome错误;事实上,当我试图简单地将css更改为:
.kiyuras-image{
position: absolute;
top: 8px;
left: 8px;
max-width: 400px;
}
.kiyuras-image:not(:hover) {
position: absolute;
top: 8px;
left: 8px;
max-width: 220px;
}
它仍然没有奏效。
PS:对不起我的英语。
0
2017-11-06 15:59
我不是百分百肯定为什么 :hover
声明仅在轻微鼠标移动时触发。一个可能的原因可能是技术上你可能不是真的 徘徊 元素。基本上你是在加载光标时推动光标下的元素(直到大图像被完全加载 A
元素有 display: none
因此不可能在 :hover
州)。与此同时,这并不能解释与较小图像的差异......
所以,一个解决方法是只使用JavaScript并离开 :hover
声明之外的声明。只是向用户展示两种不同的用户 IMG
元素取决于悬停状态(在JavaScript中切换)。作为额外的优势,图像不必由浏览器动态地放大和缩小(Chrome中的视觉故障)。
看到 http://jsbin.com/ifitep/34/
UPDATE:通过使用JavaScript添加 .active
在大图像上,完全可以继续使用原生CSS动画。看到 http://jsbin.com/ifitep/48
0
2017-11-05 18:57