Древовидный выбор в HTML

Я пытаюсь создать <select> древовидное изображение с помощью HTML и CSS.

Для обеспечения доступности я бы по возможности избегал использования javascript. Я также хотел бы избежать использования &nbsp; вместо заполнения, так как это предотвращает нажатие буквенных клавиш для перехода к элементам.

На данный момент у меня есть следующее:

<select>
    <optgroup label="fluffy" style="padding-left: 10px;"></optgroup>
        <optgroup label="kitties" style="padding-left: 20px;"></optgroup>
            <option value="1" style="padding-left: 30px;">Fluffykins</option>
            <option value="2" style="padding-left: 30px;">Mr Pooky</option>
        <optgroup label="puppies" style="padding-left: 20px;"></optgroup>
            <option value="3" style="padding-left: 30px;">Doggins</option>

    <optgroup label="not fluffy" style="padding-left: 10px;"></optgroup>
        <optgroup label="snakes" style="padding-left: 20px;"></optgroup>
            <option value="4" style="padding-left: 30px;">Fingers</option>
        <optgroup label="crabs" style="padding-left: 20px;"></optgroup>
            <option value="5" style="padding-left: 30px;">Lucky (AKA Citizen Snips)</option>
</select>

Это отлично работает в Firefox, но IE игнорирует заполнение, отображая его как плоский список (что довольно сложно использовать), а Chrome не отображает <optgroup>s, которые технически недействительны, поскольку <optgroup> должен содержать как минимум <option>.

К сожалению, <optgroup>s не могут быть вложены.

Вот как это обрабатывает Firefox


person Greg    schedule 05.08.2009    source источник
comment
Все HTML и CSS есть   -  person Greg    schedule 05.08.2009


Ответы (5)


С элементом SELECT это не сработает. Вы можете создать собственный SELECT на основе этого:

css:

    * {
        margin: 0;
        padding: 0;
    }

    .select, .select-tree {
        border: 1px solid black;
        width: 200px;
        overflow: hidden;
        list-style-type: none;
        margin: 10px;
    }

    .select .group-label {
        background-color: white;
    }

    .select .option-label {
        background-color: white;
        display: block;
    }

    .select .hidden-checkbox {
        display: none;
    }

    .select .hidden-checkbox:checked + .option-label,
    .select-tree .hidden-checkbox:checked ~ .group-children,
    .select-tree .hidden-checkbox:checked ~ .group-children * {
        background-color: lightblue;
    }

    .select-tree .group-children {
        list-style-type: none;
        padding-left: 20px;
    }
    .select-tree .option-label {
        padding-left: 5px;
    }

    .select-list .level-0 {
        padding-left: 10px;
    }

    .select-list .level-1 {
        padding-left: 20px;
    }

    .select-list .level-2 {
        padding-left: 30px;
    }

html:

выберите много из списка (группы нельзя выбрать):

<ol class="select select-list select-many">
    <li>
        <input name="list1[1]" type="checkbox" id="check1" class="hidden-checkbox"/>
        <label for="check1" class="option-label level-0">option 1</label>
    </li>
    <li>
        <span class="group-label level-0">group 1</span>
    </li>
    <li>
        <input name="list1[2]" type="checkbox" id="check2" class="hidden-checkbox"/>
        <label for="check2" class="option-label level-1">option 2</label>
    </li>
    <li>
        <span class="group-label level-1">group 2</span>
    </li>
    <li>
        <input name="list1[3]" type="checkbox" id="check3" class="hidden-checkbox"/>
        <label for="check3" class="option-label level-2">option 3</label>
    </li>
    <li>
        <input name="list1[4]" type="checkbox" id="check4" class="hidden-checkbox"/>
        <label for="check4" class="option-label level-2">option 4</label>
    </li>
    <li>
        <input name="list1[5]" type="checkbox" id="check5" class="hidden-checkbox"/>
        <label for="check5" class="option-label level-0">option 5</label>
    </li>
</ol>

выберите один из списка (группы нельзя выбрать):

<ol class="select select-list select-one">
    <li>
        <input name="list2" type="radio" id="check6" class="hidden-checkbox"/>
        <label for="check6" class="option-label level-0">option 1</label>
    </li>
    <li>
        <span class="group-label level-0">group 1</span>
    </li>
    <li>
        <input name="list2" type="radio" id="check7" class="hidden-checkbox"/>
        <label for="check7" class="option-label level-1">option 2</label>
    </li>
    <li>
        <span class="group-label level-1">group 2</span>
    </li>
    <li>
        <input name="list2" type="radio" id="check8" class="hidden-checkbox"/>
        <label for="check8" class="option-label level-2">option 3</label>
    </li>
    <li>
        <input name="list2" type="radio" id="check9" class="hidden-checkbox"/>
        <label for="check9" class="option-label level-2">option 4</label>
    </li>
    <li>
        <input name="list2" type="radio" id="check10" class="hidden-checkbox"/>
        <label for="check10" class="option-label level-0">option 5</label>
    </li>
</ol>

выберите один из дерева (группы выбираются):

