:hover . For starters, iOS7, for example, will not respond to hover unless the element, or its parent, has clicked event handling. This is clearly seen here in this example: jsfiddle.net/H8EmG - you don’t see any underscores with your finger on the text. In this example, jsfiddle.net/H8EmG/1 “poking” with your finger in the text will lead to its underlining. An interesting fact - until we push another element, the text will sit under the hover ...alert('click') . This is because iOS understands that for :hover something is hidden, and tries not to break the behavior laid down by the author of the site.div that is hidden by default and is shown when you hover over the line. Implemented through :hoveroverflow: scroll enabled overflow: scrollclick (and alert ) you will not see how not to try to make a line.-webkit-overflow-scrolling: touch on the container of the label that really helped with the example from jsFiddle, but did not help with the real application.:hover replaced with a CSS class that “throws” in code, catching mouseenter / mouseleave ? This simple fix actually solves everything. Even begins to work "more fun" - no need to click twice. From the first click, we get both alert and checkbox: jsfiddle.net/822eG/10MutationObserver (which is in iOS 6-7), we monitor the insertion of link tags into the head document — we can afford it, because All styles we obviously connect using require.js and in Safari this is guaranteed to be a new linklink let's go over document.styleSheets and analyze them ...:hoverdisplay other than none and visibility other than visible:hover with. .hover (i.e., pseudo-class with a regular class) ...mouseenter / mouseleave for the found selector, more precisely for the part that is located before :hoverstyleSheet contains a collection of rules , in which the rules themselves lie. Each rule has the property selectorText which can be changed on the go. And also has a collection of style where firstly contains a set of properties specified in this style - they are stored as an "array". The style has .length , going through the length we get all the properties that are changed in this style. Secondly, the style contains the values ​​of the changed properties. At the index equal to the name of the property the value of the property is stored. .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' and style.display == 'block' .rules takes the lion's share of time. Perhaps WebKit initializes this property lazily and the first call initiates some deep parsing of styles into a set of objects. $(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 }); }); Source: https://habr.com/ru/post/212959/
All Articles