🕐 10 хв читання

Нестандартні елементи форм

Конспект лекції: display: inline-block, випадаючий список <select>, background-властивості, радіокнопки, чекбокси, кастомна стилізація, псевдоелементи, селектори + і ~

display: inline-block

Окрім block, inline та flex, є ще одне значення — inline-block. Воно поєднує поведінку строкових і блочних елементів.

Що від чого?

Від строкових (inline) Від блочних (block)
Елементи розташовуються в рядок Можна задавати width і height
Без width ширина визначається вмістом padding, margin працюють повноцінно
Позиціонуються через text-align Не розбиваються на частини при переносі рядка
Кнопка <button> за замовчуванням має display: inline-block. Тому її можна центрувати через text-align: center на батьківському елементі.

Центрування кнопки

.form-row:last-child {
    text-align: center;  /* кнопка всередині стане по центру */
}

Пробіл між inline-block елементами

Між inline-block елементами з'являється пробіл (~4px). Він не «створюється» — він бере початок від символу переносу рядка або пробілу у вашому HTML-коді.

Як виникає?

<!-- Між цими div є перенос рядка → браузер показує 1 пробіл -->
<div class="card">...</div>
<div class="card">...</div>

Як прибрати?

Спосіб Недолік
Писати теги без пробілів між ними Крихке рішення — будь-який пробіл зламає верстку
font-size: 0 на батьку, відновити на дітях Ламає відносні одиниці (em), незручно
Flexbox замість inline-block Найкраще рішення — без хаків
Якщо вам потрібно, щоб елементи щільно прилягали один до одного — використовуйте display: flex замість inline-block. Flex-елементи не мають пробілів між собою.

Випадаючий список: <select> + <option>

<select> — елемент форми для вибору одного варіанту зі списку. <option> — кожен варіант вибору (може бути лише всередині <select>).

<label>
    <span class="form-hint">Оберіть місто</span>
    <select class="select" name="city">
        <option>Київ</option>
        <option selected>Львів</option>
        <option>Одеса</option>
        <option>Харків</option>
    </select>
</label>
Атрибут Призначення
selected Позначає варіант, вибраний за замовчуванням
multiple Дозволяє обрати кілька (рідко використовується — незручний UX)
Без selected — вибраним стає перший <option>. Якщо selected є на кількох — виграє останній у коді.

Коли select, а коли radio?

<select>
  • Варіантів більше 5
  • Займає мінімум місця
  • Потрібно 2 кліки (відкрити + обрати)
radio
  • Варіантів 2–5
  • Усі варіанти видимі одразу
  • Вибір за 1 клік

appearance: none — скидання стилізації

Браузери мають власну стилізацію для елементів форм (<select>, деякі типи <input>), яку складно перевизначити. Властивість appearance зі значенням none вимикає цю базову стилізацію.

.select {
    -webkit-appearance: none;  /* Safari, старі Chrome */
    -moz-appearance: none;     /* Firefox */
    appearance: none;          /* стандарт */
}
Сучасні браузери (Chrome 84+, Firefox 80+, Safari 15.4+) підтримують appearance: none без префіксів. Але для повної сумісності додавайте всі три рядки.

Де застосовувати?

  • <select> — прибирає стандартну стрілку, дозволяє повну стилізацію
  • input[type="search"] — прибирає нестандартне оформлення в Safari
Не застосовуйте appearance: none повсюдно. Кнопки та звичайні <input> прекрасно стилізуються і без нього.

background — фон елемента

Група властивостей для керування фоном: колір, зображення, повторення, позиція, розмір.

background-color

Задає колір фону. Рекомендується завжди підкладати колір під background-image — на випадок, якщо картинка не завантажиться.

background-image

background-image: url("icons/arrow.svg");

Завантажує зображення і показує його як фон елемента. Без додаткових налаштувань — повторюється і заповнює весь блок.

background-repeat

Значення Поведінка
repeat (за замовчуванням) Повторюється по горизонталі та вертикалі
repeat-x Тільки по горизонталі
repeat-y Тільки по вертикалі
no-repeat Без повторення (одна копія)
no-repeat використовується найчастіше — для іконок, декоративних елементів, унікальних фонових зображень.

background-position

Визначає положення фонового зображення. Два значення: горизонталь і вертикаль.

/* 9 опорних точок */
background-position: left top;       /* лівий верхній кут */
background-position: center center;  /* строго по центру */
background-position: right center;   /* справа по центру */

/* Зі зміщенням від опорної точки */
background-position: right 10px center;  /* справа, -10px ліворуч */
Вибирайте найближчу опорну точку до потрібного місця. Для іконки у правій частині поля — right center зі зміщенням ліворуч.

background-size

Значення Поведінка
200px auto Ширина 200px, висота — пропорційно
auto 100px Висота 100px, ширина — пропорційно
cover Покриває весь блок (частина картинки може бути обрізана)
contain Вписується в блок цілком (частина блоку може бути порожньою)
cover — для декоративних фонів, де не важливі деталі.
contain — для зображень, де важливо показати все (портрети, діаграми).