<ol class="select select-tree select-one">
    <li>
        <input name="tree1" type="radio" id="check11" class="hidden-checkbox"/>
        <label for="check11" class="option-label">option 1</label>
    </li>
    <li>
        <input name="tree1" type="radio" id="check12" class="hidden-checkbox"/>
        <label for="check12" class="option-label group-label">group 1</label>
        <ol class="group-children">
            <li>
                <input name="tree1" type="radio" id="check13" class="hidden-checkbox"/>
                <label for="check13" class="option-label">option 2</label>
            </li>
            <li>
                <input name="tree1" type="radio" id="check14" class="hidden-checkbox"/>
                <label for="check14" class="option-label group-label">group 2</label>
                <ol class="group-children">
                    <li>
                        <input name="tree1" type="radio" id="check15" class="hidden-checkbox"/>
                        <label for="check15" class="option-label">option 3</label>
                    </li>
                    <li>
                        <input name="tree1" type="radio" id="check16" class="hidden-checkbox"/>
                        <label for="check16" class="option-label">option 4</label>
                    </li>
                </ol>
            </li>
        </ol>
    </li>
    <li>
        <input name="tree1" type="radio" id="check17" class="hidden-checkbox"/>
        <label for="check17" class="option-label">option 5</label>
    </li>
</ol>

Только IE9 + (и вы должны указать doctype для msie) ... Я думаю, что вы не можете сделать это без классов css "level-x", потому что для вложенных div'ов отступы также смещают цветной фон метки ...

В IE8 вы должны использовать javascript для раскрашивания меток ...

person inf3rno    schedule 20.03.2012
comment
Я бы по крайней мере использовал вложенные теги ‹UL› или ‹OL›, чтобы поддерживать некоторую семантику. - person Luke H; 03.06.2013
comment
Я изменил пример и добавил дерево с выбираемыми группами. - person inf3rno; 05.06.2013
comment
Вам нужно будет реализовать некоторый javascript для обеспечения удобства использования, так как предполагается, что выборки могут взаимодействовать с клавиатурой. - person Wing; 03.07.2014
comment
Йепп, верно. На самом деле вы можете добавить tabindex к метке, чтобы табулятор работал, но каким-то образом пробел или ввод не работают с меткой, только с вводом. Я предполагаю, что это ошибка браузера, потому что щелчок мышью работает по ярлыку ... - person inf3rno; 03.07.2014
comment
Я добавил отчет об ошибке Firefox. Я жду ответа, и если они это исправят, я отправлю отчет об ошибке команде разработчиков других браузеров. Tabindex не работает с ярлыками с хромом. По msie, он прокручивает до ярлыка, нажимая пробел. - person inf3rno; 08.07.2014
comment
Не исправлено в Firefox через 6 лет. - person inf3rno; 11.02.2021

Как вы заметили, вы не можете вложить одну OPTGROUP в другую. Но вы должны их заключить. Это позволит достичь по крайней мере базового уровня отступа, который вы еще не видите.

<optgroup label="fluffy" style="padding-left: 10px;">
  <optgroup label="&nbsp;&nbsp;&nbsp;kitties" style="padding-left: 20px;">
     <option value="1" style="padding-left: 30px;">Fluffykins</option>
     <option value="2" style="padding-left: 30px;">Mr Pooky</option>
  </optgroup>
  <optgroup label="&nbsp;&nbsp;&nbsp;puppies" style="padding-left: 20px;">
     <option value="3" style="padding-left: 30px;">Doggins</option>
  </optgroup>
</optgroup>

Поскольку вы все равно не можете перейти к заголовкам OPTGROUP с клавиатуры (и только к фактическому OPTION), должно быть нет проблем с добавлением label out с помощью &nbsp; для решения кроссбраузерных проблем с заполнением.

person random    schedule 05.08.2009

Я полагаю, что margin-left не делает того, что вы хотите?

person FrostbiteXIII    schedule 25.09.2009
comment
margin-left на ‹option›, похоже, полностью игнорируется в IE и Chrome - person Greg; 25.09.2009

Вы должны заключить option-Tags в optgroup-Tags.

Должно получиться так:

        <optgroup label="kitties" style="padding-left: 20px;">
            <option value="1" style="padding-left: 30px;">Fluffykins</option>
            <option value="2" style="padding-left: 30px;">Mr Pooky</option>
        </optgroup>
        <optgroup label="puppies" style="padding-left: 20px;">
            <option value="3" style="padding-left: 30px;">Doggins</option>
        </optgroup>

Надеюсь, поможет :)

person ChrisBenyamin    schedule 05.08.2009
comment
Хм? Что ты имеешь в виду? Посмотрите на W3C, и вы увидите пример использования optgroup: w3 .org / WAI / PF / select-offer.html - person ChrisBenyamin; 06.08.2009
comment
Вы связались с предложением, которое никогда не содержало спецификации. В HTML 4.01 optgroups не могут быть вложенными - person Greg; 25.09.2009

Это не совсем хорошее решение, но пробовали ли вы использовать элементы с неразрывными пробелами (& nbsp;)?

person Oliver Hanappi    schedule 25.09.2009