Detect focus/blur between two iframes (Accessibility) - html

Inside of a page, there are 2 iframe buttons (external, not from the same origin as my site) next to each other that grab the focus when a keyboard user focusses to them.
I need to style them (for accessibility reasons) when the user is focussed on them. Since iframes grab the focus, the page has no control over the focus styles inside the iframes so i have made custom borders to go around the iframe when the main window loses focus. [The first iframe has an indicator, yay!]
BUT I realized when you are tabbing BETWEEN the 2 iframes (from the first to the second), the browser cannot detect that action. It is as if it skips form one iframe to the next without notifying the main window of anything. Therefore, I can never style the next iframe and unstyle the first...
I have tried everything even down to using the sandbox attribute to force same origin, which ends up causing issues with these social media iframes (i am warned in the console that they will not pass the iframe to me within a sandbox, once again... rightfully so). Anyone have any ideas?

Related

Avoid cookies pop up window inside iframe?

I have an iframe that displays live prices of stock market. My problem is that when i load my page, this iframe shows a pop up window for cookies policy.
Is there anyway to avoid this window completely (or select "accept" in background) so that this iframe will directly show stock prices?
I found some information about sandbox option but could not go deeper with that
My website is the following and the iframe is on the down-left
https://grbusinessforum.com/
("Αποδέχομαι" is the button of "Accept cookies")
Thanks
Sandboxing the iframe can prevent all JS from running inside it, but that would probably break the page in other ways.
There's nothing you can do from outside the frame.
You'd need to change the page inside the frame instead. You could add a query string to the URL that it uses to disable the tracking cookies by default, or use postMessage to send a message into the frame that code there uses to remove the cookie prompt.
Of course, this will need the cooperation of the people who control the site you are displaying in the frame … but if they are happy for you to show their content on your page that shouldn't be too much of a problem, should it?

ARIA Live Regions for single page applications

