Split button dropdown без javascript

в 11:21, , рубрики: css3, custom form elements, html, веб-дизайн, Веб-разработка, метки: , ,

Всем доброго времени суток!

Совсем недавно мне нужно было сотворить некий multi-action control для списка записей. На ум сразу же пришло использование split button dropdown, т.е. в данном случае кнопки отправки формы совмещенной с выпадающим списком экшенов. Подобные контролы не редко можно встретить в современных интерфейсах. Также существуют готовые решения входящие в сборки типа Twitter Bootstrap.

Однако реализации подобные бутстраповским не нравятся по нескольким причинам:

  • излишняя и не совсем нейтивная разметка
  • заточенность под javascript

Именно по этим причинам я решил заделать собственный вариант подобного контрола. Сразу хочу отметить, что все идеи реализовать так и не удалось, поэтому способ не претендует на полную замену js-решениям. Опять же, выкладываю его только для тех, кому будет полезно.

Собственно решение основывается на идеи, изложенной мной в статье Простая кастомизация Checkbox и Radio.

Сразу хочу отметить, что приведенный ниже пример упрощен, поэтому может быть не совсем кросс-браузерным. В нем я решил не концентрировать внимание на полной выкладки стилей, использование браузерных префиксов для свойств, поллифилах и т.п. Хотя вариант без сомнения совершенно рабочий.
Все дальше только код.

Разметка

    <button id="action">Action</button>
    <label for="action">
        <ul>                
            <li title="Edit selected"><input id="edit" type="radio" name="action" value="edit" hidden checked /><label for="edit">Edit</label></li>
            <li title="Delete selected"><input id="delete" type="radio" name="action" value="delete" hidden /><label for="delete">Delete</label></li>
            <li title="Mark selected as read"><input id="read" type="radio" name="action" value="read" hidden /><label for="read">Read</label></li>
            <li title="Mark selected as spam"><input id="spam" type="radio" name="action" value="spam"  hidden /><label for="spam">Spam</label></li>
        </ul>
    </label>

Стили

button, label {cursor: pointer;}
button,
button + label {
    float: left;
    display: inline-block;
    margin: 0;
    background: #659A22 repeat-x;
    background-image: -webkit-linear-gradient(top, #9AC92C, #659A22);
    background-image: -o-linear-gradient(top, #9AC92C, #659A22);
    background-image: -moz-linear-gradient(top, #9AC92C, #659A22);
    background-image: linear-gradient(top, #9AC92C, #659A22);
    border: 1px solid rgba(0, 0, 0, 0.0976563);
    border-bottom-color: rgba(0, 0, 0, 0.246094);
    border-top-color: rgba(255, 255, 255, 0.148438);
    color: #fff;
    font-size: 13px;
    cursor: pointer;
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
    line-height: 16px;
    padding: 5px 10px;
    text-shadow: #659A22 1px 1px 0px;
    -webkit-transition: 0.1s linear all;
    transition: 0.1s linear all;
    vartical-align: middle;
}
button:hover, button + label:hover {
    text-decoration: none;
    background-color: #659A22;
    background-position: 0 -15px;
    -webkit-transition: background-position 0.1s linear;
    -o-transition: background-position 0.1s linear;
    -moz-transition: background-position 0.1s linear;
    transition: background-position 0.1s linear;  
}
button {border-top-left-radius: 3px; border-bottom-left-radius: 3px; }
button:active {
    color: #fff;
    box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);     
}
button + label {
    border-top-right-radius: 3px;
    border-bottom-right-radius: 3px;
    position: relative;   
}
button + label:hover > ul {
    visibility: visible;
    opacity:1;
    margin: 0;  
}
ul {
    visibility: hidden;
    position: absolute;
    top: 30px;
    right: 0;
    width: 90px;
    margin: 20px 0 0 0;
    padding: 10px 0;
    z-index: 9999;
    border: 1px solid #ccc;
    border-top-clor: #cfcfcf;
    border-image: initial;
    background: #fff;
    color: #659A22;
    text-shadow: none;
    opacity: 0;
    box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2);
    border-radius: 3px;
    transition: all 0.2s ease-in-out;
    -webkit-transition: all 0.2s ease-in-out;
    -moz-transition: all 0.2s ease-in-out;
    -o-transition: all 0.2s ease-in-out;
}
 
ul li {
    float: none;
    display: block;
    border: 0;
    line-height: 20px;  
}
ul li input[type="radio"] { display:none; }
ul li input[type="radio"]  + label {
    font-size: 14px;
    width: 70px;
    display: list-item;
    list-style: none;
    vertical-align: baseline;
    padding: 2px 10px;
}
ul li input[type="radio"] + label:hover, ul li input[type="radio"]:checked + label {
    background-color: #659A22;
    background-repeat: repeat-x;
    background-image: -webkit-linear-gradient(top, #9AC92C, #659A22);
    background-image: -moz-linear-gradient(top, #9AC92C, #659A22);
    background-image: -o-linear-gradient(top, #9AC92C, #659A22);
    background-image: linear-gradient(top, #9AC92C, #659A22);
    color: #fff;
    text-shadow: none;
}
ul li input[type="radio"] + label:hover {
    box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);    
}

Вот демка, в которой я также добавил форму и js для отлавливания ее отправки, который выводит alert со значением экшена: Демо. Соответственно ровно таким же способом можно сделать отправку нескольких экшенов, используя вместо радио-кнопок чекбоксы.

Под конец

Итак что получилось, а что нет:

Получилось:

  • представить список radio-кнопок в виде выпадающего меню действий
  • сделать это без javascript нейтивным способом, работающий с обычными формами

НЕ Получилось:

  • вызов списка по клику
  • кросс-браузерная отправка формы при клике на элемент выпадающего списка без javascript

Насчет последнего пункта уточню. Я надеялся реализовать отправку формы по клику на radio-кнопки без необходимости отлавливания событий с помощью javascript. Если точнее, нажатие должно было происходить по самой кнопке, с помощью использования того же способа с label, а также эффекта «всплытия». Однако этот способ возымел действие только в Opera. Она умудряется успешно обрабатывать и клик по label привязанному к radio-кнопке и клик по label привязанному к button и реально отправляет форму. Все остальные браузеры делают интересную вещь — кнопка как бы нажимается, что можно заметить благодаря эффекту на button:active, но форма не отправляется.

На самом деле пока не знаю в чем причина. Либо это опять различия в интерпретации спецификация браузерами, либо я где-то налажал. Если у кого-то есть идеи, прошу поделиться в комментах.

Автор: PaulMaly


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js