Стилізація <select>: повний приклад

Після скидання appearance: none елемент <select> стає звичайним прямокутником. Тепер ми додаємо власну стрілку через background-image:

.select {
    display: block;
    width: 100%;
    padding: 10px 35px 10px 15px;  /* більше padding-right для стрілки */
    border: 1px solid #ccc;
    border-radius: 4px;
    font-size: 16px;
    font-family: inherit;
    box-sizing: border-box;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    background-image: url("icons/arrow-down.svg");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 12px auto;
}
Не забудьте обгорнути <select> у <label> — щоб клік по підпису активував поле. І додайте стилі :focus однакові з іншими полями.

Радіокнопки: input type="radio"

Радіокнопки дозволяють обрати один варіант із групи. Назва «radio» походить від старих радіоприймачів: натискаєш одну кнопку — інша вистрибує.

<label>
    <input type="radio" name="gender" class="radio">
    <span class="radio-text">Чоловіча</span>
</label>
<label>
    <input type="radio" name="gender" class="radio">
    <span class="radio-text">Жіноча</span>
</label>

Атрибут name — створення радіогрупи

Без name кожна радіокнопка працює незалежно — можна обрати усі одночасно. Атрибут name зв'язує радіокнопки в групу: у групі обрана лише одна.

Значення name повинно відображати призначення групи: "gender", "subscription", "delivery" — а не абстрактне "radiogroup".
Обгортайте радіокнопки в <label> — тоді клік по тексту теж активує вибір. Плюс <label> — строковий елемент, тому радіокнопки автоматично стоятимуть в одному рядку.

Псевдоелементи ::before та ::after (практика)

Псевдоелементи дозволяють додати до будь-якого елемента віртуальні блоки — без зміни HTML-коду. Вони створюються виключно через CSS.

Обов'язкова властивість content

.heading::before {
    content: "";  /* обов'язково! без content — елемент не з'явиться */
    display: block;
    width: 60px;
    height: 4px;
    background-color: #4caf50;
    margin-bottom: 10px;
}

Обмеження

Псевдоелементи не працюють для тегів:

  • <input> — самозакривний, без вмісту
  • <textarea>
  • <select>
  • <img> — самозакривний
Не вставляйте текстовий контент через псевдоелементи — він невидимий для скрінрідерів і не індексується пошуковими системами. Псевдоелементи — лише для декоративного оформлення.

Пріоритет шарів

::before з'являється перед вмістом і має нижчий пріоритет (вміст його перекриває). ::after з'являється після вмісту і має вищий пріоритет (може перекрити вміст).

vertical-align — вирівнювання по вертикалі

Працює для inline та inline-block елементів. Визначає, як елемент вирівнюється відносно рядка.

Значення Поведінка
baseline (за замовчуванням) По базовій лінії тексту (нижній край букв)
top По верхньому краю рядка
middle По центру рядка
bottom По нижньому краю рядка
vertical-align: middle ідеально підходить для вирівнювання іконок, радіокнопок, чекбоксів поряд із текстом.

Селектори + (суміжний) та ~ (загальний братський)

Ці селектори працюють між «братами» — елементами одного рівня вкладеності (один батько). Аналог селекторів > (дитина) та пробілу (нащадок), але по горизонталі.

Селектор + (суміжний)

Стилізує елемент, якщо його безпосередній старший брат відповідає умові:

/* Стилізуємо .radio-text, якщо безпосередньо перед ним — .form-hint */
.form-hint + .radio-text {
    color: red;
}

Селектор ~ (загальний братський)

Стилізує елемент, якщо будь-який його старший брат відповідає умові:

/* Стилізуємо .radio-text, якщо десь вище по коду є .form-hint */
.form-hint ~ .radio-text {
    color: red;
}

Порівняння усіх чотирьох «горизонтально-вертикальних» селекторів

Селектор Напрямок Строгість
A B (пробіл) Батько → нащадок (будь-якої глибини) М'який
A > B Батько → безпосередня дитина Строгий
A ~ B Старший брат → будь-який молодший М'який
A + B Старший брат → безпосередній наступний Строгий
Селектор ~ надійніший за +: якщо хтось вставить додатковий елемент між братами, + зламається, а ~ — ні.
Ці селектори працюють лише від старшого до молодшого брата. Стилізувати старшого на основі молодшого — неможливо у CSS.

Кастомна стилізація радіокнопок

Стандартні радіокнопки не стилізуються: браузери не дозволяють змінювати колір, розмір, форму. Рішення — створити муляж і приховати оригінал.

Крок 1: створюємо муляж через ::before

Оскільки <input> не підтримує псевдоелементи, створюємо їх на сусідньому <span>:

