[CSS, HTML, Разработка веб-сайтов] Еще раз о визуализации input типа checkbox и radio. Для тех, кто забыл как
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Тема старая и уже, как выяснилось, подзабытая.
Недавно у меня была короткая работа по разработке ТЗ на модернизацию давно существующего проекта. И, в частности дело касалось стилизации пресловутых <input type="checkbox">. Выяснилось, что исполнитель, программист «на все руки» даже не понял, что я ему на словах объяснял как это сделать. Пришлось делать примеры и, как результат, появился этот текст.
Напомню, что сейчас checkbox и radiobox разные сайты изображают по-разному. Бывает, что не отмеченный input сразу и не разглядишь – такой он «дизайнерский красивый», а у последних версий Chrome выбранные checkbox стали гнусного цвета циан.
Итак, ситуация
Есть три компании, которые используют некий программный продукт, связанный с заказами, бухгалтерией, складом и пр. Работа с заказчиками, партнерами, исполнителями и пр.
Маркетологи и рекламщики тоже его используют. Что эта система делает – неважно, на чем написано – неважно.
А важно, что на сайте этого продукта есть много страниц с формами, на которых много input checkbox и radio.
Жалобы сотрудников
Директор: На большом экране плохо видно и незаметны «крыжики».
Главбух: На моем компе «крыжики» выглядят так, у сотрудниц иначе, дома тоже не так, а на планшете совсем иначе.
Маркетолог: А можно, так что бы некоторые не выбранные позиции были красными, а другие выбранные были зелеными?
И т.д., и т.п.
Итак, задача
- Минимальными затратами и минимальными изменениями исправить внешний вид checkbox и radiobox.
- Сделать стилизацию checkbox и radiobox для разных юзеров. Важно: это закрытый сайт, там «всё свои», «красоты» не нужны, а нужна эффективность восприятия.
Что нельзя
1. Серверную часть трогать нельзя.
2. Файлы javascript трогать нельзя, свой javascript вставлять нельзя.
3. Файлы css трогать нельзя.
А что можно
1. Править html шаблоны.
2. Создать файл стилей для всех юзеров.
4. Создать файл стилей для конкретного юзера или группы юзеров.
А что сделали можно сразу посмотреть на codepen.io, но лучше почитать дальше.
Предварительное изучение показало
1. Почти все <input type="checkbox"> имеют поле name, а которые не имеют, то у них есть id.
2. Все <input type="radio"> имеют поле name, некоторые имеют id.
3. Соответственно, в css к checkbox можно обращаться как по id, так и по name. К radio – или по id, или по номеру потомка у родителя.
Фрагменты исходного кода:
/* вариант 1 */
<tag><input type="checkbox"> Некий текст</tag>
/* вариант 2 */
<tag><input type="checkbox"> Некий текст<br>
<input type="checkbox"> Некий текст</tag>
/* вариант 3 */
...<label><input type="checkbox"> Некий текст</label>...
/* вариант 4 */
<td><input id="idxxx" type="checkbox"></td>
<td><label for="idxxx">Некий текст</label></td>
Так исправим код:
/* вариант 1 */
<tag><label class="new-input"><input type="checkbox"><s></s><span>Некий текст</span></label></tag>
/* вариант 2 */
<tag><label class="new-input"><input type="checkbox"><s></s><span>Некий текст</span></label><br>...</tag>
/* вариант 3 */
...<label class="new-input"><input type="checkbox"><s></s><span>Некий текст</span></label>...
/* вариант 4 */
<td><label class="new-input new-input-one"><input id="idxxx" type="checkbox"><s></s></label></td>
<td><label for="idxxx">Некий текст</label></td>
Всё тоже самое и для <input type="radio">, класс у LABEL тот же.
Что конкретно сделали?
- Каждый input (корме варианта 3) обернули тэгом LABEL с нашим классом. Варианту 3 просто добавили класс.
- Сразу после input вставили пустой тэг S. Так как сам input будет не видим, то это тэг будет визуализировать это input.
- Сопроводительный текст обернули тэгом SPAN (кроме варианта 4). Этот тэг понадобиться, когда будем решать вопрос выравнивания визуального input относительно этого текста.
- Варианту 4 добавили еще класс, что бы не осуществлять это выравнивание, раз сопроводительный текст стоит в другой ячейки таблицы. Строго говоря, надо было бы сделать на оборот – вариантам 1-3 добавить класс, отвечающий за выравнивание. Но, вариантов 1-3 гораздо больше, чем 4-го и что бы не раздувать html сделано так.
Риторические вопросы и риторические же ответы
SPL
1. Зачем тэг S? Ну, не нравится S – можно использовать любой другой строчный элемент. Просто он должен быть, его можно стилизовать в зависимости от состояния предшествующего input.
2. Почему тэги S и SPAN без классов? Ну, зачем раздувать html? Тем более, что не очевидно, что одна из конструкций ниже будет «работать» медленнее другой.
.new-input > S { }
.new-input > .new-input-S {}
3. Как вы догадались, мне не нравятся идеи БЭМ, тем более идея «раздувать» html файл обилием упоминаний разных классов. В реальном проекте мы использовали только два класса – mni и mnio. :-))
Некоторые предварительные рассуждения и настройки css касательно box-sizing:border-box, нормализации LABEL, селекторов «A + B», «A ~ B» и «[attr]», псевдоклассов :checked, :disabled и ::before. Кто не уверен, что знает или хочет освежить знания смотрит под катом.
Предварительные рассуждения
SPL
1. Напомню, что в «старом» css (box-sizing:content-box) свойства width и height задают только ширину и высоту содержимого, а padding и border добавляются к этим значениям. box-sizing:border-box меняет схему так, что padding и border включаются в width и height.
2. Проверка показала, что в нашем случае используется старая модель, а менять «настройки» страниц запрещено. Не «наши» LABEL это простые строчные элементы, в них только текст. Поэтому стилизуем ВСЕ LABEL.
LABEL {
box-sizing:border-box; cursor:pointer; user-select:none;
}
LABEL *,
LABEL *::before,
LABEL *::after {
box-sizing:inherit;
}
Т.е., ставим box-sizing:border-box для тэга LABEL, всем его потомкам. Заодно ставим курсор и запрещаем выделение текст (что бы не мешало клику).
3. Комбинация селекторов «A + B» означает, что стили будут применяться только к селектору B, если он следует сразу ПОСЛЕ селектора A, т.е. только для первого B. С другой стороны, «A ~ B» означает, что ко всем селекторам B после селектора A, т.е. для первого и последующих.
Естественно, всё в пределах одного «родителя».
Как это будем использовать?
<label class="new-input"><input type="checkbox"><s></s><span>Некий текст</span></label>
<label class="new-input"><input type="radio"><s></s><span>Некий текст</span></label>
/* 1 */
.new-input > INPUT + S {}
.new-input > INPUT ~ SPAN {}
/* 2 */
.new-input > INPUT:not(:checked) + S {}
.new-input > INPUT:not(:checked) ~ SPAN {}
/* 3 */
.new-input > INPUT:checked + S {}
.new-input > INPUT:checked ~ SPAN {}
/* 4 */
.new-input > INPUT:disabled + S {}
.new-input > INPUT:disabled ~ SPAN {}
/* 5 */
.new-input > INPUT[type="radio"] + S {}
Первая группа – общие стили для тэгов S и SPAN.
Вторая группа – стили только когда INPUT НЕ выбран.
Третья – стили только когда INPUT выбран.
Четвертая – когда INPUT заблокирован.
И, наконец, пятая группа – общие стили для тэга S ТОЛЬКО, если он стоит после input radio.
Таким образом, можно изменять стили тэгов S и SPAN в зависимости от состояния input.
4. Поскольку у нас тэг S будет изображать из себя input, то самому input поставим display:none, его не будет видно, а тэг LABEL будет его переключать, а тэг S будет соответственно меняться. Почему не используем html свойство hidden у input? Потому, что на некоторых браузерах hidden у input «работает» не совсем верно, плюс не будем перегружать html файл.
Итак, начинаем визуализацию input
Пример N 1. Самый простой – используем алфавитные символы
html код тот же, а css будет такой:
/* s1 */
.new-input > INPUT + S::before {
content: "c";
}
/* s2 */
.new-input > INPUT:checked + S::before {
content: "V";
}
/* s3 */
.new-input > INPUT[type="radio"] + S::before {
content: "r";
}
/* s4 */
.new-input > INPUT[type="radio"]:checked + S::before {
content: "X";
}
/* s5 */
.new-input > INPUT:disabled + S::before {
opacity: 0.5;
}
/* s6 */
.new-input > S {
text-decoration: none;
margin-left: 3px;
margin-right: 6px;
}
/* s7 */
.new-input > S::before {
display: inline-block;
width: 1.25em;
text-align: center;
color: #fafafa;
background-color: #37474f;
}
/* s8 */
.new-input > INPUT[type="radio"] + S::before {
border-radius: 50%;
}
Тэг S буде визуализировать input. Но мы «разделим» его по функционалу: сам тэг S будет отвечать за размещение в LABEL и выравнивание относительно следующего SPAN.
А псевдоэлемент S::before разместится внутри тэга S и будет изображать из себя input.
Строка s1 определяет, какой символ будет помещен в S::before когда input не выбран. В принципе надо было бы написать «.new-input > INPUT:not(:checked) + S::before», но некоторые браузеры (например, IE), подобную конструкцию могут и не исполнить.
Строка s2 определяет символ, когда input выбран.
Строки s3 и s4 делают то же для input radio.
Строка s5 описывает, что будет если input заблокирован – в данном случае тэг S будет наполовину прозрачным.
Строка s6 определяет выравнивание, в данном случае дает отбивку слева и справа (только в этом примере). Плюс, убирает штатное перечеркивание.
Строка s7 делает квадратик, s8 превращает его в кружок для input radio.
Пример N 1 можно посмотреть на codepen.io. Там представлены нативные input и новые. Первые можно убрать.
Чуток подробнее про display: inline-block, font-size, line-height
SPL
Конченая высота строки текста определяется на основе заданных font-size, line-height. При единичном line-height – высота будет по font-size, при числовом line-height – высота будет по их произведению или, при указании единиц измерения для line-height – высоту определит максимальное значение. В примере указан line-height:1.25, поэтому и у S::before указано width:1.25em.
Для S::before указано display: inline-block – в этом случае S::before «внутри» себя будет блоком (можно указать ширину, высоту, рамки и пр.), а «снаружи» он останется строчным элементом. В дальнейшем об этом будет подробнее.
Вопрос:
Может можно использовать специальные символы? Типа вот этих:
□ ■ ▢ ▣ ○ ● ◎◉
Задать им нужный размер и всё. Нет?
Ответ:
Можно. Но не нужно. Ибо будет большой геморрой и танцы с бубнами по заданию нужного размера, выравнивания по вертикали, обрезке по высоте и прочее. Плюс, разные браузеры с этими символами работают по-разному.
Мы пошли другим путем. Хотя в финальном примере есть реализация этой идеи.
Пример N 2. «Рисуем» элементы input средствами css
html код тот же, а css будет такой:
/* s1 */
.new-input > S::before {
content: "";
display: inline-block;
width: 0.75em;
height: 0.75em;
border: 1px solid currentColor;
padding: 2px;
background-clip: content-box;
border-radius: 20%;
}
/* s2 */
.new-input > INPUT[type="radio"] + S::before {
border-radius: 50%;
}
/* s3 */
.new-input > INPUT:checked + S::before {
background-color: currentColor;
}
/* s4 */
.new-input > INPUT:disabled + S::before {
opacity: 0.5;
}
/* s5 */
.new-input > S {
text-decoration: none;
margin-left: 3px;
margin-right: 6px;
}
Строка s1 определяет S::before для визуализации input. Это будет inline-block, ширина и высота которого установлена в 0.75em, что примерно равно высоте прописной буквы и зависит от font-size родителя. Задана тонкая рамка текущим цветом, внутренняя отбивка, небольшое скругление углов. И – самое важное! – установлено свойство background-clip:content-box. Это очень интересное свойство – если будет установлен background-color, то он закрасит только контентную часть и не затронет отбивку (padding). Что нам и надо.
Строка s2 для input типа radio делает S::before круглым.
Строка s3 для отмеченного input устанавливает для S::before background-color текущим цветом. Т.е., «рисует» внутри квадратик или кружок.
Строка s4 отрабатывает блокировку input, строка s5 дает отбивки слева и справа.
Преимущества этого метода
- Всё очень просто. Работает на всех браузерах. Даже у IE10 (в эмуляции у 11-го).
- Можно раскрашивать по своему усмотрению.
- Раз S::before это inline-block, то он сидит на попе базовой линии ровно и никуда с нее не слезает. Если он по высоте будет больше текста, то просто увеличит высоту строки и останется на базовой линии.
- Раз визуализация input находится внутри тэга S, то его можно легко позиционировать и выравнивать.
- Размеры S::before в em дают возможность задавать его размер относительно размера текста подписи. Можно, к примеру, поставить предельные значения высоты и ширины.
Недостатки этого метода
В основном в использовании размеров в em. Дело в том, что может возникнуть ситуация когда ширина и высота при расчете (из em в px) будет иметь дробное значение. На обычных компьютерах с обычным экраном округление может произойти не корректно. Например, размеры 12.8px на 12.8px у той же Мозилы могут стать как 13px на 12px. Тогда надо ставить фиксированные размеры. Хотя на современных мониторах и видеокартах, ноутбуках, на планшетах и смартфонах этого не происходит из-за того, что точка (пиксель) браузера состоит из нескольких пикселей экрана.
Пример N 2 можно посмотреть на codepen.io. Там представлены нативные input и новые. Первые можно убрать.
Итак, первую задачу – визуализацию input – выполнили. Переходим к избранной «раскраске».
Раскрашиваем input
html для примера:
<label class="new-input"><input name="chb1" type="checkbox" ...><s></s><span>Некий текст</span></label>
<label class="new-input"><input id="rb1" type="radio" ...><s></s><span>Некий текст</span></label>
К input типа checkbox будем обращаться по name, к radio по id.
Всё красим в синий
/* только input */
.new-input > INPUT[name="chb1"] + S,
.new-input > INPUT#rb1 + S {
color: #0091ea;
}
/* только text */
.new-input > INPUT[name="chb1"] ~ SPAN,
.new-input > INPUT#rb1 ~ SPAN {
color: #0091ea;
}
/* или всё */
.new-input > INPUT[name="chb1"] ~ *,
.new-input > INPUT#rb1 ~ * {
color: #0091ea;
}
Помним о специфичности в css, эти стили будут более специфичны, чем базовые и сработают обязательно. Чем они отличаются от описанных выше? Тем, что применяются только к избранным input – к тем, что имеет указанное значение name и id.
Тут всё хорошо кроме того, что не выбранные input будут не очень хорошо глядеться – тонкая синяя рамка мало заметна.
Красим в зеленый, когда input выбран
/* только input */
.new-input > INPUT[name="chb1"]:checked + S,
.new-input > INPUT#rb1:checked + S {
color: #00c853;
}
/* только text */
.new-input > INPUT[name="chb1"]:checked ~ SPAN,
.new-input > INPUT#rb1:checked ~ SPAN {
color: #00c853;
}
/* или всё */
.new-input > INPUT[name="chb1"]:checked ~ *,
.new-input > INPUT#rb1:checked ~ * {
color: #00c853;
}
Первый вариант, на мой взгляд, не очень хорош – зеленым будут и рамка, и внутренний квадратик/кружок. Можно раскрасить только его.
/* только input и только внутри */
.new-input > INPUT[name="chb1"]:checked + S::before,
.new-input > INPUT#rb1:checked + S::before {
background-color: #00c853;
}
Красим в красный, когда input НЕ выбран
/* только input */
.new-input > INPUT[name="chb1"]:not(:checked) + S,
.new-input > INPUT#rb1:not(:checked) + S {
color: #d50000;
}
/* только text */
.new-input > INPUT[name="chb1"]:not(:checked) ~ SPAN,
.new-input > INPUT#rb1:not(:checked) ~ SPAN {
color: #d50000;
}
/* или всё */
.new-input > INPUT[name="chb1"]:not(:checked) ~ *,
.new-input > INPUT#rb1:not(:checked) ~ * {
color: #d50000;
}
Логика понятна? Можно и дальше делать более сложные конструкции.
Например, при не выбранном input текст должен быть красным и жирным, а при выбранном внутренний элемент input и текст должен быть зеленым. Элементарно!
/* текст, когда нет выбора */
.new-input > INPUT[name="chb1"]:not(:checked) ~ SPAN,
.new-input > INPUT#rb1:not(:checked) ~ SPAN {
color: #d50000;
font-weight: bold;
}
/* внутренний элемент input, когда выбран */
.new-input > INPUT[name="chb1"]:checked + S::before,
.new-input > INPUT#rb1:checked + S::before {
background-color: #00c853;
}
/* текст, когда выбран */
.new-input > INPUT[name="chb1"]:checked ~ SPAN,
.new-input > INPUT#rb1:checked ~ SPAN {
color: #00c853;
}
А, к примеру, надо обработать целую группу input (10-15 штук). Что бы не писать кучу строк можно найти их общего родителя (.parent_element) и сократить условие.
.parent_element > .new-input > INPUT:not(:checked) ~ SPAN {
color: #d50000;
font-weight: bold;
}
.parent_element > .new-input > INPUT:checked + S::before {
background-color: #00c853;
}
.parent_element > .new-input > INPUT:checked ~ SPAN {
color: #00c853;
}
Всё можно посмотреть в финальном примере на codepen.io
Вот, вроде как, и всё. Осталось только «почесать родимые пятна» перфекциониста – проблемы выравнивания.
Выравнивание визуального input и сопроводительного текста
Для начала напомню общеизвестные вещи на тему размещения текста, форматирования и прочего. Всё под катом.
Общеизвестные вещи
SPL
Буду стараться не применят специальные термины, ибо в дизайне, верстке и css они иногда отличаются. Всё простыми словами.
1. Свойство font-size не определяет размер букв, а только размер знакоместа. Есть базовая линия (baseline), по которой расположены «нормальные» буквы. У «ненормальных» – g ц – нижние элементы «свисают» ниже её. Есть линия капители (cap height) – это верхняя граница «нормальной» прописной (заглавной) буквы. У «ненормальных» – Ё Й – верхние элементы «вылезают» выше её. Иными словами, размер прописной буквы это расстояние от базовой линии до капители, а знакоместо это чуть больше сверху и снизу. Обычно в «нормальных» шрифтах высота капители это 75% от высоты знакоместо. К примеру, font-size:16px, а размер буквы Н у шрифта Arial будет 12px. Но, бывают «специалисты» у шрифтов которых всё не так.
2. Свойство line-height определяет высоту строки. Если его вычисленное значение больше, чем указано в font-size, то браузер разместит текст так, что бы нормальная прописная буква была по середине высоты строки. Есть нюансы, но тут они не важны.
3. Соответственно, в нашем случае тэги S и SPAN должны иметь одинаковые значения font-size и line-height желательно заданные где-то выше у родителей. В нашем случае в примерах font-size:16px и line-height:1.25. Поэтому в примере N1 у S::before ширина указана 1.25em, а высота у него определяется автоматически. А в примере N2 (и финальный пример) – у S::before ширина и высота 0.75em, что бы был по высоте с прописную букву. Задав другое значение font-size ничего менять не надо. Естественно, эту величину надо подогнать под конкретный шрифт.
4. Если перед текстом стоит какая-то квадратная или круглая «штучка», то любой дизайнер скажет, что она должна быть по высоте с прописную букву. А отбивка между ними должна быть в определенных процентах от размера шрифта. Если высота меньше высоты буквы, то она должна быть визуально значительно меньше, но не меньше 50%. Если больше, то тоже визуально значительно больше, но не больше 150%. А вот чуть-чуть, на пару пикселей больше/меньше – это ужас-ужас! Ну, и расположена эта штучка должна быть на базовой линии или по середине без всяких там чуть-чуть.
Зачем я это упомянул? А затем, что перфекционисту глаза режет, когда input криво стоит рядом с текстом — или прилипает, или далеко, или чуть меньше, или чуть больше. Мы так делать не должны!
Что будет, если сопроводительный текст в SPAN будет выведен в две или три строки? Очевидно, что он «залезет» под input. Это не красиво, надо исправить.
Один древний метод такой: тэгу S делаем float:left, а тэгу SPAN display:block и overflow:hidden.
Получится колонка текста. Подразумевается, что у кого-то из них будет соответствующий margin, что даст отбивку между ними. Ну, ещё добавляется геморрой с прекращением float после SPAN. Мы пойдем современным путем – применим flexbox. Он тут совершенно к месту.
.new-input {
display: flex;
flex-direction: row;
align-items: start;
}
.new-input > S {
margin-right: 4px;
flex: 0 0 auto;
}
.new-input > SPAN {
flex: 0 1 auto;
}
В этом случае тэг LABEL (который .new-input) будет flex, S и SPAN будут блоками, разместятся вверху LABEL. Текст в SPAN в случае необходимости будет в несколько строк. Вот из-за этого визуальный input описали в S::before. Независимо от высоты SPAN S::before будет расположен на одной базовой линии с первой строкой SPAN. Как вариант можно было указать align-items:center – тогда при однострочном SPAN визуальный input был бы вверху, а при двух строках – посередине, а при трех – у второй строки. В финальном примере можно переключать расположение input.
Вот и всё
Надеюсь, было интересно и кому-нибудь полезно. Прошу, не сильно меня ругать – это мой первый опыт на Хабр.
Пример N 1 – просто демонстрация взаимодействия изменения input и соседнего элемента.
Пример N 2 – визуализация input средствами css, как основа решения.
Финальный пример – всё описанное вместе.
Про конкретную реализацию
Там были обширные формы, где блоки полей возможные для правки конкретным пользователям выделялись слабым фоном, а остальным input имели свойство disabled и служили только для информации. Поэтому стиль «.new-input > INPUT:disabled + S::before» не применяли.
===========
Источник:
habr.com
===========
Похожие новости:
- [CMS, Разработка веб-сайтов, Laravel] Создание кастомного плагина для October CMS (перевод)
- [JavaScript, Программирование, Разработка веб-сайтов] 155 вопросов по JavaScript
- [Разработка веб-сайтов, JavaScript, Node.JS] Установка и обновление зависимостей в JavaScript
- [Интерфейсы, Программирование, Разработка веб-сайтов, Учебный процесс в IT] Задачи для фронтенд-тренировки: реализуем отдельные элементы интерфейсов YouTube, Instagram, Spotify, GitHub (перевод)
- [Разработка веб-сайтов, JavaScript, Программирование, ReactJS] Типичные ошибки джунов, использующих React (перевод)
- [HTML] «Чек-лист верстки»: как избавить себя от правок и угодить заказчику
- [HTML] 10 лучших инструментов для HTML-верстки
- [Развитие стартапа, Разработка веб-сайтов, Управление продуктом] Как выбрать компанию для реализации своего IT-стартапа?
- [CSS, HTML, JavaScript, Программирование, Разработка игр] Создание браузерных 3d-игр с нуля на чистом html, css и js. Часть 1/2
- [JavaScript, Программирование, Разработка веб-сайтов, Учебный процесс в IT] Задачки для фронтенд-тренировки: doodle-place, Apple Podcasts, Site Blocker, парсинг CSV-файлов (перевод)
Теги для поиска: #_css, #_html, #_razrabotka_vebsajtov (Разработка веб-сайтов), #_input, #_checkbox, #_radio, #_flex, #_flexbox, #_css, #_html, #_razrabotka_vebsajtov (
Разработка веб-сайтов
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 02:18
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Тема старая и уже, как выяснилось, подзабытая. Недавно у меня была короткая работа по разработке ТЗ на модернизацию давно существующего проекта. И, в частности дело касалось стилизации пресловутых <input type="checkbox">. Выяснилось, что исполнитель, программист «на все руки» даже не понял, что я ему на словах объяснял как это сделать. Пришлось делать примеры и, как результат, появился этот текст. Напомню, что сейчас checkbox и radiobox разные сайты изображают по-разному. Бывает, что не отмеченный input сразу и не разглядишь – такой он «дизайнерский красивый», а у последних версий Chrome выбранные checkbox стали гнусного цвета циан. Итак, ситуация Есть три компании, которые используют некий программный продукт, связанный с заказами, бухгалтерией, складом и пр. Работа с заказчиками, партнерами, исполнителями и пр. Маркетологи и рекламщики тоже его используют. Что эта система делает – неважно, на чем написано – неважно. А важно, что на сайте этого продукта есть много страниц с формами, на которых много input checkbox и radio. Жалобы сотрудников Директор: На большом экране плохо видно и незаметны «крыжики». Главбух: На моем компе «крыжики» выглядят так, у сотрудниц иначе, дома тоже не так, а на планшете совсем иначе. Маркетолог: А можно, так что бы некоторые не выбранные позиции были красными, а другие выбранные были зелеными? И т.д., и т.п. Итак, задача
Что нельзя 1. Серверную часть трогать нельзя. 2. Файлы javascript трогать нельзя, свой javascript вставлять нельзя. 3. Файлы css трогать нельзя. А что можно 1. Править html шаблоны. 2. Создать файл стилей для всех юзеров. 4. Создать файл стилей для конкретного юзера или группы юзеров. А что сделали можно сразу посмотреть на codepen.io, но лучше почитать дальше. Предварительное изучение показало 1. Почти все <input type="checkbox"> имеют поле name, а которые не имеют, то у них есть id. 2. Все <input type="radio"> имеют поле name, некоторые имеют id. 3. Соответственно, в css к checkbox можно обращаться как по id, так и по name. К radio – или по id, или по номеру потомка у родителя. Фрагменты исходного кода: /* вариант 1 */
<tag><input type="checkbox"> Некий текст</tag> /* вариант 2 */ <tag><input type="checkbox"> Некий текст<br> <input type="checkbox"> Некий текст</tag> /* вариант 3 */ ...<label><input type="checkbox"> Некий текст</label>... /* вариант 4 */ <td><input id="idxxx" type="checkbox"></td> <td><label for="idxxx">Некий текст</label></td> Так исправим код: /* вариант 1 */
<tag><label class="new-input"><input type="checkbox"><s></s><span>Некий текст</span></label></tag> /* вариант 2 */ <tag><label class="new-input"><input type="checkbox"><s></s><span>Некий текст</span></label><br>...</tag> /* вариант 3 */ ...<label class="new-input"><input type="checkbox"><s></s><span>Некий текст</span></label>... /* вариант 4 */ <td><label class="new-input new-input-one"><input id="idxxx" type="checkbox"><s></s></label></td> <td><label for="idxxx">Некий текст</label></td> Всё тоже самое и для <input type="radio">, класс у LABEL тот же. Что конкретно сделали?
Риторические вопросы и риторические же ответыSPL1. Зачем тэг S? Ну, не нравится S – можно использовать любой другой строчный элемент. Просто он должен быть, его можно стилизовать в зависимости от состояния предшествующего input.
2. Почему тэги S и SPAN без классов? Ну, зачем раздувать html? Тем более, что не очевидно, что одна из конструкций ниже будет «работать» медленнее другой. .new-input > S { }
.new-input > .new-input-S {} 3. Как вы догадались, мне не нравятся идеи БЭМ, тем более идея «раздувать» html файл обилием упоминаний разных классов. В реальном проекте мы использовали только два класса – mni и mnio. :-)) Некоторые предварительные рассуждения и настройки css касательно box-sizing:border-box, нормализации LABEL, селекторов «A + B», «A ~ B» и «[attr]», псевдоклассов :checked, :disabled и ::before. Кто не уверен, что знает или хочет освежить знания смотрит под катом. Предварительные рассужденияSPL1. Напомню, что в «старом» css (box-sizing:content-box) свойства width и height задают только ширину и высоту содержимого, а padding и border добавляются к этим значениям. box-sizing:border-box меняет схему так, что padding и border включаются в width и height.
2. Проверка показала, что в нашем случае используется старая модель, а менять «настройки» страниц запрещено. Не «наши» LABEL это простые строчные элементы, в них только текст. Поэтому стилизуем ВСЕ LABEL. LABEL {
box-sizing:border-box; cursor:pointer; user-select:none; } LABEL *, LABEL *::before, LABEL *::after { box-sizing:inherit; } Т.е., ставим box-sizing:border-box для тэга LABEL, всем его потомкам. Заодно ставим курсор и запрещаем выделение текст (что бы не мешало клику). 3. Комбинация селекторов «A + B» означает, что стили будут применяться только к селектору B, если он следует сразу ПОСЛЕ селектора A, т.е. только для первого B. С другой стороны, «A ~ B» означает, что ко всем селекторам B после селектора A, т.е. для первого и последующих. Естественно, всё в пределах одного «родителя». Как это будем использовать? <label class="new-input"><input type="checkbox"><s></s><span>Некий текст</span></label>
<label class="new-input"><input type="radio"><s></s><span>Некий текст</span></label> /* 1 */
.new-input > INPUT + S {} .new-input > INPUT ~ SPAN {} /* 2 */ .new-input > INPUT:not(:checked) + S {} .new-input > INPUT:not(:checked) ~ SPAN {} /* 3 */ .new-input > INPUT:checked + S {} .new-input > INPUT:checked ~ SPAN {} /* 4 */ .new-input > INPUT:disabled + S {} .new-input > INPUT:disabled ~ SPAN {} /* 5 */ .new-input > INPUT[type="radio"] + S {} Первая группа – общие стили для тэгов S и SPAN. Вторая группа – стили только когда INPUT НЕ выбран. Третья – стили только когда INPUT выбран. Четвертая – когда INPUT заблокирован. И, наконец, пятая группа – общие стили для тэга S ТОЛЬКО, если он стоит после input radio. Таким образом, можно изменять стили тэгов S и SPAN в зависимости от состояния input. 4. Поскольку у нас тэг S будет изображать из себя input, то самому input поставим display:none, его не будет видно, а тэг LABEL будет его переключать, а тэг S будет соответственно меняться. Почему не используем html свойство hidden у input? Потому, что на некоторых браузерах hidden у input «работает» не совсем верно, плюс не будем перегружать html файл. Итак, начинаем визуализацию input Пример N 1. Самый простой – используем алфавитные символы html код тот же, а css будет такой: /* s1 */
.new-input > INPUT + S::before { content: "c"; } /* s2 */ .new-input > INPUT:checked + S::before { content: "V"; } /* s3 */ .new-input > INPUT[type="radio"] + S::before { content: "r"; } /* s4 */ .new-input > INPUT[type="radio"]:checked + S::before { content: "X"; } /* s5 */ .new-input > INPUT:disabled + S::before { opacity: 0.5; } /* s6 */ .new-input > S { text-decoration: none; margin-left: 3px; margin-right: 6px; } /* s7 */ .new-input > S::before { display: inline-block; width: 1.25em; text-align: center; color: #fafafa; background-color: #37474f; } /* s8 */ .new-input > INPUT[type="radio"] + S::before { border-radius: 50%; } Тэг S буде визуализировать input. Но мы «разделим» его по функционалу: сам тэг S будет отвечать за размещение в LABEL и выравнивание относительно следующего SPAN. А псевдоэлемент S::before разместится внутри тэга S и будет изображать из себя input. Строка s1 определяет, какой символ будет помещен в S::before когда input не выбран. В принципе надо было бы написать «.new-input > INPUT:not(:checked) + S::before», но некоторые браузеры (например, IE), подобную конструкцию могут и не исполнить. Строка s2 определяет символ, когда input выбран. Строки s3 и s4 делают то же для input radio. Строка s5 описывает, что будет если input заблокирован – в данном случае тэг S будет наполовину прозрачным. Строка s6 определяет выравнивание, в данном случае дает отбивку слева и справа (только в этом примере). Плюс, убирает штатное перечеркивание. Строка s7 делает квадратик, s8 превращает его в кружок для input radio. Пример N 1 можно посмотреть на codepen.io. Там представлены нативные input и новые. Первые можно убрать. Чуток подробнее про display: inline-block, font-size, line-heightSPLКонченая высота строки текста определяется на основе заданных font-size, line-height. При единичном line-height – высота будет по font-size, при числовом line-height – высота будет по их произведению или, при указании единиц измерения для line-height – высоту определит максимальное значение. В примере указан line-height:1.25, поэтому и у S::before указано width:1.25em.
Для S::before указано display: inline-block – в этом случае S::before «внутри» себя будет блоком (можно указать ширину, высоту, рамки и пр.), а «снаружи» он останется строчным элементом. В дальнейшем об этом будет подробнее. Вопрос: Может можно использовать специальные символы? Типа вот этих: □ ■ ▢ ▣ ○ ● ◎◉ Задать им нужный размер и всё. Нет? Ответ: Можно. Но не нужно. Ибо будет большой геморрой и танцы с бубнами по заданию нужного размера, выравнивания по вертикали, обрезке по высоте и прочее. Плюс, разные браузеры с этими символами работают по-разному. Мы пошли другим путем. Хотя в финальном примере есть реализация этой идеи. Пример N 2. «Рисуем» элементы input средствами css html код тот же, а css будет такой: /* s1 */
.new-input > S::before { content: ""; display: inline-block; width: 0.75em; height: 0.75em; border: 1px solid currentColor; padding: 2px; background-clip: content-box; border-radius: 20%; } /* s2 */ .new-input > INPUT[type="radio"] + S::before { border-radius: 50%; } /* s3 */ .new-input > INPUT:checked + S::before { background-color: currentColor; } /* s4 */ .new-input > INPUT:disabled + S::before { opacity: 0.5; } /* s5 */ .new-input > S { text-decoration: none; margin-left: 3px; margin-right: 6px; } Строка s1 определяет S::before для визуализации input. Это будет inline-block, ширина и высота которого установлена в 0.75em, что примерно равно высоте прописной буквы и зависит от font-size родителя. Задана тонкая рамка текущим цветом, внутренняя отбивка, небольшое скругление углов. И – самое важное! – установлено свойство background-clip:content-box. Это очень интересное свойство – если будет установлен background-color, то он закрасит только контентную часть и не затронет отбивку (padding). Что нам и надо. Строка s2 для input типа radio делает S::before круглым. Строка s3 для отмеченного input устанавливает для S::before background-color текущим цветом. Т.е., «рисует» внутри квадратик или кружок. Строка s4 отрабатывает блокировку input, строка s5 дает отбивки слева и справа. Преимущества этого метода
Недостатки этого метода В основном в использовании размеров в em. Дело в том, что может возникнуть ситуация когда ширина и высота при расчете (из em в px) будет иметь дробное значение. На обычных компьютерах с обычным экраном округление может произойти не корректно. Например, размеры 12.8px на 12.8px у той же Мозилы могут стать как 13px на 12px. Тогда надо ставить фиксированные размеры. Хотя на современных мониторах и видеокартах, ноутбуках, на планшетах и смартфонах этого не происходит из-за того, что точка (пиксель) браузера состоит из нескольких пикселей экрана. Пример N 2 можно посмотреть на codepen.io. Там представлены нативные input и новые. Первые можно убрать. Итак, первую задачу – визуализацию input – выполнили. Переходим к избранной «раскраске». Раскрашиваем input html для примера: <label class="new-input"><input name="chb1" type="checkbox" ...><s></s><span>Некий текст</span></label>
<label class="new-input"><input id="rb1" type="radio" ...><s></s><span>Некий текст</span></label> К input типа checkbox будем обращаться по name, к radio по id. Всё красим в синий /* только input */
.new-input > INPUT[name="chb1"] + S, .new-input > INPUT#rb1 + S { color: #0091ea; } /* только text */ .new-input > INPUT[name="chb1"] ~ SPAN, .new-input > INPUT#rb1 ~ SPAN { color: #0091ea; } /* или всё */ .new-input > INPUT[name="chb1"] ~ *, .new-input > INPUT#rb1 ~ * { color: #0091ea; } Помним о специфичности в css, эти стили будут более специфичны, чем базовые и сработают обязательно. Чем они отличаются от описанных выше? Тем, что применяются только к избранным input – к тем, что имеет указанное значение name и id. Тут всё хорошо кроме того, что не выбранные input будут не очень хорошо глядеться – тонкая синяя рамка мало заметна. Красим в зеленый, когда input выбран /* только input */
.new-input > INPUT[name="chb1"]:checked + S, .new-input > INPUT#rb1:checked + S { color: #00c853; } /* только text */ .new-input > INPUT[name="chb1"]:checked ~ SPAN, .new-input > INPUT#rb1:checked ~ SPAN { color: #00c853; } /* или всё */ .new-input > INPUT[name="chb1"]:checked ~ *, .new-input > INPUT#rb1:checked ~ * { color: #00c853; } Первый вариант, на мой взгляд, не очень хорош – зеленым будут и рамка, и внутренний квадратик/кружок. Можно раскрасить только его. /* только input и только внутри */
.new-input > INPUT[name="chb1"]:checked + S::before, .new-input > INPUT#rb1:checked + S::before { background-color: #00c853; } Красим в красный, когда input НЕ выбран /* только input */
.new-input > INPUT[name="chb1"]:not(:checked) + S, .new-input > INPUT#rb1:not(:checked) + S { color: #d50000; } /* только text */ .new-input > INPUT[name="chb1"]:not(:checked) ~ SPAN, .new-input > INPUT#rb1:not(:checked) ~ SPAN { color: #d50000; } /* или всё */ .new-input > INPUT[name="chb1"]:not(:checked) ~ *, .new-input > INPUT#rb1:not(:checked) ~ * { color: #d50000; } Логика понятна? Можно и дальше делать более сложные конструкции. Например, при не выбранном input текст должен быть красным и жирным, а при выбранном внутренний элемент input и текст должен быть зеленым. Элементарно! /* текст, когда нет выбора */
.new-input > INPUT[name="chb1"]:not(:checked) ~ SPAN, .new-input > INPUT#rb1:not(:checked) ~ SPAN { color: #d50000; font-weight: bold; } /* внутренний элемент input, когда выбран */ .new-input > INPUT[name="chb1"]:checked + S::before, .new-input > INPUT#rb1:checked + S::before { background-color: #00c853; } /* текст, когда выбран */ .new-input > INPUT[name="chb1"]:checked ~ SPAN, .new-input > INPUT#rb1:checked ~ SPAN { color: #00c853; } А, к примеру, надо обработать целую группу input (10-15 штук). Что бы не писать кучу строк можно найти их общего родителя (.parent_element) и сократить условие. .parent_element > .new-input > INPUT:not(:checked) ~ SPAN {
color: #d50000; font-weight: bold; } .parent_element > .new-input > INPUT:checked + S::before { background-color: #00c853; } .parent_element > .new-input > INPUT:checked ~ SPAN { color: #00c853; } Всё можно посмотреть в финальном примере на codepen.io Вот, вроде как, и всё. Осталось только «почесать родимые пятна» перфекциониста – проблемы выравнивания. Выравнивание визуального input и сопроводительного текста Для начала напомню общеизвестные вещи на тему размещения текста, форматирования и прочего. Всё под катом. Общеизвестные вещиSPLБуду стараться не применят специальные термины, ибо в дизайне, верстке и css они иногда отличаются. Всё простыми словами.
1. Свойство font-size не определяет размер букв, а только размер знакоместа. Есть базовая линия (baseline), по которой расположены «нормальные» буквы. У «ненормальных» – g ц – нижние элементы «свисают» ниже её. Есть линия капители (cap height) – это верхняя граница «нормальной» прописной (заглавной) буквы. У «ненормальных» – Ё Й – верхние элементы «вылезают» выше её. Иными словами, размер прописной буквы это расстояние от базовой линии до капители, а знакоместо это чуть больше сверху и снизу. Обычно в «нормальных» шрифтах высота капители это 75% от высоты знакоместо. К примеру, font-size:16px, а размер буквы Н у шрифта Arial будет 12px. Но, бывают «специалисты» у шрифтов которых всё не так. 2. Свойство line-height определяет высоту строки. Если его вычисленное значение больше, чем указано в font-size, то браузер разместит текст так, что бы нормальная прописная буква была по середине высоты строки. Есть нюансы, но тут они не важны. 3. Соответственно, в нашем случае тэги S и SPAN должны иметь одинаковые значения font-size и line-height желательно заданные где-то выше у родителей. В нашем случае в примерах font-size:16px и line-height:1.25. Поэтому в примере N1 у S::before ширина указана 1.25em, а высота у него определяется автоматически. А в примере N2 (и финальный пример) – у S::before ширина и высота 0.75em, что бы был по высоте с прописную букву. Задав другое значение font-size ничего менять не надо. Естественно, эту величину надо подогнать под конкретный шрифт. 4. Если перед текстом стоит какая-то квадратная или круглая «штучка», то любой дизайнер скажет, что она должна быть по высоте с прописную букву. А отбивка между ними должна быть в определенных процентах от размера шрифта. Если высота меньше высоты буквы, то она должна быть визуально значительно меньше, но не меньше 50%. Если больше, то тоже визуально значительно больше, но не больше 150%. А вот чуть-чуть, на пару пикселей больше/меньше – это ужас-ужас! Ну, и расположена эта штучка должна быть на базовой линии или по середине без всяких там чуть-чуть. Зачем я это упомянул? А затем, что перфекционисту глаза режет, когда input криво стоит рядом с текстом — или прилипает, или далеко, или чуть меньше, или чуть больше. Мы так делать не должны! Что будет, если сопроводительный текст в SPAN будет выведен в две или три строки? Очевидно, что он «залезет» под input. Это не красиво, надо исправить. Один древний метод такой: тэгу S делаем float:left, а тэгу SPAN display:block и overflow:hidden. Получится колонка текста. Подразумевается, что у кого-то из них будет соответствующий margin, что даст отбивку между ними. Ну, ещё добавляется геморрой с прекращением float после SPAN. Мы пойдем современным путем – применим flexbox. Он тут совершенно к месту. .new-input {
display: flex; flex-direction: row; align-items: start; } .new-input > S { margin-right: 4px; flex: 0 0 auto; } .new-input > SPAN { flex: 0 1 auto; } В этом случае тэг LABEL (который .new-input) будет flex, S и SPAN будут блоками, разместятся вверху LABEL. Текст в SPAN в случае необходимости будет в несколько строк. Вот из-за этого визуальный input описали в S::before. Независимо от высоты SPAN S::before будет расположен на одной базовой линии с первой строкой SPAN. Как вариант можно было указать align-items:center – тогда при однострочном SPAN визуальный input был бы вверху, а при двух строках – посередине, а при трех – у второй строки. В финальном примере можно переключать расположение input. Вот и всё Надеюсь, было интересно и кому-нибудь полезно. Прошу, не сильно меня ругать – это мой первый опыт на Хабр. Пример N 1 – просто демонстрация взаимодействия изменения input и соседнего элемента. Пример N 2 – визуализация input средствами css, как основа решения. Финальный пример – всё описанное вместе. Про конкретную реализацию Там были обширные формы, где блоки полей возможные для правки конкретным пользователям выделялись слабым фоном, а остальным input имели свойство disabled и служили только для информации. Поэтому стиль «.new-input > INPUT:disabled + S::before» не применяли. =========== Источник: habr.com =========== Похожие новости:
Разработка веб-сайтов ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 02:18
Часовой пояс: UTC + 5