Making my hidden radio buttons tabbable/508 Compli

2019-03-31 04:21发布

问题:

First off, I know there is a duplicate, but I have tried the solution and it does not work for me.

So, I need a faux-segmented control to be tabbable, or at least keyboard selectable. Getting the tab key to highlight the button is easy - I just add

tabindex="0"

To the element I want to be tabbable. Problem is, while I can get it to give the barely perceptible blue outline, I cannot select the button that's highlighted.

The solution proposed in the other question was to make my radio buttons visible with an opacity of zero, but that failed to do anything but ruin the buttons spacing.

The last pertinent I can think of is that the radio buttons themselves are set to.

display:none

Just to be absoluetly clear, selecting this with the mouse works fine - keyboard controls do not work. So, any ideas?

Page code, just in case you need it

<p class="segmented-control">
    @foreach (var ruby in RubricData)
    {
        <input type="radio" id="@ruby.Id" ng-model="rubricStandardId" value="@ruby.Id"/>
        <label for="@ruby.Id" class="sc-label" style="background-color:@ruby.RubricHexColor;" tabindex="0">@ruby.RubricSymbol
        <span class="sc-tooltip">@ruby.RubricStandard</span></label>

    }
</p>

回答1:

If I understand what you're trying to accomplish, you would style the input's label to reflect the state of the visually hidden radio input (such as: not focused and not checked, focused but not checked, focused and checked).

When you first tab into the radio control, the first option will be focused but not selected. You can then either check/select the first option by pressing spacebar or you can check/select an adjacent option using the arrow keys.

Pressing tab from within the radio control will bring you to the next tabbable element on the page, not the next option in the radio control.

Also, in your code above (OP), your radio input elements are missing a name attribute which means that each of your radio inputs that your for loop produces are treated as individual controls as opposed to multiple options for one control.

And according to WebAIM on keyboard accessibility testing and tabindex, only non-link and non-form elements need tabindex="0":

tabindex="0" allows elements besides links and form elements to receive keyboard focus. It does not change the tab order, but places the element in the logical navigation flow, as if it were a link on the page.

Run the code snippet below to see a working example. The snippet <p> text will provide some more reference.

.segmented-control {
  border: 0;
}
.segmented-control label{
    background: #f00;
    border:1px solid #000;
    padding:10px 20px;
    margin:5px 0;
    max-width:200px;
    clear:both;
    display: inline-block;
    cursor:pointer;
    color: #fff;
}

.segmented-control label[for="0"] {
  background: #ccc;
}

.segmented-control label[for="1"] {
  background: #ce0002;
}

.segmented-control label[for="2"] {
  background: #ff690b;
}

.segmented-control label[for="3"] {
  background: #ffb605;
}

.segmented-control label[for="4"] {
  background: #6ea458;
}

.segmented-control label[for="5"] {
  background: #3a7428;
}

.segmented-control input[type='radio']{
    margin-left: -2rem;
    opacity: 0;
    position: absolute;
}

.segmented-control input[type='radio']:checked + label{
    outline: 3px solid blue;
}

.segmented-control input[type='radio']:focus:not(:checked) + label{
    outline: 3px solid green;
}
<p>Select this text then tab into the form radio control.</p>
<p>Tabbing into the fieldset will bring focus to the first option (but it will not select / check it).</p>
<p>Once the radio control has focus, you can hit spacebar to select that first option, and/or use up/down or right/left arrow to select (check) other options.</p>
<p><span style="color:green;">Green</span> outline = focused but not checked.  <span style="color:blue;">Blue</span> outline = focused + checked.</p>
<p>Once your option is selected, press tab to move focus to the next focusable element, which is the link in the paragraph below the fieldset.</p>
  
<fieldset class="segmented-control">
  <input name="radio1" id="0" class="sc-label" type="radio" value=>
  <label for="0">
    <span class="sc-tooltip">-</span>
  </label>
  
  <input name="radio1" id="1" class="sc-label" type="radio">
  <label for="1">
    <span class="sc-tooltip">1</span>
  </label>

  <input name="radio1" id="2"class="sc-label" type="radio">
  <label for="2">
    <span class="sc-tooltip">2</span>
  </label>
  
  <input name="radio1" id="3"class="sc-label" type="radio">
  <label for="3">
    <span class="sc-tooltip">3</span>
  </label>
  
  <input name="radio1" id="4"class="sc-label" type="radio">
  <label for="4">
    <span class="sc-tooltip">4</span>
  </label>
  
  <input name="radio1" id="5"class="sc-label" type="radio">
  <label for="5">
    <span class="sc-tooltip">5</span>
  </label>
</fieldset> 

<p>A paragraph with a <a href="#">tabbable link</a>.



回答2:

You can use the label to wrap the input, and hide the input.

<style type="text/css">
    input[type="radio"] { opacity: 0; position: absolute; }
    input:checked + .sc-tooltip { background: red; color: white; }
    input:focus + .sc-tooltip { box-shadow: 0 0 3px 1px blue; }
</style>

<p class="segmented-control">
    <fieldset>
        <input type="text">
    </fieldset>

    <fieldset>
        <label>
            <input class="sc-label" type="radio" name="radio" id="radio1" checked>
            <span class="sc-tooltip">Tabbable</span>
        </label>

        <label>
            <input class="sc-label" type="radio" name="radio" id="radio2">
            <span class="sc-tooltip">Tabbable</span>
        </label>

        <label>
            <input class="sc-label" type="radio" name="radio" id="radio3">
            <span class="sc-tooltip">Tabbable</span>
        </label>
    </fieldset>

    <fieldset>
        <input type="text">
    </fieldset>
</p>