I am new to accessibility of web pages. I have an application where the content of the body changes based on the header link clicks in an ajax call without page refresh. So the HTML content inside the body gets updated for each link click with different page content (table + button + information text).
My requirement here is the screen reader should announce the information text each time when the page gets loaded. Here the container is body (or an immediate div inside body) for all pages. So I have made it aria-live="polite", but every time page loads it is announcing the whole page content but I want to make it announce only the information text. Other elements of the page should be announced on focus/visit. I hope I can apply aria-live="off" for all other elements but I'm looking for any ideal solution for this. I cannot change the layout of the application.
Can some one help me on this. Thanks in advance.
SPA pattern best practices
You are essentially following a Single Page Application pattern. As such the method recommended for handling navigation is actually quite straight forward with two steps.
tell a user that navigation is about to occur (before navigation)
let a user know that loading is complete (after navigation).
before navigation (link click)
You need to signal to a user that a page is loading if you are using a SPA pattern (and therefore interrupting normal navigation). e.g. I click your link, you need to let me know that an action is being performed (loading.....) as you intercept the normal browser behaviour with e.preventDefault() or equivalent.
The simplest way is to use aria-live=assertive on a region that explains the page is loading. You can Google how to implement that correctly but essentially you would update the content of a hidden div (<div aria-live="assertive" class="visually-hidden">loading</div> with some loading message the second a link is clicked.
This should be done before any AJAX calls are made.
after navigation (new content loaded)
When the new page loads you need to manage focus.
The best way to do this is to add a level 1 heading (<h1>) to each page that has tabindex="-1". By using tabindex="-1" it means that the heading won't be focusable by anything other than your JavaScript so won't interfere with the normal document flow.
Once the page loads and the content has been populated fully the last action you perform in your JavaScript navigation function is to place the focus onto this heading.
This has two benefits:
it lets the user know where they are now
it also lets them know when the page load is complete (as AJAX navigation doesn't announce when the page is loaded in most screen readers).
At this point you may also want to clear the <div aria-live="assertive"> contents so that it is ready for further navigation.
Have you tried to wrap the "live zones" - where updates happen in div with aria-live="polite". Then screen reader will announces only these zones on updates.Don't wrap whole page or div in aria-live="polite".
<div aria-live="polite">
<p id="errorText">Announced on update</p>
</div>
<div>
other page sections..
</div>

Is an empty element (such as <a href="#">) valid for accessibility purposes?

I manage several websites that use a featured article scroller on their homepages, which allows the user to click a forward or back arrow in order to see the next article headline and blurb while remaining on the same page.
I use WAVE's accessibility checker and any sites that have this particular plugin throw an error back because within the code there is an empty link, written as <a href="#">. Is there any way around this? I've defined a title attribute but the # is causing the empty link error to still come up.
Some places I've seen that this is perfectly acceptable and others claim this is a problem. What's the actual answer and potential workaround?
Change the <a href="#"> to a <button> and put your event handler on it.
Some more context on which elements belongs where....
Does the Control Take Me to Another Page? Use an Anchor
If, when clicked, tapped, or activated by keyboard or voice (or insert novel interaction method here), the user is whisked to another URL (including an anchor on the same page), then use <a href="[URL]">. Make sure you use the href attribute and that it has a real URL, not a “#” (otherwise you’re probably relying on JavaScript, which is not at all necessary for a hyperlink). If an href points to just a “#”, then you’re probably doing it wrong. If it points to a named anchor as part of your progressive enhancement efforts, then that’s totally valid.
Does the Control Change Something on the Current Page? Use a Button
If, when activated, the user is not moved from the page (or to an anchor within the page), but instead is presented with a new view (message boxes, changes in layout, etc.), then use a <button>. While you could use an<input type="button">, it’s more likely you’ll get into conflicts with pre-existing styles and subsequent developers (like me).
Does the Control Submit Form Fields? Use a Submit
If, when activated, information the user has entered (either by manually typing or by choosing items on the screen) is being sent back to the server, then use an <input type="submit">. This has better live within a <form>. If you need more styling control or have to embed more than just a simple text string, use a <button type="submit"> instead.
Keyboard Considerations
Think of keyboard users for a moment. A hyperlink can be fired by pressing the enter key. But a true button can be fired by pressing the enter key or the space bar. When a hyperlink has focus and the user presses the space bar, the page will scroll one screenful. If there isn’t more to scroll then the user just experiences nothing. Given a set of interface elements that look the same, if some work with a space bar and some don’t, you can’t expect users to have much confidence in how the page behaves.
I think it’s also worth mentioning that events triggered by a space bar only fire when the key is released, whereas using the Enter key will fire the event as soon as you press the key down (prior to releasing it).
Some source suggests that link would be an invalid hypertext reference, but in fact the problem would exist only in non javascript browsers which is out of the scope of WCAG 2. This is not your problem here as this is not an error that WAVE considers.
The problem here is the fact that you have an empty link content and that adding a title attribute does not satisfy WAVE algorithm.
If your only concern is to satisfy WAVE, just put some content in the link and use any CSS trick to hide this content.

How to hide specific iframe elements from JAWS frames list?

I've got some specific iframe elements that I want to be able to hide from the JAWS frame list (insert + f9). There are other iframes that are very important so just having a user ignore iframes isn't going to work.
Is it possible to do this?
Edit: I should mention why. There is a user option that changes whether specific types of windows open in a new window or open in an iframe on the page, even if the option is set to open in a new window the iframe is still there but the src is set to a blank html file. In that case I(or if it's set to load in the iframe but it isn't at the moment) the content of the iframe is useless to the user and I'd rather hide it from them. I'd rather not make major changes to the code if I can avoid it.
You should be able to hide it with CSS (visibility: hidden or display: none) or with aria-hidden="true".

Overlay one iframe on top of another, scroll them together

Following up on How to rewrite URLs referenced by Javascript code? I'd like to overlay a button on top of someone else's website (e.g. overlay a Paypal button alongside Stackoverflow's bounty button) and have the two <iframe>s scroll together. The button would reside in the top layer. The website would reside in the bottom layer.
I understand that transparent <iframe>s were/are abused for clickjacking but the browser security mechanism seems to block legitimate use-cases. In my case the user is seeing the same button he/she is clicking. It's even possible that this is a browser bug.
Here is what I see under Chrome:
The top <iframe> intercepts all mouse clicks, even for areas that do not contain any components. Meaning, users cannot interact with the bottom layer at all.
If I style the top <iframe> with pointer-events: none the opposite problem occurs: users are able to see the top layer but all mouse clicks go to the bottom layer. Applying pointer-events: auto to child components does not help (clicks still pass through to the bottom layer).
If I size and position the top <iframe> so its area is equal precisely to the button I am trying to overlay, then mouse clicks go to the right layer but the top layer fails to scroll alongside the bottom layer. Meaning, the button always remains in the same absolute position as the bottom layer scrolls.
Is it possible for me to position a button in the top layer so that it always aligns with a certain position in the bottom layer? In the example where I position a Paypal button alongside the Stackoverflow bounty, I expect the Paypal button to scroll off the page as the user scrolls down the question.
https://stackoverflow.com/a/4087397/14731 leads me to believe this is not possible. Is there another way to implement this?
UPDATE: Here is a jsfiddle for you to play with. The test button is found to the right of "NEWS & VIEWS" in the middle of the page.
Update: New approach
Following discussion with Gili below, the requirement for the solution to work across multiple pages made me rethink my solution.
The new approach:
Doesn't require any code changes or specific features on the target site.
Works on every page while the user navigates (as long as they stay on the same domain)
Could be tweaked to inject any HTML/JS into any DOM element within any target page
My solution works as follows:
Send the person you want to demonstrate Widget X to an email with a link to your instructions page
That instructions page contains a bookmarklet which they add to their bookmarks bar
They visit their own site and click your bookmarklet
Your bookmarklet injects javascript into their page
That javascript creates a pop-up window with content that appears to belong to the target domain, since that domain generated the popup
That pop-up window then monitors the DOM on the target browser window (window.opener) and injects our arbitrary HTML whenever the current page doesn't contain our target node ID.
It seems to work well in my testing (perfect in Chrome, haven't tested across all browsers yet) and seems to work on every target site from StackOverflow to Twitter.
Live demo here: How to demo an web widget on a third party site without having access to their code
Sample code below, expanded for readability:
s = "<script type='text/javascript'>setInterval(function() { if(!window.opener.document.getElementById('gctrlPixelator')) {var i=document.createElement('IMG');i.src='//lorempixel.com/400/200/';i.id='gctrlPixelator';i.style.cssText='top:20;right:20;position:absolute;z-index: 9999;';window.opener.document.getElementsByTagName('body')[0].appendChild(i);}},500);</script>";
t = "<div style='text-align: center; font-family: Arial, Helvetica;'><h1 style='font-size: 18px;'>Demo running!</h1> Keep this window open and return to the main site window to continue the demo.</div>";
w = window.open('','name','height=200,width=400');
w.document.write(s);
w.document.write(t);
The above should be converted into a bookmarklet before deploying to an 'instructions' landing page for a potential client.
Original solution
First, sorry for posting this as an answer rather than as a comment. I've been thinking about this for half an hour, and only just realised I need 50 reputation to comment. So, apologies, but I wanted to share...
I agree that it's unlikely there is a cross browser way to do this double iframe trick. I read your other question about javascript URL rewriting and it lead me to an idea: Rather than trying to embed/hijack their site on another URL, how about creating a bookmarklet that allows you to inject your Javascript into their page?
It could work like this:
Direct them to your site where you host the custom bookmarklet link. Ask them to add it to their favorites.
Ask them to go to their own site, then click your bookmarklet in their bookmarks.
This would inject your JS into their page, allowing you to edit the DOM any way you wanted (e.g. changing styles, adding DOM elements, etc.)
Code something like this, converted to a bookmarklet (i.e. wrapped in a function with a javascript: at the start) could do the trick...
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", "http://www.example.com/file.js");
document.getElementsByTagName("head")[0].appendChild(script);
I've tested that in Chrome and it seems happy to load the JS cross-domain. The only rule seems to be that the protocols must match (http or https).
Not quite what you asked for, but a possible solution.