Voiceover reading pseudo-elements despite aria-hidden attributes within <label /> - ios

I'm creating custom radio / checkbox icons by adding a pseudo-element on a label element with the :before css rule. I've added aria-hidden to the label element, but VO on iOS is still reading the pseudo-element.
I understand that some screen readers will ignore an aria-hidden attribute if the element is providing additional context (this is the case for label elements, since they provide additional information about a connected input element). To get around this I've added a aria-label attribute, but again, this is ignore by VO on iOS. This seems to fix the same problem for other screen reader, browser, and device combinations (Narrator and IE / Edge for example).
I've also tried to add a child span or i element to the label and add the :before css rule and aria-hidden attribute to that, but VO on iOS is still reading the pseudo-element.
Does anyone have any advice for having the screen reader read the correct content?
My basic approach is below (note: won't work in a jsfiddle since I'm not loading my font-face).
You can also view the first example here:
http://uatwww.surveygizmo.com/s3/4102902/Basic-Radio
<input type="radio" id="radio1" value="1" name="example" />
<label for="radio1" class="custom-icon" aria-hidden="true" aria-label="example 1">Example 1</label>
<input type="radio" id="radio2" value="2" name="example" />
<label for="radio2">
<span class="custom-icon" aria-hidden="true" aria-label="example 2"></span>
Example 2
</label>
<input type="radio" id="radio3" value="3" name="example" />
<label for="radio3">
<i class="custom-icon" aria-hidden="true" aria-label="example 3"></i>
Example 3
</label>
<style>
input[type=radio] {
opacity: 0;
position: absolute;
border: 0;
height: 0;
margin: 0;
overflow: hidden;
padding: 0;
}
input[type=radio] + .custom-icon:before,
input[type=radio] + label .custom-icon:before {
content: "\26aa";
}
input[type=radio]:checked + .custom-icon:before,
input[type=radio]:checked + label .custom-icon:before {
content: "\26ab";
}
</style>

I think the problem is that you are giving confusing instructions to both the browser and screenreader. You have an invisible input with CSS content attached to it, which is then associated to a label which is aria-hidden but also has an aria-label. You’re definitely going to get inconsistent interpretations of that markup across different browser/screenreader combinations.
I’ve used Heydon Pickering’s custom control method successfully on a bunch of sites with no problems. It seems like a simpler version of what you’re aiming for. It accessibly hides the input from everyone except screenreader software, puts the CSS content on a span instead of the label or input. He doesn’t use any ARIA, but if more recent versions of VoiceOver announce the CSS content you can just put aria-hidden on the span and let screenreaders treat the label and input as normal.

Concerning radio1, the W3C says:
If the current node is hidden and is not referenced by aria-labelledby or aria-describedby, nor referenced by a native host language text alternative element or attribute, return the empty string.
So as long as you reference an element even though it has the aria-hidden attribute, it will be spoken out.
If you want to give an alternative text for an element, you have to set the aria-label attribute on the element:
<input type="radio" id="radio1" value="1" name="example" aria-label="example 1" />
<label for="radio1" class="custom-icon" aria-hidden="true">Example 1</label>
Pseudo elements have different beheviours on browsers, and as you can see the alternative text for :before elements will be given even though the associated element is marked with the aria-hidden attribute.

Related

How to disable field's auoifilling in Chrome with Vaadin?

In all input fields in Chrome appear nonsens texts - some texts, that were written in other text field. It seems, that it is connected with default IDs. It can be probably resolved for text fields with setting custom id with setId(..) method. But it doesn't work for datefields, comboboxes etc. while the id is set for the parent div not the input itself eg.:
<div role="combobox" class="v-filterselect v-widget small v-filterselect-small v-has-width" id="Field-1553856663994" style="width: 100%;" autocomplete="off">
<input type="text" class="v-filterselect-input" autocomplete="nope" id="gwt-uid-134" aria-labelledby="gwt-uid-133" style="width: 100%;" tabindex="0" dir="">
<div class="v-filterselect-button" aria-hidden="true" role="button"></div></div>
Is the way in Vaadin to set id for inner element or to disable completion in Chrome?
Chrome the behavior on autocomplete attribute changed a while ago, but it has been until recently we made a change in our implementation according to that in Vaadin 8.
There is lengthy discssion about this in our issue tracker;:: https://github.com/vaadin/framework/issues/11437

Force label float when no input data in Angular Material

