Наблюдая за потоком вопросов по CSS на Тостере уже давно заметил, что многие из них повторяются много-много раз. Да, есть совсем глупые вопросы, на которые так и тянет ответить RTFM! Но есть и более занятные. Они связаны с не совсем стандартной версткой. Не такой, чтобы глаза на лоб лезли, но и заметно выходящей за рамки условного бутстрапа и традиционных туториалов для новичков. Похожие вопросы довольно сложно загуглить — обычно вся суть в картинке, но и отвечать каждый раз надоедает. В этой статье мы постараемся посмотреть некоторые приемы, охватывающие довольно широкий круг подобных вопросов. Информация в первую очередь адресуется начинающим верстальщикам, но возможно и опытным будет, чем вдохновиться.
1. Туда-сюда-обратно
Начнем с простого. Если трансформировать элемент-контейнер, а затем применить противоположную трансформацию к его контенту, то можно получить много всего интересного. Это часто используют для создания косых секций. Рассмотрим следующую разметку:
<div class='custom-section'>
<div class='block -left'>
<img class='background' src='...' />
<a class='link' href=''>Summer</a>
</div>
<div class='block -right'>
<img class='background' src='...' />
<a class='link' href=''>Winter</a>
</div>
</div>
Довольно просто, ничего лишнего. Из нее мы получаем вот такой результат:
Как это произошло? Здесь мы применили transform: skew(-15deg)
для блока и transform: skew(15deg)
для контента — картинок и ссылок. Собственно вот и все. Применили трансформацию и отменили ее для потомков. Выглядит это примерно так:
.custom-section {
> .block.-left {
transform: skew(-15deg) translate(-15%);
}
> .block.-left > .background {
transform: skew(15deg) translateX(15%);
}
}
При использовании transform: skew
может возникать необходимость компенсировать длину контента или немного его подвинуть, что мы и сделали с помощью transform: translate
.
В подобных компонентах часто применяются картинки в виде тегаimg
. Будет очень не лишним вспомнить проobject-fit: cover
.
Разумеется, подобные действия можно совершить и с другими трансформациями. Например rotate
дает нам возможность сделать циферблат или расположить фотографии по кругу:
Принцип работы тот же. Применили трансформацию и отменили ее для дочерних элементов:
.image-wrapper {
&:nth-of-type(2) {
transform: rotate(45deg);
.image { transform: rotate(-45deg); }
}
&:nth-of-type(3) {
transform: rotate(90deg);
.image { transform: rotate(-90deg); }
}
и.т.д.
}
2. Бордиенты
У нас в CSS довольно ограниченные возможности по оформлению границ элементов. Но в голове дизайнера все совсем по-другому. Это приводит к тому, что начинающий верстальщик часто встает в ступор и предлагает дать дизайнеру клавиатурой по голове. На Тостере часто спрашивают о том, как оставить от стандартного бордера только уголки, сделать двойной/тройной бордер и.т.д. Все подобные вопросы можно решить с помощью градиентов.
Основная идея проста до невозможности: взять линейные градиенты и с помощью них нарисовать такой бордер, какой мы захотим. В нашем обществе очень сильно влияние стереотипов и многим людям видимо просто не приходит в голову, что инструменты (в частности свойства CSS) можно использовать не совсем по назначению.
Собственно лучше всего проиллюстрирует эти слова живой пример:
Здесь мы видим два подхода к использованию градиентов: в border-image
и background-image
. Первый вариант может быть удобен в сочетании со свойством border-image-slice
, а второй уже давно популярен для рисования чего угодно.
.example {
&:nth-of-type(1) {
border-size: 3px;
border-style: solid;
border-image: linear-gradient(to bottom, #86CB92 0%, transparent 40%, transparent 60%, #86CB92 100%);
border-image-slice: 1;
}
&:nth-of-type(3) {
background: linear-gradient(to right, #86CB92 0%, transparent 100%),
linear-gradient(to right, transparent 0%, #86CB92 100%),
linear-gradient(to bottom, #86CB92 0%, transparent 100%),
linear-gradient(to bottom, transparent 0%, #86CB92 100%),
linear-gradient(to right, #86CB92 0%, #86CB92 100%),
linear-gradient(to right, #86CB92 0%, #86CB92 100%);
background-size: 70% 3px, 70% 3px, 3px 70%, 3px 70%, 20% 20%, 20% 20%;
background-position: 50% 0, 50% 100%, 0 50%, 100% 50%, 5% 5%, 95% 95%;
background-repeat: no-repeat;
}
}
В Safari как всегда есть проблемы с прозрачностями. Всегда используйте развернутую запись сborder-width
иborder-style
, как в первом примере, вместо короткойborder: 3px solid transparent
.
3. Частичное дублирование стилей
И раз уж мы говорим о бордерах, скажем пару слов о дублировании. Тоже полезный прием. Если у элемента есть бордер, мы можем взять один из его псевдоэлементов (::before
или ::after
), положить его сверху, задать тот же размер в 100% / 100%
и полностью или частично продублировать бордер основного элемента.
.overflow-example {
border: solid 5px #fff;
position: relative;
&::after {
display: block;
content: '';
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
border-bottom: solid 5px #fff;
}
}
Это даст возможность сделать "вылезание" контента через границу элемента:
Подобный эффект часто встречается на рекламных страницах, так что его точно стоит взять на вооружение.
Не забывайте добавлять pointer-events: none
всем элементам, которые перекрывают контент.
4. Контент, вырванный из контекста
Вылезание элемента за границы родителя приводит нас к другой штуковине — вырыванию элемента из контекста. Про свойство z-index
знает каждый верстальщик, но мало кто вспоминает про него, когда речь идет о многослойных бутербродах из эффектов. В результате это приводит к излишнему усложнению разметки.
Рассмотрим пример. Нужно сделать эффект фонарика (что-то вроде освещения фона и границ элементов в некотором радиусе от курсора). Как подойти к этому вопросу?
Допустим у нас уже есть разметка:
<div class='custom-grid'>
<div class='item'>
<div class='text'>Lorem ipsum dolor sit amet</div>
</div>
<div class='item'>
<div class='text'>Lorem ipsum dolor sit amet</div>
</div>
и.т.д.
Можем ли мы как-то добавить подсветку прямо сюда? Да. Причем решение очень простое:
- Кладем сверху на все это большой радиальный градиент с прозрачной дыркой в центре
- С помощью
z-index
вырываем контент из текущего контекста и он автоматически располагается поверх градиента
Сам по себе радиальный градиент не представляет из себя ничего необычного:
.shadow {
position: absolute;
left: 50%;
top: 50%;
height: 200vh;
width: 200vw;
transform: translateX(-50%) translateY(-50%);
background: radial-gradient(circle at center, transparent 0%, transparent 5%, #302015 70%, #302015 100%);
}
В подобных эффектах, привязанных к мышке часто применяют размеры в 200vh/200vw для того, чтобы их края не вылезали в видимую пользователем область.
Получился бутерброд. Снизу остались бордеры, посередине лег градиент, сверху все накрылось контентом. Даже в существующую разметку такой эффект добавится всего одним элементом и парой строк CSS. Бывают конечно исключения, но все же. Осталось только оживить эффект, привязав его к мышке:
const grid = document.getElementById('js-grid');
const shadow = grid.querySelector('.shadow');
document.addEventListener('mousemove', (e) => {
const rect = grid.getBoundingClientRect();
window.requestAnimationFrame(() => {
shadow.style.left = `${e.clientX - rect.left}px`;
shadow.style.top = `${e.clientY - rect.top}px`;
});
});
Подобный прием также можно применять и с модальными окнами или меню, перекрывая все остальное красивой тенью.
5. Бутерброд из SVG и HTML
Бутерброды. Хмм… Есть еще один. Очень полезный. Решает он следующую проблему: если у нас есть какая-то схема, карта, график или еще что-то в виде SVG картинки, вставленной в разметку, то при адаптивном изменении ее размера начинают уменьшаться или увеличиваться тексты на ней. Это мало того, что может приводить к их "размыливанию" и искажению пропорций, но и выбивает эту самую схему или график из общего стиля страницы.
Чтобы это дело поправить, можно класть поверх SVG обычный div
, в котором верстать все эти надписи абсолютным позиционированием.
.mixed-graph {
> .svg {
....
}
> .dots {
position: absolute;
z-index: 1;
}
}
Удобно сразу делать viewbox='0 0 100 100'
у картинки, чтобы координаты абсолютного позиционирования в слое HTML совпали с ними же в слое SVG.
Таким образом мы сможем сделать условный график, на котором все надписи будут такими же, как и на всей остальной странице. В сочетании с адаптивной типографикой это может давать очень приятные в использовании результаты.
Вместо заключения
Начинающие верстальщики, изучайте и используйте все возможности, которые предоставляют вам ваши инструменты. Мир меняется. Многие тяжелые плагины для jQuery сейчас легко заменить парой строк CSS, да и возможности по оформлению страниц не идут ни в какое сравнение с тем, что было в начале 2000х. Пора уже изменить восприятие мира веб-разработки, принять тот факт, что "верстка" становится все более широкой областью деятельности, и начать уже делать современные сайты без оглядки на былые стереотипы и ограничения.