I've been working on a web component that will hide/reveal content by hovering over a <div>. I've got the functionality working the way I want, but I just realized isn't accessible via tabbing.
I was able to include tabindex="0" role="button" aria-pressed="false" to each of the <div> boxes, which allows you to toggle between each box, but I have no way of revealing the hidden content.
You can find my code here, which demonstrates the issue:
https://codepen.io/ckatz/pen/XQaKdB
Is there a markup I'm missing to allow for someone to hit Enter to show the text?
I added this to your CSS and it worked when i press TAB and move from div to div:
.color:focus {
/* Change the flex-basis so that we know what
size to transition to on hover. Arbitrary,
based on our design/content.
*/
flex-basis: 20em;
}
.color:focus .details {
opacity: 1;
}
Related
I'm working on a dynamic form builder, where the user can add different blocks of content to a page (buttons, text inputs, paragraphs of text, images etc), which they can later publish and it will be a simple HTML form they can use.
For the 'preview' section of this application (where they are adding different blocks of content and modifying the content and look of it), it occurs to me that the simplest way to do this, is to just display the end product HTML itself and that way I'm more or less guaranteed that what is displayed in the preview matches what is displayed in the actual form.
Where this is important is with obscure styling quirks, such as the behaviour of buttons with display:block.
However, I don't want the the preview to be actually interactive like the real form would. That is, I don't want the following behaviours:
Inputs receiving focus and being able to insert content
Buttons having click animations
Clicking links navigating
Default hover styles occuring.
Also, in terms of accessibility, it might be very confusing if there are a bunch of input that don't do anything appearing on the screen.
Is there a browser native/standard way to do this?
My fallback will likely be to disable all of the elements. But this won't work for links for example.
An alternative might be to put an invisible div on top of the form, which captures all of the click events. But I don't like this from an accessibility POV.
Is using the role="presentation" intended for this?
Code Example
As an example here, see some sample code here: https://codepen.io/dwjohnston/pen/qBrGPmr?editors=1111
Now for this, I have the divs with role="button" - These buttons are intended to be clickable, - when you click them the side panel will show content configuration eg, the default value of the input, label, etc.
Already, there is a problem - interactive content is not permitted inside a button.
But also, I shouldn't be able to tab to those controls, (now I can manually add tabindex = "-1", but that's not the complete picture). I don't want to confuse screen readers etc.
INFO
There is an edit to this question that addresses the specific issues OP has with their current implementation. I have left this first part here as my original answer.
I don't want the the preview to be actually interactive like the real form would.
Why? Having the form be interactive would be great for all users (taking into account that some functionality needs to not work fully in a preview).
Let people see what default hover styles look like, what clicking links would do (i.e. click the link and alert says "would navigate to xxx page") etc.
I understand not wanting to be able to navigate to new pages and submit the form (any "save" or "update" actions plus any "navigation" actions) but everything else I believe should be able to work in a preview.
Also, in terms of accessibility, it might be very confusing if there are a bunch of input that don't do anything appearing on the screen.
It would be far more confusing if a preview appeared on screen but then I couldn't navigate to the buttons, links etc.
How would that behave for a screen reader user? i.e. would you hide all elements using aria-hidden="true" (in which case how would they test the page?).
My fallback will likely be to disable all of the elements. But this won't work for links for example.
This is really one of the worst ways you could handle it, disabled inputs generally can't receive focus so keyboard users would suffer when testing.
Plus if some elements in the final production form are disabled until a certain field is filled in (for example) then how could a user test that in your end form?
Also if you intercept the navigation for a link without explaining why the link doesn't work that could also cause confusion. (and yet again could that link open in a new window in "preview" mode if you explain that to end users? Obviously depends if it is a static link etc. but just a thought on a way users can check any custom links point to the right place).
Proposed Solution
I would say you need two versions of the finished form. The "real world" one and the "preview" one.
The HTML can be (read "should be") identical but you need to implement JavaScript handlers to disable the functionality you don't want to be active.
There is nothing wrong with having an editing tool only work with JavaScript if that is one of your concerns, as long as you provide a warning to end users that the tool requires JavaScript to work. (The difference between a publishing tool and an end user experience is you can be much more reliant on JavaScript.)
For example: Let's say you have a <button> that when clicked should add a new row to the form (in the production version of the form) and for whatever reason you do not want this functionality to be active in the preview version.
In that case in the preview / demo version of the form when you click this button an alert could be shown that says "will add a new row to the form".
That way screen reader users and keyboard only users can test the form without you needing to do too much extra work (and can also see if the form has usability issues for keyboard users while they are at it!)
I think this would be the most clear for everybody and a much better user experience.
You just need to think of navigating in and out of preview mode (Esc to close for example) and quick edits (when you preview the form give the option to focus the previously focused element if the forms are particularly long, keyboard only users will thank you for this! The same for when you go back to the edit, put focus back on the last edited item).
Further reading
From an accessibility perspective WCAG isn't what you are looking for in this scenario, Authoring Tool Accessibility Guidelines (ATAG) is.
This is a little known set of guidance on how to create editors, WYSIWYGS etc. etc.
As with all W3C guidance it is a heavy read but if you understand the core principles it will guide you to good decisions and you can always ask here if you need clarity on some of the individual points that aren't clear :-).
EDIT: How could you achieve an accessible interface with the current design
The issues that you have within the codepen you linked and their solutions are as follows:
Stop interactive items receiving focus
As you wrap each element you have correctly diagnosed your biggest issue which is nested interactive elements.
The solution to this is quite straight forward: Give every interactive element a tabindex="-1" as you said. This makes sure they cannot be focused incorrectly.
Make sure the actual wrapper item can be focused and activated
Then we just need to make sure that the wrapper .content-item has tabindex="0" so it is added to the focus order.
We also need to capture the Enter and the Space keys and ensure our panel is activated with them also.
Visual focus indicator
I also added an outline to the wrapper "button" so that visual focus indicators are available.
So that essentially fixes normal keyboard navigation issues, the next issue is how a screen reader will interpret nested buttons, inputs etc.
Screen reader corrections
Here I would also go simple, hide the button, input etc. entirely from a screen reader and instead explain what element is inside.
Effectively we make the button invisible and instead describe the contents of the .content-item.
To hide the element we use aria-hidden="true"
To announce something meaningful we can use some visually-hidden (screen reader only) text inside a <span>. This will be far more robust that using aria-label with such a complex application.
make the application behave well with a mouse
Final challenge - stop mouse events.
Luckily pointer-events: none has really good support and even on the few browsers that don't support it being able to click into an input isn't the end of the world (we have fixed it for keyboard users)
Example with all issues resolved:
This solves all of the issues with your selection method.
Please note it doesn't take into account accessibility errors of the components themselves (for example the <input> having no <label> etc.) but I assume that is just because it is an example.
The only thing you need to work out is how to generate the visually hidden text describing the item and the .content-info "button" action.
document.addEventListener("DOMContentLoaded", function () {
const items = document.getElementsByClassName("content-item");
const rightPanel = document.getElementById('right-panel');
for (let i = 0; i< items.length; i++) {
const item = items[i];
item.addEventListener("click", (e) => {
console.log(e.target);
const id = e.target.dataset.id;
rightPanel.innerHTML = id;
});
// ADDED this to capture the Enter and Space presses on our wrapper button
item.addEventListener("keydown", function(e){
if(e.keyCode == "32" || e.keyCode == "13"){
console.log(e.target);
const id = e.target.dataset.id;
rightPanel.innerHTML = id;
}
});
}
});
.main {
display: flex;
flex-flow: row nowrap;
}
.left {
flex: 1 1 auto;
}
.right {
flex: 1 1 auto;
}
.content-item {
margin-top: 20px;
width: 600;
border: solid 2px blue;
cursor: pointer;
}
/* ADDED a focus indicator so keyboard users know where they are */
.content-item:focus{
outline: 4px solid #333;
}
/* ADDED to stop pointer events reaching the input, button etc. */
input, button{
pointer-events: none;
}
/* ADDED the visually hidden class so we can provide meaningful text to screen reader users */
.visually-hidden {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px, 1px, 1px, 1px); /*maybe deprecated but we need to support legacy browsers */
clip-path: inset(50%); /*modern browsers, clip-path works inwards from each corner*/
white-space: nowrap; /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */
}
<div class ="main">
<div class ="left">
<!-- Added `tabindex="0"` so the wrapper is focusable by keyboard -->
<div class="content-item" role="button" data-id="item-1" tabindex="0">
<!-- added `aria-hidden="true"` and `tabindex="-1"` to hide the input from screen readers and make sure it cannot be focused by keyboard, I also added `role="presentation"` just for good measure, although it shouldn't be needed. -->
<input type="text" aria-hidden="true" tabindex="-1" role="presentation">
<!-- Added this span that explains the action that the "content-item button" would perform if clicked. You need to come up with something meaningful for the contents of this -->
<span class="visually-hidden">Edit input [input identifier]</span>
</div>
<div class="content-item" role="button" data-id="item-2" tabindex="0">
<button aria-hidden="true" tabindex="-1" `role="presentation"`> I am a button</button>
<span class="visually-hidden">Edit button [button identifier]</span>
</div>
</div>
<div class ="right" >
<h2> Right panel</h2>
<div id ="right-panel">
</div>
</div>
</div>
You might want to look into the inert attribute. It is not supported by any browser at the moment, but there are polyfill libraries.
The idea is that marking this on any element will make it and all its children non-interactive and invisible for accessibility purposes.
You can read some background and download the library here:
https://github.com/WICG/inert
Try this
$(document).ready(function(){
var demoPage = $('div.demoPage');
demoPage.find('a').attr('href','#');
demoPage.find('button').attr("disabled", true)
})
div {
padding: 20px;
margin: 20px;
background: #eee;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div class="no-copy">
<p>You can't click me.</p>
</div>
<div class="demoPage">
<a href="www.google.com" readonly="" class="no-copy">
It is a link
</a>
<button> It is a button</button>
</div>
<!--you can do this-->
<input type="text" id="input" disabled>
<script>
document.getElementById('input').disabled = true;
</script>
You can do that very simple by adding some css classes:
<div class="content-item disable-control" role="button" data-id="item-1">
<input type="text" />
</div>
<div class="content-item disable-control" role="button" data-id="item-2">
<button> I am a button</button>
</div>
^^ I added an additional "disable-control" class
.content-item.disable-control * {
pointer-events: none;
cursor: inherit;
user-select: none;
}
.content-item.disable-control *::selection {
background: transparent;
}
Make sure to add some browser-specifix css if needed, e.g.
*::-moz-selection
.. and of course, you can modify my code to apply the class only once (for the whole left pane) and not for each control seperately
Add the disabled attribute to all form elements that you want to disable.
I have a component that, upon a hover, shows a button and a link that you can click on. This is not a menu... just a box in the middle of the page.
For accessibility, I would like a user to be able to tab into the container (happens now, and displays the content in the .HiddenUntilHover class) AND also continue to tab to the button and link that show up on the hover/focused state.
Right now you can focus on the container and see the hover state; however, when you tab it just goes to the next element and does not allow you to tab to the button or link WITHIN the hover state.
Pseudo code example:
/* My component .jsx */
<div tabIndex="0" className="MainContainer">
<div className="SomeOtherClass">
<div className="HiddenUntilHover">
/* I would like to be able to tab to these clickable things! */
<button>Click me!</button>
I am also clickable
</div>
</div>
</div>
And my SCSS:
.HiddenUntilHover {
display: none;
}
MainContainer:focus,
MainContainer:hover,
> .HiddenUntilHover {
display: block
}
I ran into this issue a few days ago and I solved it using css classes to make the hovered content accessible via keyboard navigation.
The way I got this working was to use css pseudo-classes to ensure that when the div element is active & focused that the buttons inside also display. Specifically the additional use of :focus-within & :focus-visible should ensure that when you tab over the list items, their contents are also displayed and keyboard accessible.
.MainContainer {
&:not(:hover, :focus, :active, :focus-visible, :focus-within) {
.HiddenUntilHover {
visibility: hidden;
}
}
}
<body>
<div tabIndex="0" className="MainContainer">
Content
<div className="SomeOtherClass">
<div className="HiddenUntilHover">
<button>Click me!</button>
I am also clickable
</div>
</div>
</div>
</body>
Here's a link to the Codesandbox demo of this working
When the box is in focus, tabbing further to the button will make the box blur, which will hide it, and its contents, so focus will move to the next accessible element. I think this is the behavior you are experiencing.
You might consider using inserting an aria-activedescendant or tabindex attribute when the box comes into focus. This requires a little javascript.
Strictly speaking, you don't need to rely on the hover state to make that control accessible. You could have an offscreen (or clipped) button/link that is not a DOM child of the hidden (display:none) box. If you take this approach, read up on the aria-owns attribute.
As long as it is marked up as a button or link (or has a tabindex="0" setting), and is not 'really' hidden, it ought to be possible to tab to it.
Try increasing the properties of the class MainContainer
for example.
.MainContainer {
width: 100%;
height: 100px;
}
.MainContainer .HiddenUntilHover {
display: none;
}
.MainContainer:hover .HiddenUntilHover, .MainContainer:focus .HiddenUntilHover {
display: block;
}
Elements appearing on hover are inherently inaccessible. You are experiencing one side of the problem with your code, where it is difficult to make it keyboard accessible.
But think about touch screens that have no real concept of hover: is there some way to reach your button on a smarphone or tablet?
For a more pragmatic answer, if you need to stay with hover, a less hacky solution than the two already posted ones could be the following:
use focusin and focusout events. See for example this question for explanations and differences with focus/blur, and this w3school doc for browser compatibility.
You will have to structure your HTML differently, such as:
<div id="outer">
<div id="hover">
...
</div><!--hover-->
<button>Your button which only appears on hover</utton>
</div><!--outer-->
As well as use a bit of js:
$('#outer').on('focusin', __=>$('#hover').classNames.add('keep-visible'));
$('#outer').on('focusout', __=>$('#hover').classNames.remove('keep-visible'));
With a corresponding .keep-visible class which will leave the element display:block (I'm not a CSS expert, I let you write the code).
The overal functionning is the following: when some element within #outer takes the focus, the focusin element is fired due to bubbling. In the event, you put your class .keep-visible which makes the element to stay visible.
The focusout event is fired when the focus leaves the last element within #outer. At that point you remove the .keep-visible class, which makes the element to disappear.
According to the link above, onfocusin/out aren't standard, but are supported by all major browsers including IE. Firefox is the last one to implement it in 52.0, so it's a kind of defacto standard; we can reasonably expect that it won't disappear soon.
I am having trouble with two buttons at the top of my mobile site
www.thefriendlydentist.ie
They are clickable on desktop but on mobile I get no response?
The html is placed in the header of the WP theme.
<div id="topcontact-2" style="background-color:white;">
<p style="background-color:white;padding:none;"class="call-button" id="call-button"> CALL US </p>
<p style="background-color:white;padding:none;" class="call-button" id="email-button"> EMAIL US </p>
</div>
You need check your all elements (divs) properly, I strongly suggest you using mobile device toolbar on Chrome or Mozilla.
If you look on desktop browser using by mobile device toolbar, you will see the some elements overlapping the all page. So your buttons that you want to click stay behind of those elements.
- Option 1: remove overlapping elements
- Option 2: use z-index to manage them.
<div class="mobile-bg-fix-img-wrap">
<div class="mobile-bg-fix-img" style="/* width: 375px; *//* height: 767px; */"></div>
</div>
You can see in image how above elements fill the page.
How Z-Index Works?
All of us are quite comfortable set some x (left:10px) and y (top:10px) values to elements by using CSS but not for z-index. Z-index property defines the level of an HTML element on the screen. Let's check the elements below.
In brief, z-index will define the closeness of the elements to the user. In this sample you can assign elements like below:
red square z-index:10
blue circle z-index:56
white square z-index:985
in this order, nothing will change. In this case, we know that z-index is relative. Another important thing, we need to know about z-index, it will only work on an element whose position property has been explicitly set to absolute, fixed, or relative
To deep dive, please check the z-index documentation.
How to Activate Mobile Toolbar on Chrome?
Mobile toolbar shows how your elements are placed in a mobile browser. Using this tool, you can detect almost everything you would expect to see in a mobile browser. You can also inspect and alter your CSS codes easily.
Below image will guide you to how to activate mobile toolbar on Google Chrome.
Other Possibilites For The Problem
1. Javascript Blocking
Using javascript, you can override original behavior of an HTML element. Check below code, this will prevent the real action of the <a> element.
Non-clickable Link
Using JQuery
<script>
$(".prevent-click").click(function(){
return false;
})
</script>
Using Javascript
document.getElementsByClassName("prevent-click")[0].addEventListener('click', function (event) {
event.preventDefault();
return false;
});
Please check your codes carefully, is there any Javascript code to prevent the original action of HTML elements. In addition, to check this quickly, you can disable all javascript codes on Chrome by following steps below.
Open Developer Console
Go to Settings - right top corner of the inspection tool
Check the box (Disable Javascript)
Refresh the page.
Please go in to your CSS and make this change.
.mobile-bg-fix-wrap .mobile-bg-fix-img {
position: absolute;
width: 100%;
height: 125%;
left: 0;
top: 0;
background-size: cover;
}
To:
.mobile-bg-fix-wrap .mobile-bg-fix-img {
position: absolute;
width: 100%;
height: 125%;
background-size: cover;
}
The top and left set to 0 was overlapping the two buttons causing it that you could not click on them.
HTML links not clickable on mobile, but are clickable on desktop.
I have one solution. Try this
Html
<a href="https://www.stackoverflow.com" class="goclick">
css
.goclick{
position: relative;
z-index: 9;
}
For this, go to Google Chrome > Developer tools.
Inspect the element, if it is being overlapped by anything, add clear: both;
to the overlapping element.
Actually, in my issue, it fixed everything.
for me, i had a class with...
z-index: -1
which was forcing the parent <div> to the back. changing this to 0 or simply removing it, solved the problem
ref: https://www.sitepoint.com/community/t/solved-href-not-working/248882/6
I came across this very neat annotation overlay effect: http://tympanus.net/codrops/2012/05/14/annotation-overlay-effect-with-css3/
You can see a live demo here: http://tympanus.net/Tutorials/CSS3AnnotationOverlayEffect/ (you will need to click on the picture there to see the effect)
I am trying to make the text within annotation <span> clickable with some external link, like:
<span>Easy Theme Options</span>
but it doesn't work... whenever I click on the annotation, it transitions back to full size image.
I appreciate any help, thank you!
I made it work, as you see in this Fiddle.
The problem is that the checkbox is always over the spans. And because all the checkbox and the spans are positioned absolute, changing the z-index wouldn't work! The only way I found it to work with only CSS (by not changing to much) is by messing with the pointer-events property and the <div class="ao-annotations">'s z-index. (z-index is layered within an element. Because the annotations <div> and the checkbox are both in <div class="ao-preview">, changing the <span> z-index wouldn't work.
I did the following:
I set the z-index of the div.ao-annotations higher than the input.ao-toggle. This results to not being able to click on the input, so not being able to toggle.
To solve this I added pointer-events: none to the <div class="ao-annotations">. Now the result is the same, but the <span>s are now positioned on top of the input.
To be able to click on the <span>s I added this CSS:
input.ao-toggle:checked ~ .ao-annotations span{
pointer-events: auto;
}
This results to only being able to click on the <span>s when the checkbox is checked.
Summary:
.ao-annotations {
z-index: 20;
pointer-events: none;
}
input.ao-toggle {
z-index: 10;
}
input.ao-toggle:checked ~ .ao-annotations span{
pointer-events: auto;
}
I am very sad to say this only works in IE11 (and all the other browsers)... So you'd probably have to 'hack' with Javascript or rebuild the HTML / CSS.
I hope you can build on this!
Here's a fiddle showing you a demo of the dropdown menu I've written.
The problem:
Part of the text (the site title link in this case) that is below the dropdown menu ("Channels") is unselectable / unclickable, while the other part below the normal "Home" link is rendered just fine. (You can try that in the demo.)
Why I think this is happening: I use JavaScript to dynamically change the height between 0 and auto values when the menu ("Channels") is clicked; NOT something like display: none;, and hence the menu-item element is only hidden, rendering the text that falls beneath it un-selectable/clickable.
The question is, how do I fix this, without breaking the menu's current functionality and style (i.e. transition for dropdown). Everything I've tried, including display: none | block;, visibility: hidden | visible;, and opacity: 0 | 1; have failed me.
EDIT: As seen in the latest versions of Google Chrome and Chromium web browsers.
It work in FF
For Chrome where for some reason the child element (of #channels-menu-item-wrapper) does not respect the overflow:hidden of the parent use (it respects the hidden in a visual manner only..)
You can use a delayed transition and move the sub-element out of the way ..
.collapse > div{
position:relative;
}
.collapse:not(.in) > div {
left:-10000px;
-webkit-transition:left 0s ease;
-webkit-transition-delay:0.35s; /*same delay as the time it takes to open/close so it does not show*/
}
(i have only added the -webkit- vendor specific rule.. apply for all)
Demo at http://jsfiddle.net/gaby/cfH33/5/
Set .collapse div's height and width to 0 using script when clicking on the menu.
Update: Form the #Gaby answer got this hint ".collapse:not(.in)".
.collapse:not(.in){
width:0;
}
This also will work. http://jsfiddle.net/8Mde7/3/
This is what I meant by setting width:0.