.radio-text::before {
    content: "";
    display: inline-block;
    width: 20px;
    height: 20px;
    margin-right: 8px;
    vertical-align: middle;
    background-image: url("icons/radio.svg");
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
}

Крок 2: передаємо стан :checked через селектор ~

/* Якщо радіокнопка обрана → підмінюємо картинку на муляжі */
.radio:checked ~ .radio-text::before {
    background-image: url("icons/radio-active.svg");
}
Читаємо справа наліво: стилізуємо ::before елемента .radio-text, якщо десь перед ним є .radio у стані :checked.

Крок 3: ховаємо оригінал доступно

.radio {
    position: absolute;
    width: 1px;
    height: 1px;
    clip-path: inset(50%);
    overflow: hidden;
}
Не використовуйте display: none або visibility: hidden — елемент стане недоступним для скрінрідерів та клавіатурної навігації. clip-path: inset(50%) ховає візуально, але зберігає доступність.

Крок 4: стан фокусу

/* Фокус з радіокнопки → візуальне виділення тексту */
.radio:focus ~ .radio-text {
    outline: 2px solid #1976d2;
    outline-offset: 2px;
}

position: absolute — коротко

position: absolute вириває елемент з нормального потоку документа і розміщує на окремому «шарі»:

  • Інші елементи поводяться так, ніби абсолютного елемента не існує
  • Ширина і висота розраховуються за вмістом (як у inline-block)
  • Можна задавати width, height — працюватимуть
  • Батьківський елемент не враховує висоту абсолютного нащадка
Детально position (static, relative, absolute, fixed, sticky) розглядається у наступних лекціях. Тут він потрібен лише для коректного приховування оригінальних radio/checkbox.

clip-path: inset() — візуальне обрізання

Властивість clip-path дозволяє показати тільки частину елемента, а решту — приховати.

/* Обрізати 50% з кожного боку — елемент зникає візуально */
clip-path: inset(50%);

/* Обрізати у формі кола */
clip-path: circle(50%);

/* Обрізати у формі багатокутника */
clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
inset(50%) — обрізає 50% з кожного боку елемента. Область, що залишається = нічого. Візуально елемент зникає, але залишається доступним для скрінрідерів.
Застаріла властивість clip: rect() робила те саме, але працювала лише з position: absolute і є deprecated. Використовуйте clip-path — вона сучасніша і підтримує більше форм обрізання.

Чекбокс: input type="checkbox"

Чекбокс — елемент «так/ні»: погодитися чи не погодитися. По суті — дві радіокнопки в одному елементі.

<label>
    <input type="checkbox" name="consent" class="checkbox" required>
    <span class="checkbox-text">Погоджуюсь на обробку персональних даних</span>
</label>

Стилізація абсолютно ідентична радіокнопкам:

  1. Створити муляж через ::before на .checkbox-text
  2. Передати стан :checked через .checkbox:checked ~ .checkbox-text::before
  3. Приховати оригінал через position: absolute + clip
  4. Додати стан :focus
/* Ховаємо разом з radio — через запятую */
.radio,
.checkbox {
    position: absolute;
    width: 1px;
    height: 1px;
    clip-path: inset(50%);
    overflow: hidden;
}

Сучасна альтернатива: accent-color

У файлі 06 ми вже згадували accent-color — властивість, яка дозволяє змінити колір стандартних checkbox, radio, range без кастомної стилізації:

input[type="radio"],
input[type="checkbox"] {
    accent-color: #e53935;
}
accent-color
  • Один рядок CSS
  • Зберігає стандартну поведінку
  • 100% доступність
  • Обмежений контроль (лише колір)
Кастомна стилізація
  • Повний контроль вигляду
  • Дизайнер вирішує форму, анімацію
  • Потрібен складний CSS
  • Потрібно дбати про доступність
Якщо дизайнер хоче лише змінити колір — використовуйте accent-color. Якщо потрібна повна кастомізація — техніка з муляжем і ::before.

Підсумок

Тема Ключове
display: inline-block Рядок + розміри; центрування через text-align; пробіл між елементами
<select> + <option> Випадаючий список; selected — передвибраний; > 5 варіантів
appearance: none Скидає стандартну стилізацію браузера для елементів форм
background image + repeat + position + size; cover vs contain
input type="radio" Вибір одного із групи; name зв'язує в радіогрупу
::before / ::after Декоративні блоки через CSS; обов'язковий content; не для input/img
vertical-align Вирівнювання inline/inline-block по вертикалі; middle для іконок
Селектори + та ~ Братські селектори; + строгий, ~ м'який; тільки від старшого до молодшого
Кастомна стилізація radio/checkbox Муляж через ::before + стан :checked через ~ + доступне приховування
position: absolute Вириває елемент з потоку; потрібний для clip
clip-path: inset() Візуальне приховування зі збереженням доступності; замінює застарілу clip: rect()
accent-color Сучасна альтернатива: змінити колір radio/checkbox одним рядком
🔍
Почніть вводити назву лекції або тему