3061
Шлёпаем формы и красим кнопки... Блог про фронтенд — просто, понятно и с юмором. Всех обнял, приподнял, пошел пилить для вас годноту) Связь: @advertos
Добавляем svg-иконку в кнопку
Часто требуется добавлять в кнопку иконку, давайте здесь разберем простой способ для создания такой кнопки)
HTML-разметка:
<button class="btn">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<!-- SVG content -->
</svg>
Кнопка
</button>
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
background: #007bff;
color: white;
font-size: 16px;
cursor: pointer;
}
.btn svg {
width: 20px;
height: 20px;
}gap задает расстояние между иконкой и текстом.currentColor иконка будет одного цвета с текстом кнопки.
Маркеры списков, зависящие от содержимого элемента
Разберем интересный метод, позволяющий создавать маркеры списков, которые меняются в зависимости от данных самого элемента через атрибуты HTML.
HTML-разметка:
<ul class="emoji-list">
<li data-icon="🚀">Запуск нового проекта</li>
<li data-icon="✅">Завершенная задача</li>
<li data-icon="⚠️">Требует внимания</li>
<li data-icon="🎯">Приоритетная цель</li>
</ul>
.emoji-list li::marker {
content: attr(data-icon) " ";
}attr() извлекаем эти данные и отображаем через ::marker.
Автоматические кавычки в CSS
А вы знали, что CSS умеет автоматически ставить правильные типографские кавычки в зависимости от языка текста?
Достаточно прописать в CSS правила для разных языков:
:lang(ru) {
quotes: "«" "»";
}
:lang(en) {
quotes: "“" "”";
}<q> и указываем язык:<!-- «Быть или не быть» -->
<p lang="ru">
Цитата на русском: <q>Быть или не быть</q>.
</p>
<!-- “To be or not to be” -->
<p lang="en">
Quote in English: <q>To be or not to be</q>.
</p>
<html lang="ru">
<q> автоматически будут с «ёлочками».
Стилизация плейсхолдера в полях ввода
При верстке макетов, практически всегда, плейсхолдер не стандартный, т.к. дизайнеры любят кастомизировать всё — даже подсказки в полях ввода должны выглядеть «не как у всех».
Делается, это просто, но давайте, на всякий случай разберем, чтобы и эта инфа была у нас в канале)
Используем псевдоэлемент ::placeholder, который позволяет менять внешний вид текста-подсказки внутри <input> или <textarea>.
Разметка:
<input type="text" placeholder="Введите своё имя">
input::placeholder {
color: #8b5cf6;
}input:focus::placeholder {
opacity: 0.5;
}
Управляем кнопкой через чекбокс с помощью :has()
Еще одно интересное использование псевдокласса :has() — делаем кнопку активной (доступной для нажатия) только если отмечен чекбокс.
HTML:
<div class="container">
<input type="checkbox" id="agreement">
<label for="agreement">Согласен с условиями</label>
<button>Отправить</button>
</div>
/* Стили для неактивной кнопки */
button {
opacity: 0.5;
pointer-events: none;
}
/* Если чекбокс отмечен — делаем кнопку активной */
.container:has(input[type="checkbox"]:checked) button {
opacity: 1;
cursor: pointer;
pointer-events: auto;
}
.container есть отмеченный чекбокс, то меняем стили и делаем кнопку активной.
Простая кнопка "Наверх"
Сегодня разберём, как сделать кнопку "Наверх", добавим немного JS, чтобы кнопка появлялась только после прокрутки вниз.
HTM:
<a href="#" class="up-button" id="upBtn">
<svg viewBox="0 0 24 24">
<path d="M5 15l7-7 7 7" />
</svg>
</a>
html {
scroll-behavior: smooth;
}position: fixed — всегда внизу справа.opacity: 0; pointer-events: none; — по умолчанию невидима и неактивна.display: flex + align/justify — центрируем стрелку внутри..show, кнопка становится видимой:.up-button.show {
opacity: 1;
}const btn = document.getElementById('upBtn');
window.addEventListener('scroll', () => {
btn.classList.toggle('show', window.scrollY > 300);
});.show, и кнопка появляется. Если вернулись вверх — прячем.
Бесконечная карусель без JS
Т.к. мы будем делать карусель только на HTML и CSS, то давайте сделаем это с помощью дублирования карточек + анимации translateX(-50%).
Создадим в .items два одинаковых блока изображений:
<div class="items">
<!-- Первый набор (оригиналы) -->
<img src="image1.jpg" class="item">
<img src="image2.jpg" class="item">
<!-- ... всего 7 изображений ... -->
<!-- Второй набор (точные копии) -->
<img src="image1.jpg" class="item">
<img src="image2.jpg" class="item">
<!-- ... ещё 7 таких же ... -->
</div>
.items {
display: flex;
animation: slide 50s linear infinite;
}
@keyframes slide {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}infinite), но глаз этого не замечает, потому что дубликаты идентичны оригиналам.
Разбиваем список на колонки с помощью columns
Иногда бывает задача взять список и разбить его на несколько колонок. Наверное, самый простой способ для этого — это использовать CSS-свойство columns.
Допустим, у нас есть обычный HTML-список:
<ul class="multi-column-list">
<li>Пункт 1</li>
<li>Пункт 2</li>
<li>Пункт 3</li>
<li>Пункт 4</li>
<li>Пункт 5</li>
<li>Пункт 6</li>
</ul>
.multi-column-list {
columns: 2;
}columns — норм выбор)
Убираем стрелочки у <input type="number">
При использовании <input type="number"> браузеры автоматом добавляют к полю стрелочки (спиннеры), которые позволяют увеличивать или уменьшать значение с помощью клика. Это удобно, но не всегда желательно с точки зрения дизайна или логики работы интерфейса.
Убираем стрелки с помощью псевдоэлементов:
/* Убирает стрелки в Chrome, Safari, Edge */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Убирает стрелки в Firefox */
input[type="number"] {
-moz-appearance: textfield;
}
Стилизуем первую строку текста
Ранее, здесь мы уже рассматривали использование псевдоэлемента ::first-letter, сегодня давайте вспомним о его близком "соседе" — ::first-line) Он чуть менее известен, но тоже интересен.::first-line применяется к первой строке текста внутри блочного элемента — чаще всего к абзацу <p>, но также может работать с любыми блоками с display: block.
Выглядит это так:
p::first-line {
font-weight: bold;
color: #2c3e50;
}
Счетчик уведомлений с помощью атрибутов
Если вам вдруг нужно сделать вывод уведомлений, рядом с кнопкой, без использования отдельного html элемента (типа <span class="badge">), то можно попробовать сделать это через data-count самой кнопки.
Используем ::before + attr(data-count)
Разметка:
<button data-count="7">Уведомления</button>
.button::before {
content: attr(data-count);
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: -0.75em;
right: -0.75em;
background-color: #dd7973;
border-radius: 50%;
width: 1.5em;
height: 1.5em;
}
/* Скрываем, если нет уведомлений */
.button[data-count=""]::before {
display: none;
}data-count пуст, бейдж исчезает display: none.
Live-preview проекта на мобильном устройстве
Если вы верстаете в VS Code, то вы знаете про Live Server, так вот, он позволяет смотреть результат не только в браузере ПК, но и на мобильном устройстве.
Для этого нужно:
■ Убедиться, что ПК и телефон в одной Wi-Fi сети.
■ Найти локальный IP ПК:
● Можно открыть "Параметры сети и Интернет", далее кнопка "Свойства" и там найти IPv4-адрес.
● Можно в командной строке прописать ipconfig и там также найти IPv4-адрес.
■ Открываем браузер в телефоне и вводим:http://[IP-компьютера]:5500 (например http://192.168.1.10:5500)
И всё, теперь изменения в коде автоматически обновляются и в браузере на телефоне)
У меня завелось не сразу, пришлось в защитнике Windows разрешать подключение для VS Code.
Решается проблема так:
■ откройте монитор защитника Windows:
● Жмем win+r и вводим wf.msc
● Переходим в "Правила для входящих подключений", находим там Visual Studio Code.
● Двойной клик и отмечаем "Разрешить подключение".
После этого всё должно заработать)
Выбрать камеру (фронтальную или основную) прямо из браузера
На днях я наткнулся на одну интересную фишку — возможность указать, какую камеру использовать при загрузке фото или видео с мобильного устройства.
Причем это работает прям через HTML атрибут.
<!-- Фото с фронтальной камеры -->
<input type="file" capture="user" accept="image/*" />
<!-- Фото с основной камеры -->
<input type="file" capture="environment" accept="image/*" />
<!-- Видео с фронтальной камеры -->
<input type="file" capture="user" accept="video/*" />
<!-- Видео с основной камеры -->
<input type="file" capture="environment" accept="video/*" />
capture="user" — открывает фронтальную камеру.capture="environment" — открывает основную (заднюю) камеру.
Выделение текста одним кликом
Еще один микро-лайфхак о том, как облегчить жизнь пользователям. Сделаем так, чтобы выделять текст можно было одним кликом - удобно для выделения кода, номеров заказов, реф. кодов и т.п.
Делается это с помощью свойства user-select.
CSS-свойство user-select контролирует, может ли пользователь выделить текст на странице. У него есть несколько значений, но нас интересует:
user-select: all;
<div class="code-block">
<code>npx create-react-app my-app</code>
</div>
.code-block code {
user-select: all;
}<code> будет выделен автоматически.
Shorthand-свойства в CSS
Нашел классный видос с сокращёнными свойствами в CSS, решил вам тоже показать)
Чтобы было удобнее, добавил код из видео в пост:
Padding
/* long-hand */
padding-top: 1em;
padding-right: 3px;
padding-bottom: 30px;
padding-left: 5px;
/* short-hand */
padding: 1em 3px 30px 5px;
/* long-hand */
margin-top: 10px;
margin-right: 5px;
margin-bottom: 10px;
margin-left: 5px;
/* short-hand */
margin: 10px 5px 10px 5px;
/* long-hand */
border-width: 1px;
border-style: solid;
border-color: #000;
/* short-hand */
border: 1px solid #000;
/* long-hand */
font-style: italic;
font-weight: bold;
font-size: 15px;
line-height: 1.2;
font-family: Arial, sans-serif;
/* short-hand */
font: italic bold 15px/1.2 Arial, sans-serif;
/* long-hand */
background-color: #000;
background-image: url(image.png);
background-repeat: no-repeat;
background-position: left top;
/* short-hand */
background: #000 url(image.png) no-repeat left top;
/* long-hand */
animation-name: crazy;
animation-duration: 4s;
animation-timing-function: ease-in-out;
animation-delay: 0.5s;
animation-iteration-count: 12;
animation-direction: backwards;
/* short-hand */
animation: crazy 4s ease-in-out 0.5s 12 backwards;
/* long-hand */
list-style-type: disc;
list-style-position: outside;
list-style-image: url('image.png');
/* short-hand */
list-style: disc outside url('image.png');
Когда вставил кусок кода со Stack Overflow в свой проект.
Где твой проект — это колёса)
Создаем видео-фон для блока
Иногда на лендингах, особенно на первом экране, нужно запилить видео-фон, а над ним какой-то текст, давайте разберем, один из способов, как это можно реализовать.
HTML-разметка:
<div class="container">
<video autoplay muted loop playsinline>
<source src="video.mp4" type="video/mp4">
</video>
<h1>ФОРМОШЛЁП</h1>
</div>
.container {
height: 100vh;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
}
video {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: -1;
filter: brightness(0.3) contrast(1.1);
}
Списки с автоматическими разделителями
Для тех, кто устал руками добавлять запятые, точки с запятой или другие разделители в списках, давайте разберем, как это дело упростить.
Используем для этого псевдоэлемент ::after.
Стандартная HTML разметка списков:
<ul>
<li>Flexbox</li>
<li>Grid</li>
<li>Позиционирование</li>
<li>Переменные CSS</li>
</ul>
li, кроме последнего:li:not(:last-child)::after {
content: ",";
}li:last-child::after {
content: ".";
}
Делаем кастомную иконку <summary>
Если требуется изменить стандартную иконку треугольника, на что то свое, то для этого можно использовать псевдоэлемент ::before, давайте разберем подробно.
Убираем стандартный треугольник:
details summary {
list-style: none;
}details summary::before {
content: "➜"; /* Наша кастомная иконка */
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
transition: transform 0.2s ease;
}details[open] summary::before {
transform: translateY(-50%) rotate(90deg);
}details summary::before {
content: "";
background: url("data:image/svg+xml,<svg...>") no-repeat center;
width: 16px;
height: 16px;
}
Делаем отступы только между элементами списка
Простое и эффективное решение, если нужно добавить отступы между пунктами списка, но так, чтобы не было лишних отступов сверху или снизу.
Используем селектор li + li — он применяет стиль ко всем элементам li, кроме первого:
li + li {
margin-top: 35px; /* Отступ сверху для всех, кроме первого */
}li + li, то можно :not(:last-child):li:not(:last-child) {
margin-bottom: 35px;
}ul {
display: flex;
flex-direction: column;
gap: 35px; /* Отступ между элементами */
}
Создаем стильные кастомные чекбоксы на CSS
Иногда, стандартные чекбоксы не вписываются в дизайн. Поэтому давайте сегодня разберем, как создать красивые кастомные чекбоксы, которые выглядят, как современные кнопки-теги.
HTML структура:
<div class="list">
<input type="checkbox" name="role" id="opt1" />
<label for="opt1">HTML, CSS</label>
<input type="checkbox" name="role" id="opt2" />
<label for="opt2">JavaScript</label>
</div>
<input type="checkbox">, связываем их с <label> через атрибут for..list input {
display: none;
}
.list label {
cursor: pointer;
padding: 13px 34px;
border: 0.6mm solid #000;
border-radius: 30px;
}
.list input:checked + label {
color: rgb(0, 120, 230);
border-color: rgb(15, 150, 255);
background: rgb(230, 245, 255);
}display: none скрываем чекбоксы, стилизуем label, который становится кнопкой.:checked + соседний селектор меняет стиль при выборе.
Блок по ширине контента — width: fit-content
Если нужно, чтобы блок был ровно такой ширины, как его содержимое, но при этом не вылезал за границы родителя, то есть отличное решение — width: fit-content.fit-content заставляет элемент:
■ Сжиматься под содержимое, если оно меньше доступной ширины.
■ Оставаться в пределах родителя, если контент слишком широкий.
Т.е. грубо говоря, width: fit-content ведет себя, как inline-block.
.fit-content {
width: fit-content;
}
Css Grid Layout
Еще один интересный видос обнаружил, теперь про то, как быстро накидать стандартную сетку сайта (шапка, сайдбар, контент и подвал) с помощью гридов.
Код из видео, разметка:
<main>
<header>Header</header>
<article>Content</article>
<aside>Sidebar</aside>
<footer>Footer</footer>
</main>
main {
display: grid;
grid-template-areas:
"head head head"
"side content content"
"foot foot foot";
grid-template-rows: 30px auto 30px;
min-height: 100vh;
}
header {
grid-area: head;
}
article {
grid-area: content;
}
aside {
grid-area: side;
}
footer {
grid-area: foot;
}
Мощная шпаргалка по CSS
Нашел на гитхабе крутую шпаргалку по CSS, сразу захотелось с вами поделиться)
Она прям реально большая, вот что в ней есть:
■ Основы CSS
■ Селекторы
■ Блочная модель
■ Позиционирование
■ Flexbox
■ Grid Layout
■ Трансформации и переходы
■ Анимации
■ Современные функции и переменные
■ Адаптивный дизайн
■ CSS Modules и методологии
■ Новые CSS-свойства
■ Контейнерные запросы
■ Логические свойства
■ Субгриды
■ Слои каскада
■ Дополнительные современные возможности
Согласитесь круто)
Находится она здесь — https://gist.github.com/dmitry-osin/c64f7d8eb9ed60cc932c4c56ac7eae22
Эффект тряски полей в форме
Сегодня рассмотрим эффект тряски — простой, но интересный способ сделать валидацию форм живой и понятной)
Делается это с помощью двух вещей:
1. Keyframes анимация
@keyframes shake {
0% { transform: translateX(0); }
25% { transform: translateX(-5px); }
50% { transform: translateX(5px); }
75% { transform: translateX(-5px); }
100% { transform: translateX(0); }
}
:user-invalidinput:user-invalid {
border: 2px solid red;
animation: shake 0.3s ease;
}:user-invalid, применяется анимация animation: shake 0.3s ease; которая слегка двигает поле влево-вправо, создавая эффект "ошибки".
Отключаем ховер на мобильных устройствах
Ховер-эффекты работают при наведении курсора, но на сенсорных экранах нет мыши — вместо этого есть касания.
Из-за этого могут возникать проблемы: "залипание" стилей — после тапа элемент остается в состоянии :hover, пока пользователь не коснётся другого места. Это может выглядеть странно)
Чтобы ховер работал только на устройствах с мышью, можно использовать CSS-медиазапросы:
/* Ховер только для мыши */
@media (hover: hover) {
.btn:hover {
background: #4CAF50;
}
}
Управление градиентом в DevTools
Если кто не знал (как я), то в DevTools, есть приблуда для управления направлением градиента.
Находится на вкладке Elements в стилях, на видео сверху, наглядно показал, как пользоваться.
Поэтому, если у вас есть градиент, в котором указан угол, то можно поиграться и подобрать оптимальный вариант)
Насколько понял такая фишка только в хроме, в firefox не нашел.
Улучшаем читаемость текста на фоновом изображении
Иногда фоновая картинка мешает нормально прочитать текст, который находится над ней. Для решения этой проблемы отлично подходит линейный градиент.
Буквально одной строчкой можно пофиксить проблему)
Наш фон:
background-image: url('image.jpg');background-image: linear-gradient(rgb(255, 255, 255, 0.4), rgb(255, 255, 255, 1)), url('image.jpg');linear-gradient добавляем белый полупрозрачный градиент — это сделает текст четким и сохранит красоту фона.
Аккордеон на чистом HTML и CSS
Сделаем такой аккордеон, чтобы одновременно был открыт только один элемент. В этом нам поможет старый добрый <details>, но с улучшением)
Будем использовать атрибут name, который превращает <details> в группу элементов.
И еще добавим атрибут open у первого элемента, чтобы сделать его раскрытым по умолчанию.
Получаем такой код:
<div class="accordion">
<details name="my-accordion" open>
<summary>Первый пункт</summary>
<div class="content">
<p>Текст</p>
</div>
</details>
<details name="my-accordion">
<summary>Второй пункт</summary>
<div class="content">
<p>Текст</p>
</div>
</details>
</div>