2012-10-29 85 views
11

我有一個腳本,當您將鼠標懸停在其上時,可以在縮覽圖上動態添加完整圖像。我還給出了完整的圖像CSS:懸停樣式,以使它們展開到更大的寬度(通常它們被限制在縮略圖的尺寸範圍內)。如果圖像快速加載或緩存,但是如果完整圖像需要很長時間才能加載,並且在加載時不移動鼠標,則此功能正常工作,但一旦出現圖像,它通常會保留在縮略圖寬度(非:懸停樣式),直到您再次移動鼠標。我在我嘗試過的所有瀏覽器中都看到了這種行爲。我想知道這是否是一個錯誤,以及是否有解決或解決此問題的方法。如何確保CSS:懸停適用於動態添加元素

可能值得注意的是,我也嘗試在Javascript中使用.on('mouseenter')做同樣的事情,並且遇到了同樣的問題。

由於問題的性質,可能很難重現,特別是如果您有快速連接。我選擇了來自維基百科的一張很大的照片來演示,但爲了使它工作,您可能必須將其更改爲特別大或來自緩慢域的內容。另外請注意,您可能必須清除緩存才能繼續重試。

如果仍然無法複製,則可以在致電anchor.show()之前向fullimage.load添加一個仿真延遲。

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

Updated JS Bin with 1.5-second delay added (Hopefully makes issue clearer)

再次重現該問題包括清除大圖像的緩存,然後將鼠標懸停在原始圖像上以初始加載大圖像,然後在加載時不移動鼠標。預期的行爲是大圖像在最終加載時適當地使用:hover僞類。問題我發現加載時間超過〜0.75秒的時間不會發生:直到您稍微鬆開鼠標爲止。

編輯:請參閱我對@ LucaFagioli的回答,瞭解我的用例的更多詳細信息。

編輯,續集:我以爲我已經這樣做了,但我只是試圖在Firefox中重現這個問題,我不能。也許這是一個Chrome錯誤?

+4

只是一個側面說明:不是使用.on(),而是使用.off()再次解除綁定,您可以使用.one()代替。見http://api.jquery.com/one/ – xec

+0

@xec,酷,謝謝你的提示! – jrajav

+0

建立了一個jsfiddle,人們會更清楚地看到你的問題 –

回答

7

只有當光標在元素上移動至少一個像素時,大多數瀏覽器纔會更新它們的hover狀態。當光標進入縮略圖的img時,它會應用hover並運行您的mouseenter處理程序。如果你保持光標不變,直到全尺寸的圖像加載,你的舊img(縮略圖)將保持hover狀態,新的不會得到它。

爲了使它在這些瀏覽器中工作,將hover僞類移動到CSS中的通用父元素;例如,enclose both imgs in a span

+0

再想一想,接受我自己的回答並不公平 - 這是解決方案的重要組成部分,我這個怪胎巨大的解釋並沒有太多補充。基本上,瀏覽器的工作方式,這是做這種效果的可靠方法。如果你想知道爲什麼會出現這種情況,請參閱下面的答案。 – jrajav

+0

這是一個非常整潔的解決方案,BTW。比我的更好,所以我已經更新了我的答案,指出了這一點。 –

+0

此解決方案不允許任何動畫。現在在專業環境中使用它是不可想象的。看到我的答案。 –

2

如果選擇器正確,CSS將應用於所有元素,動態或其他。這包括所有的僞類,並將在DOM更改中作爲屬性進行更改。

+2

什麼是「指針」? – xec

+1

他們當然應該,我同意。但是,我並沒有看到這一點,因爲我試圖詳細解釋。你能重現我的問題嗎? – jrajav

+1

你的意思是選擇器對不對? –

0

從你的問題的這部分:「如果圖像能夠快速加載能正常工作或緩存,但如果整個圖像需要很長的時間來加載雖然它加載你不移動鼠標,」

用JavaScript預先加載所有圖像是否值得?這可能允許所有圖像首先成功加載,並且對於連接速度較慢的用戶可能會更方便用戶。

+1

是的,我想到了這一點,但是這個腳本的目的是在可能有很多這些圖像的頁面上使用,並且即使該加載是異步完成的,它可能會帶來不必要的帶寬損耗,以加載幾兆字節可能無法使用的圖像。 – jrajav

0

你可以做這樣的事情:http://jsfiddle.net/jR5Ba/5/

綜上所述,附加在你面前的形象裝載佈局,然後附加包含具有​​回調刪除您裝載層的大圖像的股利。

由於時間不夠,上面的小提琴沒有被簡化和清理,但如果需要的話,我可以在明天繼續工作。

