From 8ab262a13a3bbe743d89aedd88ac91d1d20fd3b6 Mon Sep 17 00:00:00 2001 From: Steven Lambert Date: Tue, 30 Jul 2019 08:03:45 -0600 Subject: [PATCH] feat(is-visible): add support for clip-path techniques (#1706) * feat(is-visible): add support for clip-path techniques * ignore phantom * skip test for IE11 * pass style to isCliped function --- lib/commons/dom/is-visible.js | 36 +++++++++++++++++++------- test/commons/dom/is-visible.js | 46 ++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/lib/commons/dom/is-visible.js b/lib/commons/dom/is-visible.js index ee15196e41..bd23b50eac 100644 --- a/lib/commons/dom/is-visible.js +++ b/lib/commons/dom/is-visible.js @@ -1,21 +1,39 @@ /* global dom */ +const clipRegex = /rect\s*\(([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px\s*\)/; +const clipPathRegex = /(\w+)\((\d+)/; /** - * Determines if an element is hidden with the clip rect technique + * Determines if an element is hidden with a clip or clip-path technique * @method isClipped * @memberof axe.commons.dom * @private - * @param {String} clip Computed property value of clip + * @param {CSSStyleDeclaration} style Computed style * @return {Boolean} */ -function isClipped(clip) { +function isClipped(style) { 'use strict'; - var matches = clip.match( - /rect\s*\(([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px\s*\)/ - ); - if (matches && matches.length === 5) { - return matches[3] - matches[1] <= 0 && matches[2] - matches[4] <= 0; + const matchesClip = style.getPropertyValue('clip').match(clipRegex); + const matchesClipPath = style + .getPropertyValue('clip-path') + .match(clipPathRegex); + if (matchesClip && matchesClip.length === 5) { + return ( + matchesClip[3] - matchesClip[1] <= 0 && + matchesClip[2] - matchesClip[4] <= 0 + ); + } + if (matchesClipPath) { + const type = matchesClipPath[1]; + const value = parseInt(matchesClipPath[2], 10); + + switch (type) { + case 'inset': + return value >= 50; + case 'circle': + return value === 0; + default: + } } return false; @@ -60,7 +78,7 @@ dom.isVisible = function(el, screenReader, recursed) { if ( style.getPropertyValue('display') === 'none' || ['STYLE', 'SCRIPT', 'NOSCRIPT', 'TEMPLATE'].includes(nodeName) || - (!screenReader && isClipped(style.getPropertyValue('clip'))) || + (!screenReader && isClipped(style)) || (!recursed && // visibility is only accurate on the first element (style.getPropertyValue('visibility') === 'hidden' || diff --git a/test/commons/dom/is-visible.js b/test/commons/dom/is-visible.js index 8f29b1ae55..346743872c 100644 --- a/test/commons/dom/is-visible.js +++ b/test/commons/dom/is-visible.js @@ -3,6 +3,7 @@ describe('dom.isVisible', function() { var fixture = document.getElementById('fixture'); var fixtureSetup = axe.testUtils.fixtureSetup; + var isIE11 = axe.testUtils.isIE11; var shadowSupported = axe.testUtils.shadowSupport.v1; var fakeNode = { nodeType: Node.ELEMENT_NODE, @@ -188,6 +189,33 @@ describe('dom.isVisible', function() { el = document.getElementById('target'); assert.isFalse(axe.commons.dom.isVisible(el)); }); + + // IE11 either only supports clip paths defined by url() or not at all, + // MDN and caniuse.com give different results... + (isIE11 || window.PHANTOMJS ? it.skip : it)( + 'should detect clip-path hidden text technique', + function() { + fixture.innerHTML = + '
Hi
'; + + var el = document.getElementById('target'); + assert.isFalse(axe.commons.dom.isVisible(el)); + } + ); + + (isIE11 || window.PHANTOMJS ? it.skip : it)( + 'should detect clip-path hidden text technique on parent', + function() { + fixture.innerHTML = + '
' + + '
Hi
' + + '
'; + + var el = document.getElementById('target'); + assert.isFalse(axe.commons.dom.isVisible(el)); + } + ); + (shadowSupported ? it : xit)( 'should correctly handle visible slotted elements', function() { @@ -411,5 +439,23 @@ describe('dom.isVisible', function() { el = document.getElementById('target'); assert.isTrue(axe.commons.dom.isVisible(el, true)); }); + + it('should detect clip-path hidden text technique', function() { + fixture.innerHTML = + '
Hi
'; + + var el = document.getElementById('target'); + assert.isTrue(axe.commons.dom.isVisible(el, true)); + }); + + it('should detect clip-path hidden text technique on parent', function() { + fixture.innerHTML = + '
' + + '
Hi
' + + '
'; + + var el = document.getElementById('target'); + assert.isTrue(axe.commons.dom.isVisible(el, true)); + }); }); });