In Angular Material, the default design of input directives is for the content within <label> to be displayed in the input element until the user enters some input, at which point it will float above the input element, as seen in all examples here.
Is there any way to force the labels to float above the input box at all times instead, even when no data has been entered?
I think the css class md-input-has-placeholder is what you need:
<md-input-container class="md-input-has-placeholder">
<label>Name</label>
<input type="text"/>
</md-input-container>
Plunker example here
Hope it helps.
The is an official feature for that: floatLabel="always"
The floatLabel property of can be used to change this default floating behavior. It can set to never to hide the label instead of float it when text is present in the form field control. It can be set to always to float the label even when no text is present in the form field control. It can also be set to auto to restore the default behavior.
<mat-form-field floatLabel="always">
<mat-label>Both a label and a placeholder</mat-label>
<input matInput [(ngModel)]="model.value">
</mat-form-field>
source, see the official form-field documentation
With Md-select this worked for me:
<md-input-container style="width: 200px;" md-input-has-placeholder>
<placeholder>Snack Types </placeholder>
<md-select ng-model="selectedOption">
<md-option ng-repeat="item in snacks" >
{{item.name}}
</md-option>
</md-select>
</md-input-container>
For the md-select element, occupy the following:
<md-input-container class="md-input-has-placeholder">
<label md-no-float="true" class="md-required">Snack Types</label>
<md-select ng-model="$ctrl.selection" ng-required="true" md-no-asterisk>
<md-option ng-value="option.id" ng-repeat="option in $ctrl.selection">{{ opcion.value}}</md-option>
</md-select>
</md-input-container>
I used the following CSS to change the label when data is being entered and highlight the other fields:
md-input-container:focus-within > label[class~="md-required"]{
transform: scale(1);
font-weight: bold;
}
And the following CSS so that the asterisk is always in color (you can put the color you want):
md-input-container.md-default-theme:not(.md-input-focused):not(.md-input-invalid) label.md-required:after, md-input-container:not(.md-input-focused):not(.md-input-invalid) label.md-required:after{
color: rgb(255,87,10);
}

How to style Radiobutton list in jQueryMobile 1.4.2 with formatted content

I'm trying to create something like the following in jQueryMobile 1.4.2 - i.e. a list of radio buttons with content to explain each option. This is a jquery screenshot from version 1.2 from this great article best practices article. The size of the description text is smaller than the body text.
However when I copy his sample code directly from it comes out sized incorrectly like this (other controls shown for reference size).
Here's the sample code
<fieldset data-role="controlgroup">
<input type="radio" name="radio-choice-1" id="radio-choice-1" value="choice-1" checked="checked" />
<label for="radio-choice-1">
<h3 class="ui-li-heading">jQuery Mobile</h3>
<p class="ui-li-desc">Easy and great for all project from smartphones to dumbphones</p>
</label>
<input type="radio" name="radio-choice-1" id="radio-choice-2" value="choice-2" />
<label for="radio-choice-2">
<h3 class="ui-li-heading">Sencha Touch</h3>
<p class="ui-li-desc">Great for complex apps but a higher learning curve</p>
</label>
<input type="radio" name="radio-choice-1" id="radio-choice-3" value="choice-3" />
<label for="radio-choice-3">
<h3 class="ui-li-heading">jQTouch</h3>
<p class="ui-li-desc">Simple, lightweight, but focused on webkit</p>
</label>
</fieldset>
It turns out the reason the above code no longer works is that it references css class name ul-li-desc which used to be in jquery mobile 1.2.1 css but is no longer in the latest css for version 1.4.2.
The new 1.4.2 version has sample code for something very similar in the ListView component that looks like this
The css class that reduces the size of the font here is .ui-listview>li p
So what's the correct way in jQuery Mobile 1.4.2 to create a radio button list with added content that isn't huge?
The easiest way to undetstand jQM CSS structure, is to firebug current view. jQM changes HTML markup based on widget as it adds extra elements and wraps others in order to each the final UI.
Bear in mind, you have to be specific and caucious when overriding jQM styles. Most of the widgets share the same classes (global classes).
Also note that as of jQM 1.4 to increase performance, the team has reduced the amount of inner elements that are you used for styling widgets.
/* <p> within <label> */
label p {
font-size: .9em;
font-weight: 400;
display: block;
}
/* <h3> & <p> within <label> */
label h3, label p {
margin: .45em;
}
/* adjust position of radio button itself */
.ui-radio input, label.ui-btn:after {
top: 35% !important;
}
Demo

Using Angular to set style to display: none broken in IE 10, works elsewhere