$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

這個答案也不直接解決我的問題。事實上,對於圖像本身來說,它不會對a:hover甚至是.on('mouseenter')做任何事情。此外,您的解決方案會導致大圖像以「大」尺寸顯着加載,這並不理想。它也隱藏了這個問題,因爲我的問題涉及在圖像加載完成後調用:hover或.on('mouseenter')以將其調整爲大尺寸;與你的,這是不需要的,因爲它已經在這樣的大小。 – jrajav

+0

你是對的,這不是一個驚人的小提琴。我用另一個更新了我的答案,我希望這可以幫助你找到解決問題的方法 – sdespont

+0

呃,那也不是很理想,因爲它會產生一個從0開始的動畫,而不是原始圖像的大小。另外,即使大圖像已經加載,加載動畫仍在排隊。儘管如此,這些細節都是細微的真正的問題是你是如何解決我的主要問題,答案似乎是你每次完全添加和刪除大圖像,而是依靠原始縮略圖的mouseenter。我不想爲了表現和視覺一致性而走這條路線,但是值得一試。最後,這仍然是一個解決方法。 – jrajav

0

不要讓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

我仍然看到這個JS的問題。另外,如果我沒有弄錯,圖像是否會被檢索到,直到它具有src屬性*和*它已被添加到DOM?順便說一句,我可能會問一個無法回答的問題 - 這可能是一個瀏覽器錯誤。抱歉!我很快就會發現。如果是這樣,我會發佈一個自我回答。 – jrajav

+0

正確,圖像不會開始檢索,直到IMG標記具有src屬性之後。不過,您的原始代碼在擁有src之前將IMG標記添加到了DOM。正因爲如此,它在檢索圖像之前發射了它的加載事件。通過對指令序列重新排序,加載事件(以及_show()_這個錨點)就會在檢索到圖像後發生。這適用於我的Chrome版本。 – joequincy

+0

你可以定義「完美的作品?」你說你可以用我發佈的原始jsbin重新生成我的問題 - 也就是加載頁面後的第一個鼠標懸停,然後不移動鼠標並等待大約2秒鐘,結果是:懸停未應用,較大保留在縮略圖寬度的圖像 - 但是用JS代替(jsbin版本12)的相同再現步驟導致:懸停應用?因爲那不是我所看到的。 – jrajav

0

我不是100%肯定,爲什麼: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

良好的洞察力,但走這條路線不會讓它成爲動畫。但是,如果不是動畫,則在兩張圖像之間進行切換要比縮放較大的圖像要好。感謝您的回答! – jrajav

+0

它實際上是通過使用JavaScript來添加類,避開使用的需要:懸停。請參閱http://jsbin.com/ifitep/48或http://jsbin.com/ifitep/49,其中添加了縮放效果(天空是極限!)。 –

1

[編輯:雖然我的解釋可能會感興趣,pozs' solution above是更好的,所以我建議使用,如果你能。]

hover僞類規範quite relaxed關於何時應該激活:

CSS沒有定義哪些元素可能處於上述狀態, 或狀態是如何進入和離開的。腳本可能會更改 元素是否對用戶事件做出反應,並且不同的設備和UA可能有不同的指向方式或 激活元素。

特別是,當您更新加載時錨點元素的可見性時,未激活它。

您可以輕鬆解決這個問題:將hover樣式複製到類中,攔截移動到最終將覆蓋的元素上的光標,並基於該元素添加或刪除您的類。

演示:JS Bin (based on your delayed example)

的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; 
}
0

我這樣做,它的工作對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:對不起,我的英文不好。

1

TL; DR:您不能依賴:hover應用於光標下方的動態添加元素。但是,純CSS和Javascript都有可用的解決方法。

