Всем доброго времени суток!
Совсем недавно мне нужно было сотворить некий 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