私にとって最も印象的な例は、疑似クラス
:hover
です。 たとえば、iOS7は、クリックイベントが要素またはその親に関連付けられていない限り、ホバーに応答しません。 これは、この例ではっきりとわかります。jsfiddle.net / H8EmG-テキストをいくつ指で突いても、アンダースコアは表示されません。 また、この例では、 jsfiddle.net / H8EmG / 1がテキストに指を「 突っ込む 」と下線が引かれます。 興味深い事実-別の要素に突入するまで、テキストはホバーの下に置かれます...
別の興味深い例は、ホバー要素の処理です: jsfiddle.net/ASRm9/1テキストをクリックしてみてください。 最初に、行内に「HOVER!」というテキストが表示されますが、2回目に押すとすでに
alert('click')
トリガーされ
alert('click')
。 これは、iOSが
:hover
が隠されていることを理解し、サイトの作成者が侵入した動作を中断させないようにするためです。
しかし、これまで説明できなかったこのようなバグに遭遇すると、それをローカライズするためにiPadでデバッグするのに1日以上かかりました...私にとっては、詳細、そして賢い方法が必要です。すぐに-猫の下で、してください...
突然、サービスの次の更新後、私の「プラットフォーム」の開発者である不快な問題が明らかになりました-iPadでは、サービスにあるほとんどすべての「テーブル」で単一の行を選択できません。 「クリック」は機能しません! 「テーブル」は単なる行と列ではないことに注意してください。 私たちの場合、これはノート、ソート、グループ化、フィルター、あらゆる種類の「はしご」が印刷されてPDFおよびExcelにエクスポートされた、かなり「リッチな」UI要素です。
問題を長く退屈にローカライズした後、私たちは同様の結果をもたらしたHTML + CSSの孤立したシンプルな部分を強調しました...
- HTMLテーブル、複数行、複数列
- 列の1つに「チェックボックス」があります-デフォルトでは非表示になっており、行にカーソルを合わせると表示される
div
です。 実装:hover
- 行を
click
します - テーブルがコンテナよりも大きい
- コンテナのサイズは固定されており、
overflow: scroll
有効になっていoverflow: scroll
次に例を示します。jsfiddle.net / 822eG / 4 。 テーブルの行をクリックしてみてください。 ホバーは機能しますが(「チェックボックス」が表示され
click
)、
click
(および
alert
)
alert
、線を
click
しないようにする方法は表示されません。
このテーマで、私はSOに投稿を開始しました)
-webkit-overflow-scrolling: touch
jsFiddleの例では実際には役立ちましたが、実際のアプリケーションでは役に立たなかったタブレットコンテナーを
-webkit-overflow-scrolling: touch
します。
この混乱について考える過程で、次の解決策が出てきました(SOに関する質問に対する私自身の答え)-どうすれば
:hover
、コードで「ラップ」され、
mouseenter
/
mouseleave
キャッチするCSSクラスに置き換えられますか? この簡単な修正は本当にすべてを解決します。 「楽しい」でさえ機能し始めます-これ以上ダブルクリックする必要はありません。 最初のプレスから、アラートと「チェックボックス」の両方を取得します: jsfiddle.net/822eG/10
より良い選択肢がないため、彼らはこれについて考え始めました...実際、非常に大きなコードベースがあります。 このプラットフォームに基づいた「プラットフォーム」コードと「アプリケーション」コードの両方がたくさんあります。 そして、誰が、誰が、どこで、いつ、どのような条件で使用したいのかを知っています。ホバーと、何かを隠したいのか、見せたいのか。 一般に、「すべてを単独で」持つ必要があり、平均的な開発者はiOSの問題について考えませんでした。
その結果、次のソリューションが得られました。
-
MutationObserver
(iOS 6-7で利用可能)を使用してhead
ドキュメントのhead
link
タグの挿入を監視します。 require.jsを使用して接続することがわかっているすべてのスタイル。Safariでは、これが新しいlink
ことが保証されています。 - 新しい
link
追加するときlink
document.styleSheets
を調べて分析します... - すべてのルールをソートし、その中にあるセレクター内のルールを見つけ
:hover
- そのようなセレクターのスタイルを見てみましょう。
display
none
と異なり、visible
visibility
がvisible
と異なるかどうかを確認しvisible
- ある場合は、セレクターを書き換えて、
.hover
を.hover
(つまり、通常のクラスを持つ擬似クラス)に置き換えます... - そして、デリゲートを介してボディに、見つかったセレクター、より正確には前にある部分に
mouseenter
/mouseleave
をmouseenter
:mouseleave
幸いなことに、それは非常に単純であることが判明しました...各
styleSheet
には
rules
コレクションが含まれ、これにはルール自体が含まれます。 各ルールには、外出先で変更できる
selectorText
プロパティがあります。 また、最初に、このスタイルで定義された一連のプロパティを含む
style
コレクションがあります。これらは「配列」として保存されます。
style
は
.length
、長さをソートして、このスタイルで変更されたすべてのプロパティを取得します。 次に、
style
には変更されたプロパティの値が含まれます。 プロパティの名前に等しいインデックスには、プロパティの値が格納されます。
つまり、たとえばCSSコードがある場合:
.myClass:hover .block, .myItem:hover .element { color: red; display: block; }
このルールには
selectorText == '.myClass:hover .block, .myItem:hover .element'
、
style.length == 2
、
style[0] == 'color'
、
style[1] == 'display'
、
style.color == 'red'
および
style.display == 'block'
それ以外はすべて技術の問題です...
残念ながら、ルールの主要なバイパスが(スタイルとリンクタグのボリュームで)すぐに機能しないことが判明しました...プロファイリングは、
rules
へのアクセスに時間がかかることを示しました。 おそらくWebKitはこのプロパティを遅延的に初期化し、最初の呼び出しでスタイルの深い解析を開始してオブジェクトのセットにします。
結果は次のとおりです。
$(document).ready(function(){ // , , if (!$ws._const.browser.isMobileSafari) { return; } var $body = $('body'); // function addPseudoHover() { this.classList.add('ws-pseudo-hover'); } // "" function removePseudoHover() { this.classList.remove('ws-pseudo-hover'); } // [].filter(...) function uniq(item, index, array) { return array.indexOf(item, index + 1) == -1; } function trimHoverBase(selector) { return selector.substr(0, selector.indexOf(':hover')).trim(); } function filterHoverSelectors(selector) { return selector.indexOf(':hover') != -1; } function createBodyDelegate(hoverSelector){ $body.delegate(hoverSelector, 'mouseenter', addPseudoHover); $body.delegate(hoverSelector, 'mouseleave', removePseudoHover); } function processMutationRecord(mutationRecord) { var needRefresh = false; if (mutationRecord.addedNodes) { for(var i = 0, l = mutationRecord.addedNodes.length; i < l; i++) { if (mutationRecord.addedNodes[i].nodeName == 'LINK') { needRefresh = true; break; } } } if (needRefresh) { checkStylesheetSetDebonuced(); // } } function checkStylesheetSet() { var allHoverSelectors = [], allRules = [], sheet, sheetCheckResult; for(var i = 0, l = document.styleSheets.length; i < l; i++) { sheet = document.styleSheets[i]; // , if (sheet.processed || sheet.rules.length === 0) { continue; } sheetCheckResult = checkCSSRuleSet(sheet); if (sheetCheckResult.rules.length > 0 && sheetCheckResult.selectors.length > 0) { Array.prototype.push.apply(allHoverSelectors, sheetCheckResult.selectors); Array.prototype.push.apply(allRules, sheetCheckResult.rules); } // sheet.processed = true; } // allRules.forEach(function(aRule){ aRule.selectorText = aRule.selectorText.replace(':hover', '.ws-pseudo-hover'); }); // , body allHoverSelectors.map(trimHoverBase).filter(uniq).forEach(createBodyDelegate); } var checkStylesheetSetDebonuced = checkStylesheetSet.debounce(420); function checkCSSRuleSet(sheet) { var result = { selectors: [], rules: [] }; for(var i = 0, l = sheet.rules.length; i < l; i++) { var rule = sheet.rules[i]; if (rule.styleSheet && rule.href /* instanceof CSSImportRule*/) { // @import checkCSSRuleSet(rule.styleSheet); } else if (rule.selectorText /* instanceof CSSStyleRule*/) { var hoverSelectors = getHoverSelectors(rule); if (hoverSelectors.length > 0) { if (checkStyles(rule)) { Array.prototype.push.apply(result.selectors, hoverSelectors); result.rules.push(rule); } } } } return result; } function checkStyles(rule) { for(var i = 0, l = rule.style.length; i < l; i++) { var styleItem = rule.style[i]; if (styleItem == 'display' && rule.style.display !== 'none') { return true; } if (styleItem == 'visibility' && rule.style.visibility !== 'hidden') { return true; } } return false; } function getHoverSelectors(rule) { return rule.selectorText.split(',').filter(filterHoverSelectors); } // head new MutationObserver(function(mutationRecords){ mutationRecords.forEach(processMutationRecord); }).observe(document.getElementsByTagName('head')[0], { childList: true }); });
いくつかのリンク:
- MutationObserverサポート-caniuse.com/#feat=mutationobserver
- 便利なclassListプロパティ-caniuse.com/#feat=classlist