Skip to content

Commit 8ab262a

Browse files
authored
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
1 parent e4a0081 commit 8ab262a

File tree

2 files changed

+73
-9
lines changed

2 files changed

+73
-9
lines changed

lib/commons/dom/is-visible.js

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,39 @@
11
/* global dom */
2+
const clipRegex = /rect\s*\(([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px\s*\)/;
3+
const clipPathRegex = /(\w+)\((\d+)/;
24

35
/**
4-
* Determines if an element is hidden with the clip rect technique
6+
* Determines if an element is hidden with a clip or clip-path technique
57
* @method isClipped
68
* @memberof axe.commons.dom
79
* @private
8-
* @param {String} clip Computed property value of clip
10+
* @param {CSSStyleDeclaration} style Computed style
911
* @return {Boolean}
1012
*/
11-
function isClipped(clip) {
13+
function isClipped(style) {
1214
'use strict';
1315

14-
var matches = clip.match(
15-
/rect\s*\(([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px,?\s*([0-9]+)px\s*\)/
16-
);
17-
if (matches && matches.length === 5) {
18-
return matches[3] - matches[1] <= 0 && matches[2] - matches[4] <= 0;
16+
const matchesClip = style.getPropertyValue('clip').match(clipRegex);
17+
const matchesClipPath = style
18+
.getPropertyValue('clip-path')
19+
.match(clipPathRegex);
20+
if (matchesClip && matchesClip.length === 5) {
21+
return (
22+
matchesClip[3] - matchesClip[1] <= 0 &&
23+
matchesClip[2] - matchesClip[4] <= 0
24+
);
25+
}
26+
if (matchesClipPath) {
27+
const type = matchesClipPath[1];
28+
const value = parseInt(matchesClipPath[2], 10);
29+
30+
switch (type) {
31+
case 'inset':
32+
return value >= 50;
33+
case 'circle':
34+
return value === 0;
35+
default:
36+
}
1937
}
2038

2139
return false;
@@ -60,7 +78,7 @@ dom.isVisible = function(el, screenReader, recursed) {
6078
if (
6179
style.getPropertyValue('display') === 'none' ||
6280
['STYLE', 'SCRIPT', 'NOSCRIPT', 'TEMPLATE'].includes(nodeName) ||
63-
(!screenReader && isClipped(style.getPropertyValue('clip'))) ||
81+
(!screenReader && isClipped(style)) ||
6482
(!recursed &&
6583
// visibility is only accurate on the first element
6684
(style.getPropertyValue('visibility') === 'hidden' ||

test/commons/dom/is-visible.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ describe('dom.isVisible', function() {
33

44
var fixture = document.getElementById('fixture');
55
var fixtureSetup = axe.testUtils.fixtureSetup;
6+
var isIE11 = axe.testUtils.isIE11;
67
var shadowSupported = axe.testUtils.shadowSupport.v1;
78
var fakeNode = {
89
nodeType: Node.ELEMENT_NODE,
@@ -188,6 +189,33 @@ describe('dom.isVisible', function() {
188189
el = document.getElementById('target');
189190
assert.isFalse(axe.commons.dom.isVisible(el));
190191
});
192+
193+
// IE11 either only supports clip paths defined by url() or not at all,
194+
// MDN and caniuse.com give different results...
195+
(isIE11 || window.PHANTOMJS ? it.skip : it)(
196+
'should detect clip-path hidden text technique',
197+
function() {
198+
fixture.innerHTML =
199+
'<div id="target" style="clip-path: inset(50%);">Hi</div>';
200+
201+
var el = document.getElementById('target');
202+
assert.isFalse(axe.commons.dom.isVisible(el));
203+
}
204+
);
205+
206+
(isIE11 || window.PHANTOMJS ? it.skip : it)(
207+
'should detect clip-path hidden text technique on parent',
208+
function() {
209+
fixture.innerHTML =
210+
'<div style="clip-path: circle(0%);">' +
211+
'<div id="target">Hi</div>' +
212+
'</div>';
213+
214+
var el = document.getElementById('target');
215+
assert.isFalse(axe.commons.dom.isVisible(el));
216+
}
217+
);
218+
191219
(shadowSupported ? it : xit)(
192220
'should correctly handle visible slotted elements',
193221
function() {
@@ -411,5 +439,23 @@ describe('dom.isVisible', function() {
411439
el = document.getElementById('target');
412440
assert.isTrue(axe.commons.dom.isVisible(el, true));
413441
});
442+
443+
it('should detect clip-path hidden text technique', function() {
444+
fixture.innerHTML =
445+
'<div id="target" style="clip-path: inset(50%);">Hi</div>';
446+
447+
var el = document.getElementById('target');
448+
assert.isTrue(axe.commons.dom.isVisible(el, true));
449+
});
450+
451+
it('should detect clip-path hidden text technique on parent', function() {
452+
fixture.innerHTML =
453+
'<div style="clip-path: circle(0%);">' +
454+
'<div id="target">Hi</div>' +
455+
'</div>';
456+
457+
var el = document.getElementById('target');
458+
assert.isTrue(axe.commons.dom.isVisible(el, true));
459+
});
414460
});
415461
});

0 commit comments

Comments
 (0)