Данный материал – перевод статьи https://kilianvalkhof.com/2017/design/sloped-edges-with-consistent-angle-in-css/. Мне, как начинающему forntend-разработчику, этот материал был интересен. Полагаю, эта статья будет полезна и другим начинающим или обучающимся фронтендерам.
Если вы посмотрите выше, то увидите, что хедер этого блога имеет наклонный край. Это одна из моих любимых особенностей нового дизайна. Техника, которую я использовал, обеспечивает постоянный угол наклона независимо от размера экрана, позволяет показывать фоновые изображения и использует только один HTML-элемент без псевдоэлементов. Вот как я это сделал.
Требования
Было несколько требований, предъявляемых к реализации:
Внешний вид не зависит от размера экрана.
Поддержка (и правильная фиксация) фоновых изображений и текста на переднем плане.
Работа на разных устройствах (не слишком заботясь об IE).
Если я также смогу максимально упростить HTML и CSS, то это будет бонусом, но не требованием.
Первоначальная идея
Моей первой идеей для скошенных краев было использование трансформации вращения всего элемента. Это быстро привело к усложнению процесса.
header {
width:100%;
transform:rotate(2deg);
}
Поворот элемента приводит к тому, что мы видим часть фона в левом и правом верхних углах. Это нормально, мы можем решить эту проблему, сделав внутренний элемент шире и добавив отрицательное смещение, чтобы он правильно закрывал левый и правый верхние углы:
header {
width:110%;
top:-5%;
left:-5%;
transform:rotate(2deg);
}
Затем добавим к странице или дополнительному элементу параметр overflow:hidden;
, чтобы не возникало странных горизонтальных полос прокрутки:
body {
overflow:hidden;
}
header {
width:110%;
top:-5%;
left:-5%;
transform:rotate(2deg);
}
Это выглядит замечательно, но что, если добавить туда текст?
Теперь текст не только расположен под углом, но и немного выходит за пределы области просмотра. Чтобы он снова поместился в область просмотра, необходимо повернуть текст в противоположном направлении, а затем сместить его.
body {
overflow:hidden;
}
header {
width:110%;
top:-5%;
left:-5%;
transform:rotate(2deg);
}
header p {
margin-left:5%;
transform:rotate(-2deg);
}
До сих пор все работает нормально. Проблема начинается при переходе от фиксированной ширины к отзывчивой (responsive). Вот тот же элемент, только более широкий:
В правом верхнем углу снова появилась небольшая часть фона страницы. Единственный способ справиться с этим – увеличить площадь хедера за пределами области просмотра. Это происходит при каждом увеличении размера экрана и делает способ все более сложным, а значит, хрупким.
Кроме того, при использовании трансформаций наблюдается довольно сильный алиасинг (пикселизация по краям). Это, несомненно, улучшится с выходом новых версий браузера, но пока это выглядит не очень красиво.
Псевдоэлемент ::after
Другой часто используемой техникой является добавление преобразования к псевдоэлементу ::after
, а не к самому элементу. Это имеет ряд преимуществ по сравнению с приведенным выше кодом:
Есть уверенность в том, что страница не будет выходить за левый или правый верхний угол.
Нет необходимости поворачивать содержимое в обратную сторону.
Так что давайте попробуем:
header::after {
position:absolute;
content: " ";
display:block;
left:-5%;
bottom:-10px;
transform:rotate(2deg);
width:110%;
}
(полупрозрачность наложена с перекрытием, так что видно, где находятся элементы) Это работает, но нужно сместить элемент ::after
так, чтобы он полностью перекрывал нижний край, и, как в примерах выше, также нужно сделать его немного шире, чтобы не было видно краев слева или справа. Я отключил overflow:hidden;
и можно увидеть как располагается элемент ::after
.
Необходимо использовать одинаковый сплошной цвет фона как для заголовка, так и для элементов ::after
, чтобы этот эффект работал.
Псевдоэлемент ::after с границей
В CSS можно использовать комбинацию видимых и прозрачных границ, чтобы получить видимые треугольники, которые могут заменить наклонный край. Попробуем использовать ::after
с наклонной границей:
Выглядит хорошо, имеет гораздо лучшее сглаживание и работает, если сделать ширину тоже больше (при условии, что вы используете относительный размер для ширины границы):
Вместо границы, в другой технике, которую я видел, в качестве фонового изображения элемента ::after
используется SVG с шириной и высотой в 100%, что приводит к тому же результату.
До этого момента использование границы, безусловно, представляется лучшим вариантом, и в ней не слишком много кода, но она все равно не идеальна по нескольким причинам:
Еще один абсолютно позиционируемый элемент, который необходимо иметь в виду.
Трудно контролировать нужный угол и сохранять его.
Вы ограничены использованием сплошных фоновых цветов.
До этого момента ни один из моих примеров не демонстрировал использование фоновых изображений (это достаточно сложно само по себе), но фоновое изображение было тем, что я действительно хотел видеть в хедере и футере. Псевдоэлементы ::after
вообще не поддерживают этот эффект. Трансформированный хедер также создаст дополнительные проблемы при позиционировании фона.
Таким образом, все вышеперечисленные варианты имеют недостатки, связанные со сложностью кода или негибкостью при обеспечении одинакового вида при разных размерах экрана.
Использование Clip-Path
Если убрать трансформации и границы ::after
, останется clip-path
.
Clip-path не очень хорошо поддерживается, только браузеры с Webkit, Blink и Gecko поддерживают его, а для последнего необходим SVG-элемент. К счастью для меня, я могу пренебречь этим в моем личном блоге. Это Clip Path!
Добавление clip-path
не представляет сложности: с помощью функции polygon
можно описать трапецию следующим образом:
header {
clip-path: polygon(
0 0, /* left top */
100% 0, /* right top */
100% 100%, /* right bottom */
0 90% /* left bottom */
);
}
И это работает великолепно! Он работает так, как не работали методы transform
и border
. Можно добавить фоновое изображение, с наложением не происходит ничего курьезного, край резкий, и нужен всего один элемент <header>
.
Единственная оговорка: поскольку мы описываем многоугольник относительно его элемента, то при изменении ширины элемента по отношению к его высоте меняется угол наклона. То, что на мобильном телефоне выглядит как огромный угол, на экране retina вряд ли будет выглядеть как наклон. Вот такой же clip-path
на более широком элементе:
Здесь наклон гораздо менее острый, и эффект ослабевает. Нам нужно, чтобы наклон был постоянным независимо от ширины элемента. Для этого я использовал единицы измерения ширины области просмотра (vw).
Расчеты относительно ширины
Используя проценты в построении многоугольника, вы ставите точки в зависимость от высоты элемента. Если мы хотим, чтобы наклон оставался неизменным при изменении ширины, нам нужно предусмотреть возможность изменения и значения высоты. Если мы будем изменять их в равной пропорции, наклон останется неизменным.
Используя единицы ширины области просмотра, можно определить, на каком расстоянии от нижней части элемента должна находиться левая нижняя точка. В CSS это можно сделать с помощью функции calc
:
header {
clip-path: polygon(
0 0,
100% 0,
100% 100%,
0 calc(100% - 6vw)
);
}
При изменении ширины положение левой нижней точки уменьшится, создавая эффект, при котором наклон остается прежним.
Если нужно, чтобы наклон находился в верхней части элемента, то все будет проще: первая строка станет "6vw 0", и даже не понадобится calc()
.
Сейчас можно прокрутить страницу вверх до хедера (или вниз до футера) и изменить размеры браузера, чтобы увидеть эффект в действии.
Наклонные края с постоянным углом в CSS
Вот так в CSS создаются наклонные края с постоянным углом наклона, которые не нуждаются в overflow:hidden
, позволяют использовать фоны и могут быть выполнены с помощью всего одного элемента.
Если у вас есть замечания или улучшения по этой технике, пожалуйста, дайте мне знать об этом в Twitter или напишите мне!
Обновление от 5 июля 2017 г: миксин Sass
Найджел О Тул (Nigel O Toole) создал Sass-миксин, позволяющий задавать угол в градусах. Посмотрите демо.
Комментарии (7)
mi_ch_ae_l
18.10.2023 17:37Я в таком случае использую градиет поверх картинки
header { linear-gradient(5deg, transparent calc(50% - 2px), var(--color-bg) 50%), url(./bg.jpg)); }
2px вычитается для сглаживания угла
Metotron0
18.10.2023 17:37А если сделать mask, которому указать чёрно-белый градиент с резким переходом?
Хотя я предпочёл бы clip-path.
LolaBola
18.10.2023 17:37Привет из 2013, какие наклоны паря, о чем ты, это сто лет как вышло из моды
a-v-gor Автор
18.10.2023 17:37С такой стороны я не смотрел на этот вопрос. Меня интересовала техническая реализация. Спасибо за мысль!
Metotron0
18.10.2023 17:37Потому что дизайнерам сказали так не делать, поскольку неудобно прилеплять png шириной в 3840 пикселей?
Cere8ellum
Вот тоже когда читал начало статьи, параллельно размышлял, что проще реализовать с помощью неких автовычисляемых scss миксинов.