WCAG states that an element that has focus should always be visible to the user. This is especially hard, if not impossible in a chat window where space is limited.
When a keyboard or screen reader user tabs to the first button option and selects it, the content scrolls and button is no longer visible, breaking the "focus always visible" WCAG rule. Also if there is more than one button in the list the focus stays on the button and if they continue to tab, the window will scroll to where the focus is set. This is disorienting, and one can argue that when selecting a button the other options are not relevant, since new options are now available.
Example: https://recordit.co/2jDDvqg98J
One option is to stop scrolling when reaching the button so that the button is visible. But I feel that this is not a good experience and a compromise to comply with the WCAG rule. I have done some research and all conversational UI, with no exception, scroll to the bottom when new content is printed in the chat. If I deviate in the manner above to keep within WCAG I am breaking Jakobs Law.
Another option is to remove the focus from the selected button to the input field or the firs button in the next/new list of available buttons. But I feel that this will for blind users removes all points of reference.
Are there any other options or designs that you can think of to solve this in an accessible way?
Your example is someway too complicated.
Let's take a standard HTML page : if you focus an element with the keyboard, you are still able to scroll the page using the mouse (without modifying the keyboard cursor), and make the element disapear from the viewport. This does not invalidate any WCAG criteria.
Pressing a char key on a textarea will make it visually focused again. For a button or a link, that would require tab then shifttab, to make the button visible and focused again.
Visual focus and keyboard focus are two distinct things, but if keyboard focus impacts the visual focus, that does not reciprocate
The problem you might have is not a problem with the focus, but more a problem with Time limits.
Don't scroll if the user is not at the bottom of the window,
Don't scroll if an action has been performed during last N seconds, or wait P seconds if no other action is performed before scrolling.
Indicate that new messages have been received if the windows if not scrolling.
I think that Slack has a good implementation of the "do not scroll and indicate new messages" if you are not at the bottom.
Not a full answer
This is too large a question to answer in full, there are hundreds of things to consider and with just a GIF to see the behaviour I can only generalise.
Focus off screen
You have taken WCAG to the absolute letter and a little too far. The intention of this point is that when I change focus the focused item is visible on the screen.
If I scroll a web page you cannot expect focused items to stay on the page (otherwise no page in the world would be compliant if it was longer than a screen length!).
As long as when I focus the next item it scrolls into view and has a focus indicator I can see (correct contrast, not colour dependent) you are WCAG AAA rated on this point!
Auto scrolling content
This is where things get 'murky'. In your example content is added to a chat box and so the currently focused item scrolls off the screen.
Now if we move the focus to the latest options (buttons that appear) we have a problem that it may interrupt the flow of the screen reader and so they don't hear all the previous information and have to go back and listen again.
If we don't move the focus you have the problem you described where I press Tab (for example) and the page jumps back up before the content I just listened to.
Assuming we didn't have any other options this would still be preferable (not managing focus), but we do have options.
Time for some workarounds.
This is where accessibility gets fun, we need to find a few workarounds as there is no established pattern here.
I would argue that the biggest problem here is once the new text is spoken we jump back to the top of the page when we press Tab or other focus shortcuts.
One workaround for this would be to create a special div that gets focused the second i choose an option.
This div would have tabindex="-1" so it is not accessible via keyboard (only programatically).
The second I select an option we focus this div and then start inserting text.
That way when I press the <kbd>Tab</kbd> or shortcut for the next button it jumps to the first new option.
I have created a rudimentary fiddle below, it would need some improvement but gives you a pattern to test against / work with. (go full screen or you may not see the added buttons etc.)
var hasLoadedMore = 0;
$('.loadMore').on('click', function(e){
if(hasLoadedMore == 0){ //just a horrible hack to simluate content only loading once when you click an option.
console.log("option chosen");
$('#focusAdjuster').attr('aria-hidden', false);
$('#focusAdjuster').focus();
console.log("focus adjusted");
loadContent();
}
});
function loadContent(){
///ugly way of simulating the content being added dynamically.
$('#chat').append('<p>additional text</p>');
$('#chat').append('<p>more text</p>');
setTimeout(function(){
$('#chat').append('<p>more text</p>');
$('#chat').append('<button>Option 1 new</button>');
$('#chat').append('<button>Option 2 new</button>');
}, 500);
hasLoadedMore = 1;
}
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap; /* added line */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chat">
<p>initial text</p>
<button class="loadMore">Option 1</button>
<button class="loadMore">Option 2</button>
<button class="loadMore">Option 3</button>
<div tabindex="-1" aria-hidden="true" id="focusAdjuster" class="visually-hidden">loading</div>
</div>
Explanation of fiddle
So they key points are the visually-hidden <div> and the accompanying line in the JavaScript that focuses that div before loading more content.
The div lets us change the focus after clicking a button. I also added 'loading' to the text inside that div to add an additional purpose as your application will be AJAX powered.
The div has tabindex="-1" so it cannot receive focus. I also added aria-hidden="true" to this and toggle this off when an option button is clicked, just before giving it focus.
I would toggle this back when focus leaves this div in the real world but I wasn't doing that in a quick demo fiddle.
Doesn't this 'fail' WCAG?
Yup! In this example I made a non-focusable item focusable and it has no action. I still think this is preferable to making it a <button> as that implies it has an action. It obviously isn't perfect.
However the key part of WCAG is the 'G' - they are Guidelines. The way I am suggesting is a 'hack' or a compromise based on the fact that I am realistic about development time and tech limitations.
The 'proper' way you can do the above without the div is with some careful focus management. With unlimited time and budget I would definitely do that.
But given that you don't have to only think about the Tab key with screen readers (you can navigate by links, buttons, headings, sections etc.) that becomes a nightmare when trying to intercept key strokes and so the above is the simplest way I could think to do this.
Alternative pattern.
Because the previous example 'fails' WCAG there is another option, however I would argue this is worse and introduces lots of problems.
Replace the text within the div with new text each time.
The down side is that you would need to provide 'previous item' buttons each time and track them, the plus side is this would be WCAG compliant (although I would argue not as usable even though you 'pass' the criteria.)
Also providing those 'previous' buttons introduces a number of problems with focus management again (when do we make them visible, do they get the focus, do they add more confusion?).
Think of it like a form wizard pattern, each set of questions is a 'step', so you can go back to previous steps, and you can only see the current step on screen.
I included this as this pattern could be expanded with some thought and to give the OP / other people some ideas, do NOT use it as it is
var hasLoadedMore = 0;
var optionChosen = "";
$('.loadMore').on('click', function(e){
if(hasLoadedMore == 0){ //just a horrible hack to simluate content only loading once when you click an option.
optionChosen = $(this).text();
console.log("option chosen", optionChosen);
loadContent();
}
});
function loadContent(){
$('#chat').html('<button class="previousQuestion">You chose ' + optionChosen + '<span class="visually-hidden">(click here to go back and chose a different option)</span></button>');
$('#chat').append('<h3>' + optionChosen + '</h3>');
///ugly way of simulating the content being added dynamically.
$('#chat').append('<p>additional text</p>');
$('#chat').append('<p>more text</p>');
setTimeout(function(){
$('#chat').append('<p>more text</p>');
$('#chat').append('<button>Option 1 new</button>');
$('#chat').append('<button>Option 2 new</button>');
}, 500);
hasLoadedMore = 1;
$('.previousQuestion').on('click', function(){
console.log("now you would restore the previous question");
});
}
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap; /* added line */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chat">
<p>initial text</p>
<button class="loadMore">Option 1</button>
<button class="loadMore">Option 2</button>
<button class="loadMore">Option 3</button>
<div tabindex="-1" aria-hidden="true" id="focusAdjuster" class="visually-hidden">loading</div>
</div>
Related
If I have a 3 buttons on a page, and choosing one causes them to be hidden, and then show another div containing some form elements, I want to correctly notify the new content added shown. My understanding is dynamic content changes such as showing a region need to be handled properly in terms of WCAG. Is there a standard way to handle this in terms of aria/html?
I've tried aria-live, since it's often suggested for this scenario, on the outer div of the new region, but even with aria-live="polite" I get undesirable side affects. Let's say the region shown contains a small form. When focus moves to a text field, and I begin typing, I got the odd behavior that JAWS will repeatedly start reading the label again and again for each single keystroke as the user types characters in the input. If I remove the aria-live attribute on the parent div, then tab through the form the label is only read once on field focus, and is not read again as the user is typing.
I.e. it seems the parent having an aria-live is causing child elements like labels to get read more aggressively, even though the region being shown is a one time change, and there's no dynamic changes after that point.
This odd behavior seems to imply that aria-live is better suited for small isolated elements such as errors/alerts being added to the page, rather than large regions.
Should I be using a role instead?
<form role="form" action="/submit" method="post">
<div hidden id="section1" aria-live="polite">
<h2>Form Header</h2>
<div>
<label for="RequestNumber">Request Number*</label>
<input id="RequestNumber" name="RequestNumber" type="text" />
</div>
</div>
</form>
The golden rule - don't use ARIA unless all other options have been exhausted.
What you actually want to do here is simply manage focus.
When you click one of the 3 buttons I assume a different form is shown. 99% of Screen Readers can handle this no problem (and for the ones that can't they are used with no JavaScript so make sure your website works without it if possible.)
When you click the buttons, hide them (if you have an animation then use aria-hidden, otherwise just display:none will do) and then when the new form is shown simply focus the form using JavaScript.
The screen reader will take care of the rest.
It may be advisable to add some visually hidden text on the buttons to inform the user that the buttons disappear and a form appears - just make sure you provide a way for them to go back to the buttons in case they made the wrong choice.
Visually Hidden Class For Reference
Use the below CSS to hide an inline span within the button if you feel it is appropriate information a screen reader may need.
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap; /* added line */
}
This sounds like a case of simple progressive disclosure. What JAWS is doing is not a bug, but exactly how aria-live works. Aria-live creates a sensitive region of the DOM that triggers an utterance by Assistive Tech whenever that region is changed. This is why wrapping a form in aria-live would be unwise.
If this is truly a progressive disclosure situation where the form is building itself ahead of the user based on their selections, aria-live notifications are not necessary. As long as the user's focus moves logically through the form elements as they are pertaining to their current task and content behind the user isn't changing, no alerts should be necessary.
In your example, you're wrapping the form fields and labels as well. You might want to just add the H2 into an aria-live region which will restrict the announcment to just that element.
(Apologies if I misunderstand the situation, but if selecting one of the buttons causes the button set to disappear and a div to be added, then the real question is where does focus land?)
Does using absolute positioning on a website negatively affect voice activation software?
Context:
I'm working for a company who have had their website's accessibility assessed. One of the comments was:
The tick box shown here is not being picked up by Dragon.
This means that a voice activation user would need to use keyboard commands in order to tab onto them.
Ensure that voice activation users are able to access the checkboxes by implementing the following in the CSS:
.checkbox__input {
/* position: absolute; */
cursor: pointer;
/* left: 0; */
/* top: 0; */
width: 38px;
height: 38px;
margin: 0;
opacity: 0;
}
The commended-out properties are their suggestions on what we should remove from our CSS.
I am aware that using position: absolute takes content out of the normal flow of the page. However, we are wrapping each checkbox in a container that is relatively positioned.
Their comment is suggesting to me that there is an issue around using voice commands on content that is absolutely positioned, but I can't seem to find anything online about if there actually are any issues.
For those curious, we do not want to implement their proposed changes because it changes our page design negatively.
The OP is asking about speech recognition, such as Dragon, and not screen readers.
Positioning has nothing to do with speech recognition and the recommended CSS seems silly to me. Two obvious things can affect speech recognition:
the role of the element
the displayed label of an element compared to the underlying accessible name
For the role, if you had a <div> that was styled to look like a checkbox, but the <div> did not have a role="checkbox", then a speech recognition user would not be able to say "click checkbox".
For the label, if the visual label of the checkbox does not match the accessible name of the checkbox (which should be a rarity), then a speech recognition user might not be able to (directly) select the checkbox. For example:
<input type="checkbox" id="mycheck">
<label for="mycheck">do you like dogs?</label>
A speech recognition user will be able to say "click dogs" or "click like" or "click <any word that is part of the visible label>".
However, if you had something like:
<input type="checkbox" id="mycheck" aria-label="are you a puppy lover?">do you like dogs?
then visually, both cases would look the same but the visible label, "do you like dogs?" does not match the accessible name, "are you a puppy lover?", and a speech recognition user would not be able to say "click dogs" or "click like" because neither of those words are in the accessible name. They'd have to say "click puppy" or "click lover", which would not be obvious.
Now, regarding positioning, if you had an object that was "on top" of the checkbox and that object on top received click events, then maybe positioning might affect Dragon, but I'm not sure. With a mouse user, if they try to click the checkbox but something (whether visually apparent or not) is on top, that top object will receive the event. If the speech recognition user says "click <checkbox name>" and an object is on top of it, I don't know if the checkbox will receive the event. It seems like the checkbox would get selected because you used the name of the checkbox and didn't rely on the DOM order for an object to receive the event.
Screen readers typically follow the order of the HTML (including any HTML generated by scripts) when reading a document. When CSS is used to position content, the content that appears on the screen can appear be in a different order from what appears in the code.
From Penn State's Accessibility Office:
The position attribute is used to change the visual position of an element regardless of where it is in the code. For example any item with position:absolute and position set to top:0px and left:0px will be displayed first visually, even if the div is the final text in the HTML code. Alternatively, an item may be listed first in the code, but actually be positioned to the bottom right side of the page visually.
This can be a problem for screen reader accessibility because content can be read out of context and therefore be confusing.
http://accessibility.psu.edu/css/readorderhtml/#fxd
Relative positiong presents the same problem.
The only way to overcome this issue is to allow items to render on screen in the order that they appear in the HTML. This may mean making adjustments to your HTML code, scripts, templates, etc.
This doesn't mean that you can't use CSS to position and align things -- you certainly can. It just means that you shouldn't use CSS to re-arrange the order of things.
I have a div at the top of my mobile application that is position:fixed so it will stay on the top of the browser (it scrolls away in ios 4 and lower which is fine). When an input is focused and brings up the keyboard, the div moves down to the middle of the page. See screenshots:
http://dbanksdesign.com/ftp/photo_2.PNG
Edit:
Here is a simplified test page:
http://dbanksdesign.com/test/
<body>
<div class="fixed"><input type="text" /></div>
<div class="content"></div>
</body>
.fixed { position:fixed; top:0; left:0; width:100%; background:#ccc; }
.content { width:100%; height:1000px; background:#efefef; }
Unfortunately you are probably best off using absolute positioning for your fixed elements when working with IOS. Yes, IOS5 does claim to support fixed positioning, but it all falls down when you have interactive controls within that fixed element.
I had the same problem with the search box on my switchitoff.net site. In IOS5 the fixed header would jump down the page if the search box gained focus while the page was scrolled. I tried various workarounds, and the one I currently have is a <div> which sits over the search box. When this <div> is clicked the following occurs:
The page is scrolled to the top
The fixed header is changed to absolute
The <div> covering the search box is hidden
The search <input> is focused
The above steps are reversed when the search box loses focus. This solution prevents the header jumping down the page when the search box is clicked, but for a simpler site you are probably better using absolute positioning in the first place.
There is another tricky issue with IOS5 and fixed positioning. If you have clickable elements on your fixed area with body elements scrolled behind them, this can break your touch events.
For example, on switchitoff.net the buttons on the fixed header became unclickable when interactive elements were scrolled behind them. touchstart was not even being fired when these buttons where tapped. Luckily onClick still seemed to work, although this is always a last resort for IOS because of the delay.
Finally notice how (in IOS5) you can click on the fixed header and scroll the page. I know this emulates the way you can use the scroll wheel over a fixed header in a normal browser, but surely this paradigm doesn't make sense for a touch-UI?
Hopefully Apple will continue to refine the handling of fixed elements, but in the meantime it's easier to stick with absolute positioning if you have anything interactive in your fixed area. That or go back to IOS4 when things were so much easier!
Using the JohnW recomendation to use absolute instead of fixed I came up with this workaround:
First set up a bind to detect when the input is onFocus, scroll to the top of the page and change the element position to absolute:
$('#textinput').bind('focus',function(e) {
$('html,body').animate({
scrollTop: 0
});
$('#textinput-container').css('position','absolute');
$('#textinput-container').css('top','0px');
});
Note that I'm using the id textinput for the input and textinput-container for the div top bar that is containing the input.
Set up another bind to detect when the input is not on focus anymore to change the position of the div back to fixed
$('#textinput').bind('blur',function(e) {
$('#textinput-container').css('position','fixed');
$('#textinput-container').css('top','0px');
});
I've been using a similar solution for a bar fixed at the bottom of the page, the code posted should be working for a bar fixed at the top but I didn't test it
Modified version of pablobart's solution but without scrolling to top:
// Absolute position
$('#your-field').bind('focus',function(e) {
setTimeout(function(){
$('section#footer').css('position','absolute');
$('section#footer').css('top',($(window).scrollTop() + window.innerHeight) - $('section#footer').height());
}, 100);
});
// Back to fixed position
$('#your-field').bind('focusout',function(e) {
$('section#footer').removeAttr('style');
});
The simple CSS:
section#footer
*{ position:fixed; bottom:0; left:0; height:42px }*
This solution works pretty well for me. All the code does is wait until the user taps on a text field, then changes the element identified by the 'jQuerySelector' parameter from a 'fixed' to 'static' position. When the text field looses focus (the user tapped on something else) the element's position is changed back to 'fixed'.
// toggles the value of 'position' when the text field gains and looses focus
var togglePositionInResponseToInputFocus = function(jQuerySelector)
{
// find the input element in question
var element = jQuery(jQuerySelector);
// if we have the element
if (element) {
// get the current position value
var position = element.css('position');
// toggle the values from fixed to static, and vice versa
if (position == 'fixed') {
element.css('position', 'static');
} else if (position == 'static') {
element.css('position', 'fixed');
}
}
};
And the associated event handlers:
var that = this;
// called when text field gains focus
jQuery(that.textfieldSelector).on
(
'focusin',
function()
{
togglePositionInResponseToInputFocus(that.jQuerySelector);
}
);
// called when text field looses focus
jQuery(that.textfieldSelector).on
(
'focusout',
function()
{
togglePositionInResponseToInputFocus(that.jQuerySelector);
}
);
The reason the buttons are becoming unclickable is because they have actually scrolled invisibly with the content. They are still there, just not at the location they were originally, nor where you see them.
If you can guess how much the button has moved (based on how much the content has moved) you can click on the invisible button and it will function normally. In other words, if the content has scrolled by 50 pixels, click 50 pixels away from the button and it will work.
You can scroll the content manually (even by a tiny amount) and the buttons will again work as expected.
Just hide your fixed element on focus and then show it again on focusout. I bet your users don't need to see it when focused. I know this is not a solution but I think it is a better approach. Keep it simple.
I have a div that has background:transparent, along with border. Underneath this div, I have more elements.
Currently, I'm able to click the underlying elements when I click outside of the overlay div. However, I'm unable to click the underlying elements when clicking directly on the overlay div.
I want to be able to click through this div so that I can click on the underlying elements.
Yes, you CAN do this.
Using pointer-events: none along with CSS conditional statements for IE11 (does not work in IE10 or below), you can get a cross browser compatible solution for this problem.
Using AlphaImageLoader, you can even put transparent .PNG/.GIFs in the overlay div and have clicks flow through to elements underneath.
CSS:
pointer-events: none;
background: url('your_transparent.png');
IE11 conditional:
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='your_transparent.png', sizingMethod='scale');
background: none !important;
Here is a basic example page with all the code.
Yes, you CAN force overlapping layers to pass through (ignore) click events.
PLUS you CAN have specific children excluded from this behavior...
You can do this, using pointer-events
pointer-events influences the reaction to click-, tap-, scroll- und hover events.
In a layer that should ignore / pass-through mentioned events you set
pointer-events: none;
Children of that unresponsive layer that need to react mouse / tap events again need:
pointer-events: auto;
That second part is very helpful if you work with multiple overlapping div layers (probably some parents being transparent), where you need to be able to click on child elements and only that child elements.
Example usage:
.parent {
pointer-events:none;
}
.child {
pointer-events:auto;
}
<div class="parent">
I'm unresponsive
I'm clickable again, wohoo !
</div>
Allowing the user to click through a div to the underlying element depends on the browser. All modern browsers, including Firefox, Chrome, Safari, and Opera, understand pointer-events:none.
For IE, it depends on the background. If the background is transparent, clickthrough works without you needing to do anything. On the other hand, for something like background:white; opacity:0; filter:Alpha(opacity=0);, IE needs manual event forwarding.
See a JSFiddle test and CanIUse pointer events.
I'm adding this answer because I didn’t see it here in full. I was able to do this using elementFromPoint. So basically:
attach a click to the div you want to be clicked through
hide it
determine what element the pointer is on
fire the click on the element there.
var range-selector= $("")
.css("position", "absolute").addClass("range-selector")
.appendTo("")
.click(function(e) {
_range-selector.hide();
$(document.elementFromPoint(e.clientX,e.clientY)).trigger("click");
});
In my case the overlaying div is absolutely positioned—I am not sure if this makes a difference. This works on IE8/9, Safari Chrome and Firefox at least.
Hide overlaying the element
Determine cursor coordinates
Get element on those coordinates
Trigger click on element
Show overlaying element again
$('#elementontop').click(e => {
$('#elementontop').hide();
$(document.elementFromPoint(e.clientX, e.clientY)).trigger("click");
$('#elementontop').show();
});
I needed to do this and decided to take this route:
$('.overlay').click(function(e){
var left = $(window).scrollLeft();
var top = $(window).scrollTop();
//hide the overlay for now so the document can find the underlying elements
$(this).css('display','none');
//use the current scroll position to deduct from the click position
$(document.elementFromPoint(e.pageX-left, e.pageY-top)).click();
//show the overlay again
$(this).css('display','block');
});
I currently work with canvas speech balloons. But because the balloon with the pointer is wrapped in a div, some links under it aren't click able anymore. I cant use extjs in this case.
See basic example for my speech balloon tutorial requires HTML5
So I decided to collect all link coordinates from inside the balloons in an array.
var clickarray=[];
function getcoo(thatdiv){
thatdiv.find(".link").each(function(){
var offset=$(this).offset();
clickarray.unshift([(offset.left),
(offset.top),
(offset.left+$(this).width()),
(offset.top+$(this).height()),
($(this).attr('name')),
1]);
});
}
I call this function on each (new) balloon. It grabs the coordinates of the left/top and right/down corners of a link.class - additionally the name attribute for what to do if someone clicks in that coordinates and I loved to set a 1 which means that it wasn't clicked jet. And unshift this array to the clickarray. You could use push too.
To work with that array:
$("body").click(function(event){
event.preventDefault();//if it is a a-tag
var x=event.pageX;
var y=event.pageY;
var job="";
for(var i in clickarray){
if(x>=clickarray[i][0] && x<=clickarray[i][2] && y>=clickarray[i][1] && y<=clickarray[i][3] && clickarray[i][5]==1){
job=clickarray[i][4];
clickarray[i][5]=0;//set to allready clicked
break;
}
}
if(job.length>0){
// --do some thing with the job --
}
});
This function proofs the coordinates of a body click event or whether it was already clicked and returns the name attribute. I think it is not necessary to go deeper, but you see it is not that complicate.
Hope in was enlish...
Another idea to try (situationally) would be to:
Put the content you want in a div;
Put the non-clicking overlay over the entire page with a z-index higher,
make another cropped copy of the original div
overlay and abs position the copy div in the same place as the original content you want to be clickable with an even higher z-index?
Any thoughts?
I think the event.stopPropagation(); should be mentioned here as well. Add this to the Click function of your button.
Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
Just wrap a tag around all the HTML extract, for example
<a href="/categories/1">
<img alt="test1" class="img-responsive" src="/assets/photo.jpg" />
<div class="caption bg-orange">
<h2>
test1
</h2>
</div>
</a>
in my example my caption class has hover effects, that with pointer-events:none; you just will lose
wrapping the content will keep your hover effects and you can click in all the picture, div included, regards!
An easier way would be to inline the transparent background image using Data URIs as follows:
.click-through {
pointer-events: none;
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
}
I think that you can consider changing your markup. If I am not wrong, you'd like to put an invisible layer above the document and your invisible markup may be preceding your document image (is this correct?).
Instead, I propose that you put the invisible right after the document image but changing the position to absolute.
Notice that you need a parent element to have position: relative and then you will be able to use this idea. Otherwise your absolute layer will be placed just in the top left corner.
An absolute position element is positioned relative to the first parent
element that has a position other than static.
If no such element is found, the containing block is html
Hope this helps. See here for more information about CSS positioning.
You can place an AP overlay like...
#overlay {
position: absolute;
top: -79px;
left: -60px;
height: 80px;
width: 380px;
z-index: 2;
background: url(fake.gif);
}
<div id="overlay"></div>
just put it over where you dont want ie cliked. Works in all.
This is not a precise answer for the question but may help in finding a workaround for it.
I had an image I was hiding on page load and displaying when waiting on an AJAX call then hiding again however...
I found the only way to display my image when loading the page then make it disappear and be able to click things where the image was located before hiding it was to put the image into a DIV, make the size of the DIV 10x10 pixels or small enough to prevent it causing an issue then hiding the containing div. This allowed the image to overflow the div while visible and when the div was hidden, only the divs area was affected by inability to click objects beneath and not the whole size of the image the DIV contained and was displaying.
I tried all the methods to hide the image including CSS display=none/block, opacity=0, hiding the image with hidden=true. All of them resulted in my image being hidden but the area where it was displayed to act like there was a cover over the stuff underneath so clicks and so on wouldn't act on the underlying objects. Once the image was inside a tiny DIV and I hid the tiny DIV, the entire area occupied by the image was clear and only the tiny area under the DIV I hid was affected but as I made it small enough (10x10 pixels), the issue was fixed (sort of).
I found this to be a dirty workaround for what should be a simple issue but I was not able to find any way to hide the object in its native format without a container. My object was in the form of etc. If anyone has a better way, please let me know.
I couldn't always use pointer-events: none in my scenario, because I wanted both the overlay and the underlying element(s) to be clickable / selectable.
The DOM structure looked like this:
<div id="outerElement">
<div id="canvas-wrapper">
<canvas id="overlay"></canvas>
</div>
<!-- Omitted: element(s) behind canvas that should still be selectable -->
</div>
(The outerElement, canvas-wrapper and canvas elements have the same size.)
To make the elements behind the canvas act normally (e.g. selectable, editable), I used the following code:
canvasWrapper.style.pointerEvents = 'none';
outerElement.addEventListener('mousedown', event => {
const clickedOnElementInCanvas = yourCheck // TODO: check if the event *would* click a canvas element.
if (!clickedOnElementInCanvas) {
// if necessary, add logic to deselect your canvas elements ...
wrapper.style.pointerEvents = 'none';
return true;
}
// Check if we emitted the event ourselves (avoid endless loop)
if (event.isTrusted) {
// Manually forward element to the canvas
const mouseEvent = new MouseEvent(event.type, event);
canvas.dispatchEvent(mouseEvent);
mouseEvent.stopPropagation();
}
return true;
});
Some canvas objects also came with input fields, so I had to allow keyboard events, too.
To do this, I had to update the pointerEvents property based on whether a canvas input field was currently focused or not:
onCanvasModified(canvas, () => {
const inputFieldInCanvasActive = // TODO: Check if an input field of the canvas is active.
wrapper.style.pointerEvents = inputFieldInCanvasActive ? 'auto' : 'none';
});
it doesn't work that way. the work around is to manually check the coordinates of the mouse click against the area occupied by each element.
area occupied by an element can found found by 1. getting the location of the element with respect to the top left of the page, and 2. the width and the height. a library like jQuery makes this pretty simple, although it can be done in plain js. adding an event handler for mousemove on the document object will provide continuous updates of the mouse position from the top and left of the page. deciding if the mouse is over any given object consists of checking if the mouse position is between the left, right, top and bottom edges of an element.
Nope, you can't click ‘through’ an element. You can get the co-ordinates of the click and try to work out what element was underneath the clicked element, but this is really tedious for browsers that don't have document.elementFromPoint. Then you still have to emulate the default action of clicking, which isn't necessarily trivial depending on what elements you have under there.
Since you've got a fully-transparent window area, you'll probably be better off implementing it as separate border elements around the outside, leaving the centre area free of obstruction so you can really just click straight through.
Does anyone know how the various screen readers interact with a modal window, ie: Thickbox? Do the contents of the modal gain the reader's focus after they click on it?
This depends on the modal solution you're using. Many do not do a decent job of focus management:
putting keyboard focus onto the first element in the modal.
looping focus back to the first element when the end of the modal is reached (rather than letting focus cycle to the browser chrome or the page behind the modal).
returning keyboard focus to the original position (e.g. the opening button or link) when the modal is closed.
If the solution you're using doesn't do some of this, you can do this kind of thing in your own JavaScript. For example, if you know the first focusable element:
var focusMe = document.getElementById("#modal-focus-start");
if (focusMe) {
focusMe.focus();
}
Or if you want to focus the first link in the modal.
var modal = document.getElementById("#modal"),
focusMe;
if (modal) {
focusMe = modal.getElementsByTagName("a")[0];
if (focusMe) {
focusMe.focus();
}
}
If you don't have a convenient focusable element to move focus to, some modern browsers (Firefox seemed buggy last time I checked) allow you to set tabindex to -1 on any HTML element, making that element focusable by JavaScript.
If you wanted to go further, you can use JavaScript to find the first focusable element (uses jQuery) within the modal.