Select - multiselect без js

Я (і, як мені здається, багато хто з вас) стикався не раз з несумісністю СЕЛЕКТА з дизайном сайту.
Біль полягає в тому, що їх не можна стилізувати, а в кожному браузері вони виглядають по-своєму.

Звичайно, є величезна кількість рішень, що подаються фреймворками / бібліотеками (той же бутстрап).
Але всі вони припускають наявність JSа.
Зрозуміло, в цьому немає нічого страшного / поганого, але я спробував зробити стілізуемий селект без JS як фоллбека на випадок, якщо js з яких-небудь причин зламається.

вибір інструментів

Під інструментами в даному контексті я маю на увазі те, чим ми будемо замінювати селект.
І мій вибір припав на radio кнопки через їх схожого поведінки: можна вибрати одночасно лише один варіант.

Ми обернули радіо-кнопки в

Для реалізації вибору потрібного пункту як в СЕЛЕКТА нам треба, щоб він опинявся у верхній позиції списку.
Для цього позначимо, що значення обраного елемента має позиціонуватися абсолютно (вириватися з потоку) і поміщатися на самий верх:

Також нам треба дотримати правило: висота кожного пункту повинна бути рівною "вакантному" місця (відступу зверху) для обраного пункту

Основна частина працює - при виборі пункту він виявляється на лідируючій позиції.
Залишилося потурбуватися про те, щоб в "спокійному" стані було видно тільки обраний пункт, а інший список розкривався при кліці, також при кліці в "молоко" список повинен закриватися без зміни значення.

На думку спадає маніпуляція псевдоселектором: focus.
Додамо який-небудь інпут, який буде під нього потрапляти. Я вибрав [type = text] тому, що йому можна задати розмір (розтягнути на всю ширину і висоту) і затулити їм лідируючий обраний елемент.

Приховувати, що випадає будемо обмеженням висоти і overflow: hidden:

Зрозуміло, інпут не повинно бути видно (як і радіо-кнопок, що представляють опції):

Слід використовувати opacity: 0; замість display: none; через те, що у зірвати елементів (visually: hidden в тому числі) не може бути стану: focus.

брудний хак

І коли вже здавалося, що все вийшло, я зіткнувся з несподіванкою: при кліці по пункту меню зі списку фокус з керуючого інпут йде швидше, ніж спрацьовує клік на елементі списку.
Тобто відбувається рівно те ж, щоі при кліці в молоко - список просто закривається.

Щоб збільшити затримку до приховування випав списку, доведеться використовувати брудний хак:

Якщо ми підемо далі, то нам захочеться зробити таким же чином (без JS) мультіселект.
Не кожен інтегратор jquery-плагінів такий зробить з JS (JQuery), а ми-то з вами бач чого надумали!
Ну сказано - зроблено, не можна впасти обличчям в бруд.
Спробуємо розібратися, чи можливо це. І, якщо немає, що в якому саме моменті не можна обійтися без js.

Що нам потрібно змінити в попередньому прикладі, щоб наш селект став мульти?
Кожен пункт повинен мати можливість бути обраним в не залежності від інших.
Очевидно, нам треба змінити радіо-кнопки на чекбокси:

Так, це ще не все, і required там не випадково, з його допомогою ми будемо маніпулювати нашим списком.

Якщо ми обгорнемо це в

. то у нас з'явиться можливість маніпулювати псевдоселекторамі: valid /: invalid.

Щоб зрозуміти, що саме ми повинні зробити, треба чітко сформулювати завдання:

Нехай виділений пункт буде на початку списку. На одному рядку з ним інші виділені пункти.

Помістити в початок списку вибраний елемент нескладно, ми поставимо батькові display: flex і будемо гратися зі значенням order:

Перша умова виконано і, щоб помістити всі вибрані елементи на один рядок, для обраних пунктів задамо

Вуаля! схоже, що працює.

висновок

У нас не вийшло з'ясувати, де (в рамках завдання) ми не можемо обійтися без js.
Можливо (точно), на більш складних прикладах так і буде.

Дублирую посилання на приклади:

Ну і для тих, хто не хоче писати цю "купу розмітки" руками, накидав скрипт, який зробить це за вас.

Доповнення та інші issue вітаються, без сумніву!

Схожі статті