Продвинутые Мастерские — Тренажёр HTML Academy
Вторая часть мастерских, которые мы начали в прошлый раз. Эта часть объективно сложная. Элементы с прикольными эффектами, трансформациями, динамикой и сделаем слайдер на CSS!
Здесь ещё активно будет использовать псевдоэлементы ::before
и ::after
— часть, можно сказать, про них и про их эксплуатацию.
Сложность еще сдабривается парочкой моментов, когда мы используем штуки, которые еще не изучали. Они будут аж в «Тонкостях» — это последний блок в сетке Тренажёров! Я уже смирился, к тому же вещи не сильно сложные. Но по бомбить немного всё-таки не грех.
Маска при наведении
Достаточно впечатляющий и хитрый приём, который я думал делается на JS или какими-то другими шаманскими штуками. Мы создали элементы необычной формы — шестиугольник с закруглёнными углами, с помощью изображения-маски. На самом деле всё проще чем даже звучит.
Маской является изображение с прозрачной фигурой в центре — в нашем случае это шестиугольник и круг, которым мы задали трансформацию scale()
по наведению на блок.
<section class="shape"> <a class="overlay" href="#">Маска</a> <div class="details"> ... </div> </section>
Контейнеру, в нашем случае это <section>
, задаем изображение на фон — у нас это мокап сайта, задаём ему relative
и скрываем всё выпадающее из контейнера через overflow
:
.shape { position: relative; overflow: hidden; background: url("techmart.jpg") no-repeat 30% 0%; ... }
Маска здесь свёрстана через ссылку <a>
с классом .overlay
— она абсолютно позиционирована absolute, занимает всю площадь контейнера, на фон помещается картинка с прозрачной областью в виде нужной фигуры.
Вся хитрость, в общем-то в этом. Дальше уже пляшем с трансформацией и наведением — задаём scale(1)
базовый и какой-нибудь побольше при наведении на контейнер для эффекта увеличения:
.overlay { ... position: absolute; background-image: url("hexagon.svg"); /* картинка-маска */ z-index: 1; /* располагается явно над контейнером */ transition: transform 0.6s ease-out; /* плавный переход */ transform: scale(1); /* базовый размер */ } .shape:hover .overlay { transform: scale(1.07); /* увеличивается при наведении */ }
Бокс с описанием .details
работает по схеме, которую мы разобрали в выпадающих меню. Насколько я понял, это вообще стандартная практика.
Выдвигающееся описание
Тоже очень интересный эффект, который я часто встречал. И тоже думал делается как-то на JS, а не на чистом CSS.
Сама вёрстка немного упоротая, хотя я уже не удивлюсь если это нормальная практика. Мы явно не задаём ни заголовок ни описание в выдвигающемся окне — вся эта информация указана в data-атрибутах ссылки.
<section class="works"> <a class="caption-link" href="#" data-title="Sunset" data-description="Сайт туристического агентства, специализирующегося на незабываемых поездках в тёплые страны."> <img src="shot-1.jpg" alt="Sunset"> </a> </section>
То есть по вёрстке у нас буквально получается только контейнер, внутри которого одна ссылка <a>
, внутри которой картинга <img>
.
Здесь на сцену выходят псевдоэлементы — именно через них, а точнее через свойство content
и функцию attr()
, которая принимает в аргумент дата-атрибут, мы и выводим информацию в выдвигающемся окне.
.caption-link::before { content: attr(data-title); } .caption-link::after { content: attr(data-description); }
Интересный подход, мне бы в голову не пришел. Итак, компоненты все у нас есть, теперь стилизуем и анимируем. Во-первых, оба элемента — и <a>
, и <img>
, у нас занимаю полностью весь контейнер, но находятся в разных состояниях.
Картинка <img>
в базовом состоянии закрывает элемент, а при наведении смещается вправо на всю ширину блока:
.caption-link img { display: block; max-width: 100%; transition: transform 0.3s ease; } .caption-link:hover img { transform: translateX(100%); }
С ссылкой же хитрость. Сам элемент ссылки по сути не двигается вообще, двигаются только псевдоэлементы и картинка. Сделано это для того, чтобы в любой момент времени, даже во время анимации, можно было на нее нажать.
.caption-link { position: relative; z-index: 1; display: block; overflow: hidden; }
Ссылке <a>
задаётся z-index
, чтобы быть выше остальных элементов, позиция relative
для позиционирования псевдоэлементов и через overflow
мы скрываем выезжающие туда-сюда картинку и псевдоэлементы.
Псевдоэлементы же позиционируем абсолютно, стилизуем как нам надо и ставим базовую позицию смещённой влево, а по наведению возвращаем их в центр:
.caption-link::before, .caption-link::after { ... position: absolute; z-index: -1; /* чтобы быть ниже самой ссылки */ transition: transform 0.3s ease-in-out; transform: translateX(-80px); } .caption-link:hover::before, .caption-link:hover::after { transform: translateX(0); }
Эффектные ссылки
Продолжаем эксплуатировать псевдоэлементы, теперь сделаем несколько интересных эффектов с кнопками. Я часто видел такие «пойнтеры» делают в меню и вот, наконец, узнал как их можно сделать. Точнее один из эффектных вариантов.
Все это просто ссылки <a>
с текстом и псевдоэлементами, нет смысла сюда писать вёрстку. Разберёмся только с тем, что происходит в CSS.
Первая кнопка, «Апельсин», очень простая — один псевдоэлемент, появляется и исчезает с помощью свойства opacity
и двигается через translateY()
:
.effect-1 a::after { ... opacity: 0; transition: opacity 0.3s, transform 0.3s; transform: translateY(10px); } .effect-1 a:hover::after { opacity: 1; transform: translateY(0); }
Вторая кнопка, «Виноград», использует уже два псевдоэлемента — позиционируем их отдельно, используем translate()
и rotate()
и не забываем задать свойство transform-origin
для каждого, иначе они будут поворачиваться от центра.
.effect-2 a::before, .effect-2 a::after { ... position: absolute; opacity: 0.2; /* 20% видимости */ transition: all 0.3s; } .effect-2 a::before { top: 0; left: 0; /* прижимаем к левому-верхнему углу */ transform-origin: 0 0; /* там же и origin */ transform: rotate(90deg); } .effect-2 a::after { right: 0; bottom: 0; /* аналогично, правый нижний угол */ transform-origin: 100% 100%; /* там же и origin */ transform: rotate(90deg); } .effect-2 a:hover::before { left: 50%; /* перемещаем к центру блока*/ opacity: 1; /* делаем не прозрачным */ transform: rotate(0deg) translateX(-50%); /* поворачиваем обратно и прижимаем к верху */ } .effect-2 a:hover::after { right: 50%; opacity: 1; transform: rotate(0deg) translateX(50%); /* всё аналогично, но в обратную сторону */ }
Третья кнопка, «Лайм», использует всего один атрибут, но другой эффект. Здесь, снова задействована функция attr () — через нее мы выводим ещё одно слово «лайм» поверх в виде псевдоэлемента.
По сути в базовом состоянии мы видим псевдоэлемент, а по наведению он исчезает и «открывает» текст самого элемента.
.effect-3 a::before { position: absolute; color: #ffffff; content: attr(data-hover); transition: transform 0.3s, opacity 0.3s; } .effect-3 a:hover::before { opacity: 0; transform: scale(0.9); }
Четвёртая кнопка, «Киви» — это, в общем-то, такой же прием, что и с первой кнопкой, только псевдоэлемента теперь два и еще изменяется цвет текста при наведении.
Даже код копировать не буду — это реально тоже самое. Видимо, дали нам её просто для закрепления всего пройденного.
Закруглённые внутрь углы
Честно говоря, мне в голову такая идея ни разу не приходила. С трудом могу представить ситуации где нужно это, кроме вариантов стилизации под почтовую марку, наверное.
Но в этом примере нам еще и объясняют работу интересного свойства clip
. И есть ощущение, что задача была придумана в принципе ради него.
Свойство clip
по своей сути работает как crop-tool в Photoshop — мы выделяем область которая будет видна, а остальные части, не попавшие в выделение скрываются.
Выделение происходит с помощью функции rect(top, right, bottom, left)
, которая принимает четыре аргумента — границы сверху, справа, снизу и слева — именно в таком порядке.
Позиции границ указываются в размерных величинах, чаще всего, конечно, в пикселях px
. Кстати, кроме прямоугольника, похоже, ничего выделить до сих пор и нельзя. По крайней мере без надстроек для CSS.
Итак, зачем нам вообще это свойство? С его помощью мы сделаем открытку с вогнутыми углами. Для начала сверстаем заготовку:
<blockquote class="outer"> <div class="inner"> <p>Любую теорию можно согласовать с любым фактом, если принять некоторые дополнительные допущения.</p> <footer> <cite>— Хантер С. Томпсон</cite> </footer> </div> </blockquote>
Да, это блок цитаты и внутри него блок для стилизации. Верстаем их в виде такого толстого креста — один больше по вертикали, второй по горизонтали.
Теперь нам нужны сами вогнутости. Здесь опять выходят на сцену псевдоэлементы! Создаем кольцо с помощью толстой рамки border
и позиционируем её в углу.
А с помощью clip()
отрезаем только один угол:
Делаем это четыре раза — по два псевдоэлементы ::before
и ::after
, обоим элементам .outer
и .inner
.
Перекрашиваем их в белый и получаем натурально вогнутые углы!
Слайдер на CSS
Очень интересный приём создания вполне рабочего слайда без использования JavaScript. Он вряд ли используется часто, так как скорее всего добавлять в него новые фото проблематично, но как практическое задание очень круто.
В нашем случае слайдер — это один длинный элемент с картинками <img>
внутри, который двигается по горизонтали с помощью translateX()
, который находится внутри элемента с overflow: hidden;
.
Основная сложность в этой задаче — это «запрограммировать» переключение слайдера используя только CSS. Для этого мы используем радиокнопки, псевдокласс :checked
и селектор последующих элементов ~
.
<div class="slider-block"> <input type="radio" id="btn-1" name="toggle" checked> <input type="radio" id="btn-2" name="toggle"> <input type="radio" id="btn-3" name="toggle"> <div class="container"> <div class="slider"> <img src="img-1.jpg" alt="Первое изображение"> <img src="img-2.jpg" alt="Второе изображение"> <img src="img-3.jpg" alt="Третье изображение"> </div> </div> </div>
Здесь у нас три радио кнопки, связанные между собой через name
. Между собой кнопки и слайдер в вёрстке связаны только общим родителем.
Вся «магия» происходит в CSS — мы задаём очень хитрый селектор, который применяет свои свойства «проверяя» наличие атрибута checked
через псевдокласс у кнопок, а далее через селектор последующих элементов ~
указываем изменения в свойстве слайдера.
#btn-1:checked ~ .container .slider { transform: translate(0); } #btn-2:checked ~ .container .slider { transform: translate(-450px); } #btn-3:checked ~ .container .slider { transform: translate(-900px); }
Расшифровывая, например, второй селектор:
Задать трансформацию по горизонтали на 450 px
влево слайдеру .slider
, находящемуся в контейнере .container
, который идет после выбранной :checked
второй кнопки #btn-2
.
Каждый раз меняя выбор, то есть по факту переставляя атрибут checked, мы применяем разные селекторы, а соответственно разную позицию слайдера.
В тренажёре немного усложнено ради стилизации кнопок — они сделаны через <label>
связанные с радиокнопками через for=""
, а сами кнопки скрыты.
Breadcrumbs или «хлебные крошки»
На последок создадим блок навигации называемый «хлебные крошки» — это по сути расшифровка адреса страницы, чаще всего используются на многостраничных сайтах и форумах, где вложенность страниц важна и навигация по ним и по категориям необходима.
Финальный результат выглядит вот так:
На первый взгляд всё просто — несколько элементов с эффектами по наведению. Мы же уже делали меню в прошлой части! Здесь нюанс в нумерации — она сделана не через <ol>
, как можно предположить, а используя функцию counter()
и смежные с ней свойства counter-reset
и counter-increment
.
Функцию счётчика counter()
, насколько я понял, можно использовать только как контент content
для псевдоэлементов, хотя странно — функция же вернёт просто строку и, по идее, можно вписывать куда угодно. Как-нибудь проверим!
Для начала использования функции нужно задать свойство counter-reset
какому-либо контейнеру, где функция будет использоваться. Свойство принимает имя счётчика, которое потом будет использоваться в работе — читай переменная. Также необязательно можно задать его начальное значение, по умолчанию оно равно нулю.
.breadcrumbs { /* контейнер хлебных крошек */ ... counter-reset: flag; }
Сами кнопки у нас это ссылки <a>
, а нумерация — их псевдоэлемент ::before
. Именно ему мы записываем счётчик counter(flag)
как контент, а свойством counter-increment
мы увеличиваем счетчик — это своего рода свойство-приращение +1 к функции.
.breadcrumbs a::before { ... content: counter(flag); /* выведет значение счётчика*/ counter-increment: flag; /* прирастит к счетчику +1 */ }
При этом counter-increment
работает в селекторе одновременно с content
, то есть в нашем случае отобразиться значение 1
, так как приращение уже сработало в CSS-правиле. Для нумерации с нуля, нужно было либо задать counter-reset: -1;
, либо, например, отдельно задавать первый элемент :first-child
без приращения.
Таким образом, каждый псевдоэлемент у ссылки в контейнере .breadcrumbs
будет иметь свой счетчик, повышающийся каждое применение, то бишь каждый новый псевдоэлемент в разметке.
Второй особенностью здесь является реализация стрелок — это псевдоэлементы ::after
с трансформацией и особенностью свойства border-radius
.
Оказалось, что border-radius тоже может принимать комплекс значений — каждый угол отдельно. Начиная от левого верхнего по часовой стрелке, можно указать отдельно закругление всем углам бокса. В тренажёре мы так и поступили — закруглили псевдоэлементу ::after
один угол и повернули на 45 градусов:
.breadcrumbs a::after { ... border-radius: 50px 0 0 0; /* 50px левому верхнему углу, остальные 0 */ transform: rotate(-45deg); }
Дальше уже стилизация, эффекты наведения и остальные отступы — уже не столь интересно в контексте задачи.
Испытания
Испытаний всего два — первое испытание в основном на свойство clip. За нас всё сверстали, нам нужно только подставить правильные селекторы.
Я на нём попыхтел, но когда решил пойти сначала от списка — стало сильно легче. Честно, разбираться вот в делениях графика такое себе, но вообще интересно было. Вспомнили, кстати, про селекторы по атрибуту, я сначала тоже голову поломал — думал уже через nth-child
даже.
Второе испытание какое-то для этой части прям несправедливо лёгкое. Тоже уже всё сверстано и надо подставить селекторы, но тут буквально два класса и их псевдоэлементы.
Вот и прошли мы Мастерские. В конце последней части там еще было два урока про отметку на карте, но я решил не конспектировать, так как там просто про border-radius тот же самый.
Вообще, я думал всё уместиться в одну статью, но я, как обычно, не умею в коротко. Пусть так.
Спасибо большое за внимание, надеюсь, что это будет хоть кому-то полезно и интересно!
Ссылки на другие статьи по HTML Academy:
Знакомство с Веб-разработкой
Знакомство с HTML и CSS
Знакомство с JavaScript
Знакомство с PHP
Таблицы и подробно о формах
Наследование, каскады и селекторы
Блочная модель, поток и сетка на float
Гибкие флексбоксы display: flex
Удобные сетки на гридах display: grid
Пропуск блока «Погружение»
Позиционирование и двумерные трансформации
Теневое искусство и линейные градиенты
CSS-фильтры и Кекстаграм
Мастерские
Продвинутые Мастерские ← Вы здесь
…
Остальные статьи можно посмотреть у меня на главной странице блога.
Также мои соц. сетки, которые я продолжаю вести:
Мой Twitter
Мой Telegram
Мой Паблик ВК
Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!