我很喜歡喬丹灰色和posz的答案,我希望我可以獎勵他們兩個賞金。 Jordan Gray解決了這個問題:CSS規範在某種程度上是決定性的,並提供了(另一個)工作修復,仍然允許:懸停和其他CSS效果,如轉換,除了加載。 posz提供了一個更好的解決方案,避免了任何懸停事件的Javascript;我在這裏提供基本相同的解決方案,但是使用div而不是span。我決定授予他,但我認爲喬丹的投入是必不可少的。我添加並接受了我自己的答案,因爲我覺得有必要詳細闡述所有這些。 (編輯:改變了,我接受了posz')

Jordan引用了CSS2規範;我將轉而參考CSS3。據我所知,他們在這一點上沒有區別。

所討論的僞類是:懸停,指的是用戶使用指針設備指定的元素。「這種行爲的確切定義是故意留下來的,以允許不同類型的交互和媒體,這不幸意味着規範沒有解決像這樣的問題:」應該在指點設備下出現的新元素是否應用了這個僞類?「這是一個很難回答的問題,在大多數情況下,哪種答案會與用戶意圖一致?用戶與之交互的頁面的動態變化通常是持續用戶交互或準備的結果。 ,我會說是的,目前大多數瀏覽器似乎都認同,通常情況下,當你在光標下添加一個元素時:hover會立即被應用,你可以在這裏看到:The jsbin I originally posted.請注意,如果加載較大圖像有延遲,您可能需要刷新頁面才能使其正常工作,這是因爲我會考慮到。

現在,那裏也是類似的情況,用戶激活瀏覽器本身時,光標懸停在具有:hover規則的元素上;它應該適用於這種情況嗎?在這種情況下鼠標「懸停」不是直接用戶交互的結果。但是指針設備正在指定它,對吧?此外,鼠標的任何移動都將導致明確的交互。這是一個難以回答的問題,瀏覽器以不同的方式回答。當你激活它們時,Chrome和Firefox不會改變:懸停狀態,直到你移動鼠標(即使你點擊激活它們!)。另一方面,Internet Explorer一旦激活就會更新:懸停狀態。事實上,只要它是鼠標下的第一個可見窗口,即使它不是活動的,它也會更新它。你可以使用上面鏈接的jsbin自己看看。

但是,讓我們回到第一個案例,因爲那是我現在的問題出現的地方。在我的情況下,用戶沒有將鼠標移動一段很長的時間(超過一秒),並且一個元素直接添加到光標下。這可能更容易被認爲是用戶交互不明確的情況,以及僞類不應該被切換的情況。就我個人而言,我認爲它應該仍然適用。但是,大多數瀏覽器似乎並不同意我的觀點。當你第一次將鼠標懸停在圖像上,然後不要移動鼠標(這是我在我的問題中發佈的用於演示問題的那個,並且和第一個一樣,有一個簡單的懸停選擇器), :懸停類不是適用於當前的Chrome,Opera和IE。 (Safari也不適用它,但有趣的是,如果你繼續按下鍵盤上的按鍵,就會發生這種情況。)但是,在Firefox中,hover類立即應用。由於Chrome和Firefox是我最初測試的兩個,我認爲這是Chrome中的一個錯誤。但是,這個規範在這一點上或多或少地完全沉默。大多數實現都是這樣說的; Firefox和我說的是。

下面是the spec相關部分:

:hover僞類適用,而用戶指定用定點設備的元素,但並不必然激活它。例如,當光標(鼠標指針)懸停在元素生成的框上時,可視用戶代理可以應用此僞類。不支持交互媒體的用戶代理不必支持這個僞類。支持交互式媒體的一些相符的用戶代理可能不能支持這個僞類(例如,不檢測懸停的筆設備)。 「:活性」或「:盤旋」也是在該狀態

[...]

選擇器不如果一個元素的父是限定。

[...]

注意:如果「:懸停」狀態適用於某個元素,因爲它的孩子是通過定位設備指定,則有可能爲「:懸停」適用於一個元素不在指示設備下方。

因此!解決方法!正如幾個人在這個線程中熱烈地指出的那樣,Javascript和jQuery也爲此提供瞭解決方案,依靠'mouseover'和'mouseenter'DOM事件。在問這個問題之前和之後,我都自己探索了其中的一些解決方案。然而,這些都有自己的問題,它們的行爲略有不同,而且通常只涉及簡單地切換CSS類。此外,爲什麼使用Javascript,如果沒有必要?

我有興趣找到一個解決方案,使用:懸停,沒有別的,和this is it (jsbin)。而不是將鼠標懸停在要添加的元素上,而是將其放在包含該新元素的現有元素上,並佔用相同的物理空間;在這種情況下,一個包含縮略圖和新的較大圖像的div(當不懸停時,其大小與div和縮略圖相同)。這似乎與我的用例相當具體,但它可能通常使用與新元素大小相同的定位div來完成。

添加:我完成了這個答案後,pozs提供了基本上與上面相同的解決方案!

這個和其中一個完全Javascript解決方案之間的折衷辦法是有一個一次性使用的類,它將在添加新元素時有效地依賴Javascript/DOM懸停事件,然後刪除所有這些並依賴於:繼續前進。這是喬丹灰色提供的解決方案(Jsbin)

這兩種工作都適用於我嘗試的所有瀏覽器:Chrome,Firefox,Opera,Safari和Internet Explorer。