I have the following mvc code:
#Html.DropDownListFor(model => model.State, Model.States, new { #class = "form-control",
// Displays if the country is United States
style="display:{{State_Display()}}",
Name="State"})
#Html.TextBoxFor(model => model.State, new { #class = "form-control",
// Displays if the country is not United States
style="display:{{Province_Display()}}",
Name="Province"})
EDIT: I guess I should mention that Province_Display() is a method in my angular controller that either returns the string "none" or "block" depending on the country chosen.
In the latest versions of Chrome and Firefox, this does what you'd expect: if the user picks united states from a different control, the State field is shown and the Province field hidden.
In IE 10 however, both controls display all the time. Inspecting the elements with f12 in IE, neither of them have any style property at all.
The way I'm thinking of solving this would be to use angular to apply an additional CSS class to the elements instead of using angular to dynamically update the inline style, but my question remains:
Why does this work in Chrome and Firefox but not IE? What's being handled differently? Why doesn't anything appear for Style when I inspect in IE? If you know, will my CSS class idea actually fix the issue (before I bother reworking things)? I'd like to understand the cause so I can avoid similar situations in the future. Thanks!
Additional info:
Right-click, view page source (same in both chrome/IE):
<select Name="State" class="form-control" data-val="true" data-val-required="The State field is required." id="State" name="State" style="display:{{State_Display()}}">
<input Name="Province" class="form-control" id="State" name="State" style="display:{{Province_Display()}}" type="text" value="" />
Inspect (Chrome):
<select name="State" class="form-control" data-val="true" data-val-required="The State field is required." id="State" style="display:block">...omitted...</select>
<input name="Province" class="form-control" id="State" style="display:none" type="text" value="">
Inspect (IE):
<select name="State" class="form-control" id="State" data-val-required="The State field is required." data-val="true">
<input name="Province" class="form-control" id="State" type="text" value=""/>
There's still really not enough of your code to go by, but there are a few approaches you can take. The class thing you recommend should work, but there's something in your code we can't see that's causing it to not execute in IE properly. (any errors in your console?) My best guess... you're missing your DTD, or it's set improperly. Try adding this at the top of your html template:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
A better approach (still need to ensure your DTD is set correctly) would be to use ng-show/ng-hide: http://docs.angularjs.org/api/ng.directive:ngHide
<!-- when $scope.myValue is truthy (element is hidden) -->
<div ng-hide="myValue"></div>
<!-- when $scope.myValue is falsy (element is visible) -->
<div ng-hide="myValue" class="ng-hide"></div>
However, if you wish, you can define a css class like so:
.hide {
display:none;
}
and just apply that class to whichever input you wish to hide within you application logic.

Refreshing jQueryMobile styling on radio buttons on the fly

I'm attempting to re-style a vertical group of radio buttons, and the new theme I add to one of them shows up but the theme I remove from another/the rest doesn't go away.
My goal is to change theme of the selected radio button (the related controls, anyway) to make it stand out more when selected.
<div data-role="content">
...
<fieldset data-role="controlgroup" id="showChooser">
<legend><h3>Which show are you attending?</h3></legend>
<input type="radio" name="activeShow" id="activeShow1" value="1" />
<label for="activeShow1">
<h2>Choice 1</h2>
<p>03/25/2012 - 03/27/2012</p>
</label>
<input type="radio" name="activeShow" id="activeShow2" value="2" />
<label for="activeShow2">
<h2>Choice 2</h2>
<p>03/25/2012 - 03/27/2012</p>
</label>
<input type="radio" name="activeShow" id="activeShow3" value="3" />
<label for="activeShow3">
<h2>Choice 3</h2>
<p>03/25/2012 - 03/27/2012</p>
</label>
...
</fieldset>
...
</div>
This results in the following list being displayed:
(source: skitch.com)
So, on-click of one of them, I'm running this code:
$('#showChooser input:radio').click(function(e) {
$("#showChooser label").attr('data-theme','c');
$(this).next().attr('data-theme','e');
$("#settings").page();
});
The first line should, in theory, reset them all to the base-state of theme 'C', and then the second line would highlight the selected item. I can step through and see that these HTML changes are made, so it's obvious that what needs to happen next is for jQuery Mobile to re-parse and update the display.
Note the desperate attempt at refreshing the whole page with .page() at the end -- even that doesn't achieve the desired effect.
The first time you click one, it has the desired effect:
But subsequent clicks don't appear to un-highlight any previously selected rows:
I've also tried $("#showChooser").listview("refresh") and a few other similar things that I can't recall, but none have the desired effect. So what am I missing/doing wrong?
I had the exact same problem.
$('#showChooser input:radio').click(function(e) {
$("#showChooser label").attr('data-theme','c').removeClass('ui-btn-up-e');
$(this).next().attr('data-theme','e').addClass('ui-btn-up-e');
});
See this jQuery forum post.

Resources