Маска при наведении
В этой серии заданий мы реализуем довольно распространённый интерфейсный приём — появление текстового описания по наведению на блок с картинкой — в необычном виде.
Для начала применим к основным элементам блока с текстом базовый стиль: размер шрифта заголовков и параграфа, цвет фона и текста, общий вид кнопки-ссылки, ведущей к подробной информации. В коде пока что нет ничего необычного, кроме полупрозрачного фонового цвета у текстового блока, заданного с помощью rgba
, и свойства border-radius
для скруглённых углов у кнопки-ссылки.
Получившийся блок с текстовым описанием будет скрыт по умолчанию, а отображаться будет при наведении курсора на контейнер. Контейнеру мы присвоим фоновое изображение. С помощью псевдокласса :hover
и свойства display
будем управлять видимостью текстового блока.
На этом шаге создадим и применим к картинке маску нестандартной формы.
Для этого добавим в блок .shape
ссылку, которая будет являться верхним слоем над всем контейнером и будет использоваться как маска. В качестве фона слоя-маски используем изображение в формате .svg с непрозрачными краями и прозрачным центром. Спозиционируем этот блок-маску абсолютно, чтобы он располагался поверх блока с текстовым описанием и контентной картинкой. Фоновая контентная картинка будет при этом проглядывать через прозрачную часть слоя-маски.
Также давайте немного оживим блок с маской и будем плавно изменять его форму при наведении с помощью трансформации масштабирования transform: scale
.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<section class="shape nerds"> <a class="overlay round" href="#">Маска</a> <div class="details bg"> <header>nёrds</header> <p>Сайт маленькой, но гордой дизайн-студии из Краснодара: фиксированная вёрстка, спрайты, HTML5, CSS3, javascript.</p> <a class="button" href="/">Посмотреть</a> </div> </section> <section class="shape techmarkt"> <a class="overlay octagon" href="#">Маска</a> <div class="details"> <header>Техномаркт</header> <p>Сайт интернет-магазина строительных материалов и инстументов для ремонта: фиксированная вёрстка, спрайты, HTML5, CSS3.</p> <a class="button" href="#">Посмотреть</a> </div> </section> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
html, body { margin: 0; padding: 0; font-size: 14px; font-family: "Helvetica Neue", "Helvetica", sans-serif; text-align: center; background-color: #161616; } section { display: inline-block; margin-top: 10px; } .shape { position: relative; width: 300px; height: 300px; background-color: #ffffff; overflow: hidden; } .shape .details { display: none; width: 310px; height: 310px; padding-top: 60px; color: #ffffff; background-color: rgba(75, 90, 120, 0.9); } .details header { display: block; padding-bottom: 10px; font-size: 26px; text-transform: uppercase; border-bottom: 1px solid #cccccc; } .details p { width: 70%; margin: 10px auto; line-height: 1.4; } .button { position: relative; z-index: 2; display: inline-block; margin-top: 15px; padding: 5px 15px; text-decoration: none; color: #ffffff; background-color: #2f3644; border-radius: 20px; } .button:hover { color: #2f3644; background-color: #ffffff; } .shape.techmarkt { background: url("techmarkt.jpg") no-repeat 30% 0%; } .shape.nerds { background: url("nerds.jpg") no-repeat 30% 0%; } .shape:hover .details { display: block; } .overlay { position: absolute; top: 0; left: 0; z-index: 1; width: 310px; height: 310px; font-size: 0; background-repeat: no-repeat; background-position: 0 0; outline: 0; transition: transform 0.6s ease-out; transform: scale(1); } .shape:hover .overlay { transform: scale(1.07); } .overlay.octagon { background-image: url("oct.svg"); } .overlay.round { background-image: url("round.svg"); } |
Выдвигающееся описание
Суть данной техники заключается в том, чтобы не создавать в разметке дополнительные блоки для описания, а хранить тексты в пользовательских data-
атрибутах элементов. В HTML5 пользовательские атрибуты, начинающиеся с data-
, могут быть добавлены любому HTML-элементу для хранения текстовой информации.
Особой прелестью такого подхода является то, что мы можем обращаться к текстовому значению атрибута HTML-элемента непосредственно из CSS. Делается это с помощью свойства content
, задающего генерируемое содержимое псевдоэлементов и функции attr()
, которая применяется для добавления значения атрибута HTML-элемента в стилевое свойство.
Например, если у нас есть в разметке элемент <p data-text="hello">world</p>
, то мы можем получить надпись «hello world», взяв «hello» из атрибута data-text
в CSS и отобразив его в псевдоэлементе ::before
:
p::before { content: attr(data-text) " "; }
В нашем случае давайте хранить тексты в атрибутах ссылки: заголовок блока в тексте атрибута data-title
, а описательную часть — в атрибуте data-description
. Соответственно заголовок будем выводить в качестве контента псевдоэлемента ::before
, а описание — содержимым псевдоэлемента ::after
.
Теперь давайте реализуем плавное появление и сокрытие блока с текстовой информацией.
Для этого:
- Спрячем псевдоэлементы
::before
и::after
под картинку в блоке.caption-link
отрицательным значением свойстваz-index
. - По наведению на
.caption-link
будем сдвигать картинку на расстояние, равное ширине картинки, вправо, так чтобы блок с описанием становился видимым, оставаясь на прежнем месте. - Ограничим область видимости за границей блока
.caption-link
с помощьюoverflow: hidden
, чтобы визуально казалось, что картинка плавно уезжает и скрывается.
Для этого сдвинем трансформацией немного влево псевдоэлементы с текстом, а при наведении будем двигать их обратно в нормальное положение. Таким образом создастся эффект синхронного появления текстового блока вместе с сокрытием картинки.
HTML:
1 2 3 4 5 |
<section class="works"> <a class="caption-link" href="#" data-title="Sunset" data-description="Сайт туристического агентства, специализирующегося на незабываемых поездках в тёплые страны."> <img src="shot-1.jpg" alt="Sunset"> </a> </section> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
html, body { margin: 0; padding: 0; font-family: "Roboto", sans-serif; font-size: 14px; color: #333333; background: #f5f5f5; } .works { width: 240px; margin: 100px auto; padding: 20px; background: white; box-shadow: 0 0 3px #cccccc; } .caption-link { position: relative; z-index: 1; display: block; overflow: hidden; } .caption-link img { display: block; max-width: 100%; transition: transform 0.3s ease; } .caption-link:hover img { transform: translateX(100%); } .caption-link::before, .caption-link::after { position: absolute; z-index: -1; width: 100%; text-align: center; background: #333333; box-sizing: border-box; transition: transform 0.3s ease-in-out; transform: translateX(-80px); } .caption-link::before { content: attr(data-title); height: 30%; padding: 30px; font-size: 22px; font-weight: bold; color: #ffffff; } .caption-link::after { content: attr(data-description); top: 30%; height: 70%; padding: 0 30px; color: #d7bb97; } .caption-link:hover::before, .caption-link:hover::after { transform: translateX(0); } |
Эффектные ссылки
В этой серии заданий мы разберём интересные эффекты, которые можно применить к простым текстовым ссылкам, используя стилизацию псевдоэлементов.
В первом примере псевдоэлемент используется как декоративное подчёркивание ссылки. Давайте скроем его по умолчанию и немного опустим, а при наведении курсора на ссылку применим трансформацию, которая приподнимет псевдоэлемент обратно, и одновременно плавно покажем его.
В этом и следующем задании помимо ::after
задействуем ещё и ::before
, а также будем по наведению применять к псевдоэлементам более сложные трансформации. Сначала зададим стиль исходного состояния: спозиционируем и применим к псевдоэлементам трансформацию поворота так, чтобы они стали декоративными вертикальными рамками справа и слева от ссылки. А теперь по наведению на ссылку будем плавно менять полупрозрачность псевдоэлементов и перемещать их так, чтобы они вместо левой и правой становились верхней и нижней рамкой соответственно.
В этом задании воспользуемся ранее изученным приёмом одновременного использования пользовательского data-
атрибута, свойства content
и функции attr()
. Сначала с помощью кастомного атрибута зададим псевдоэлементу содержимое идентичное тексту ссылки. Затем спозиционируем псевдоэлемент так, чтобы он перекрыл оригинальный текст ссылки сверху. А при наведению на ссылку будем немного уменьшать и одновременно плавно скрывать её псевдоэлемент, чтобы оригинальный текст снова становился видим.
Создадим ещё одну эффектную ссылку. На этот раз псевдоэлементы будут играть роль верхней и нижней декоративной рамки. Мы будем по-прежнему управлять их позицией и прозрачностью по наведению на ссылку. Сначала установим псевдоэлементы в исходную позицию вверху и внизу ссылки. А теперь сделаем псевдоэлементы полностью прозрачными и по наведению на ссылку будем плавно их «проявлять» изменением свойства opacity
, а также менять их положение трансформацией для создания эффекта плавного появления.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 |
<div class="effect-1"> <a href="#">Апельсин</a> </div> <div class="effect-2"> <a href="#">Виноград</a> </div> <div class="effect-3"> <a href="#" data-hover="Лайм">Лайм</a> </div> <div class="effect-4"> <a href="#">Киви</a> </div> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
html, body { margin: 0; padding: 0; font-family: "Open Sans", sans-serif; font-size: 22px; color: #333333; background-color: #f5f5f5; } h1 { margin: 25px 0; font-size: 30px; font-weight: 300; text-align: center; } a { position: relative; display: inline-block; text-decoration: none; text-transform: uppercase; font-weight: 300; letter-spacing: 1px; outline: none; } div[class^="effect-"] { width: 400px; margin: 0 auto; padding: 30px 0; text-align: center; } .effect-1 { background-color: #f19f0f; } .effect-1 a { padding: 6px 0 8px; color: #ffffff; } .effect-1 a::after { content: ""; position: absolute; top: 100%; left: 0; width: 100%; height: 4px; background-color: rgba(0, 0, 0, 0.1); opacity: 0; transition: opacity 0.3s, transform 0.3s; transform: translateY(10px); } .effect-1 a:hover::after { opacity: 1; transform: translateY(0px); } .effect-2 { background-color: #435a6b; } .effect-2 a { padding: 0 20px; height: 45px; line-height: 45px; color: #ffffff; } .effect-2 a::before, .effect-2 a::after { content: ""; position: absolute; width: 45px; height: 2px; background-color: #ffffff; opacity: 0.2; transition: all 0.3s; } .effect-2 a::before { top: 0; left: 0; transform: rotate(90deg); transform-origin: 0 0; } .effect-2 a::after { right: 0; bottom: 0; transform: rotate(90deg); transform-origin: 100% 100%; } .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%); } .effect-3 { background-color: #2ac56c; } .effect-3 a { color: rgba(0, 0, 0, 0.2); font-weight: bold; } .effect-3 a::before { content: attr(data-hover); position: absolute; color: #ffffff; transition: transform 0.3s, opacity 0.3s; } .effect-3 a:hover::before { transform: scale(0.9); opacity: 0; } .effect-4 { background-color: #3fa46a; } .effect-4 a { padding: 8px; font-weight: bold; color: #237546; } .effect-4 a:hover { color: #ffffff; transition: color 0.3s; } .effect-4 a::before, .effect-4 a::after { content: ""; position: absolute; left: 0; width: 100%; height: 2px; background-color: #ffffff; opacity: 0; transition: opacity 0.3s, transform 0.3s; } .effect-4 a::before { top: 0; transform: translateY(-10px); } .effect-4 a::after { bottom: 0; transform: translateY(10px); } .effect-4 a:hover::before, .effect-4 a:hover::after { opacity: 1; transform: translateY(0px); } |
Закруглённые внутрь углы
С помощью свойства border-radius
мы можем легко сглаживать края блоков и даже сделать блок визуально полностью круглым. Но, к сожалению, border-radius
может сделать только выпуклые углы, а вогнутые — нет.
В этой серии заданий мы построим блок с вогнутыми углами.
Для этого, помимо ранее известных свойств, в текущей серии заданий мы воспользуемся свойством clip
.
Свойство clip
определяет прямоугольную область элемента, в которой будет показано его содержимое. Все, что не поместится в эту область, будет невидимым. Свойство clip
работает только для абсолютно спозиционированных элементов.
Синтаксис свойства clip
с функцией, вырезающей прямоугольную область:
clip: rect(верхняя-координата, правая-координата, нижняя-координата, левая-координата);
В качестве значений используется расстояние от края элемента до области вырезки, которое задается в единицах CSS — px, em… Если край области нужно оставить без изменений, устанавливается значение auto
. Нагляднее о том, как именно применяются координаты, показано на картинке:
Для построения блока с вогнутыми краями создадим поочерёдно для каждого угла свой маскирующий блок.
Начнём с нижнего левого угла.
Продолжим маскировать углы. Аналогично левому нижнему замаскируем правый нижний угол блока.
HTML:
1 2 3 4 5 6 7 8 |
<blockquote class="outer"> <div class="inner"> <p>Любую теорию можно согласовать с любым фактом, если принять некоторые дополнительные допущения.</p> <footer> <a href="">— Хантер С. Томпсон</a> </footer> </div> </blockquote> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
html, body { margin: 0; padding: 0; font-family: "Lora", serif; color: #333333; background-color: rgb(42, 113, 113); } .outer { position: relative; display: block; max-width: 320px; margin: 50px auto 0; padding: 20px 0; background-color: #ffffff; border: 1px solid #888888; border-width: 1px 0; } .inner { position: relative; padding: 0px 40px; font-style: italic; background-color: #ffffff; } .inner p { margin: 0 0 1.0em; font-size: 1.5em; } .inner footer { display: block; text-align: right; } .inner footer a { text-decoration: none; color: #333333; } .inner { margin: 0 -20px; } .inner::before, .inner::after, .outer::before { content: ""; position: absolute; z-index: 1; width: 80px; height: 80px; border: 20px solid #ffffff; border-radius: 50%; box-sizing: border-box; } .inner::before { bottom: -60px; left: -40px; clip: rect(auto, auto, 40px, 40px); } .inner::after { right: -40px; bottom: -60px; clip: rect(auto, 40px, 40px, auto); } .outer::before { top: -40px; left: -60px; clip: rect(40px, auto, auto, 40px); } .outer::after { content: ""; position: absolute; z-index: 1; width: 80px; height: 80px; border: 20px solid #ffffff; box-sizing: border-box; top: -40px; right: -60px; border-radius: 50%; clip: rect(40px, 40px, auto, auto); } |
Пример: Статистика браузеров
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<section> <h1>Статистика браузеров (06.2014)</h1> <div class="pie-container"> <div id="safari" class="pie"></div> <div id="ie" class="pie"></div> <div id="firefox" class="pie"></div> <div id="chrome" class="pie"></div> </div> <div class="stats"> <ul> <li data-name="Chrome">Chrome</li> <li data-name="Firefox">Firefox</li> <li data-name="Internet Explorer">Internet Explorer</li> <li data-name="Safari">Safari</li> </ul> </div> </section> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
html, body { width: 550px; margin: 0; padding: 0; font-family: "Arial", sans-serif; color: #333333; background-color: #f5f5f5; } main { position: relative; display: block; width: 500px; height: 300px; margin: 0 auto; } h1 { margin: 0; margin-bottom: 10px; padding: 10px 0; } .pie-container { position: relative; float: left; width: 150px; height: 150px; border-radius: 50%; box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.8); } .pie-container::after { content: ""; position: absolute; top: 25%; left: 25%; z-index: 50; width: 50%; height: 50%; color: white; background-color: #f5f5f5; border-radius: 50%; box-shadow: inset 0px 0px 4px rgba(0, 0, 0, 0.8); } .pie { position: absolute; width: 100%; height: 100%; background-color: #aaaaaa; border-radius: 50%; clip: rect(0px, 75px, 150px, 0px); } #safari { z-index: 10; background-color: #aaaaaa; transform: rotate(-20deg); } #ie { z-index: 20; background-color: #0074d9; transform: rotate(160deg); } #firefox { z-index: 30; background-color: #ff851b; transform: rotate(20deg); } #chrome { z-index: 40; background-color: #2ecc40; transform: rotate(100deg); } .stats { float: left; margin-left: 50px; } .stats ul { list-style: none; } .stats li { position: relative; margin: 10px 0; } .stats li::before{ content: ""; position: absolute; top: 2px; left: -25px; width: 15px; height: 15px; background-color: #aaaaaa; } li[data-name="Chrome"]::before { background-color: #2ecc40; } li[data-name="Firefox"]::before { background-color: #ff851b; } li[data-name="Internet Explorer"]::before { background-color: #0074d9; } |
Слайдер на CSS
В этой серии мы будем строить полнофункциональный слайдер на HTML и CSS без применения JavaScript.
Сначала нужно собрать разметку с картинками в нужном виде:
- картинки располагаются в ряд;
- у общего контейнера должно быть задано свойство
overflow: hidden
, скрывающее всё, кроме текущей видимой картинки; - а ширина дочернего контейнера должна равняться суммарной ширине всех картинок внутри.
Для начала внесём кнопки и подписи к ним в HTML, немного декорируем подписи и скроем сами кнопки. Кнопки и подписи связаны между собой атрибутами id
и for
, поэтому клик на подписи будет выделять и соответствующий чекбокс (даже если он невидим).
Теперь нам нужно в зависимости от состояния невидимых радио-кнопок соответствующим образом стилизовать видимые подписи. Для этого воспользуемся подобным селектором:
#btn-1:checked ~ .slider-controls label[for="btn-1"] { ... } Что он выбирает? Подпись в блоке .slider-controls
, идущем в разметке после выделенной радио-кнопки с id="btn-1"
. Причём подпись с атрибутом for="btn-1"
, то есть связанную с этой радио-кнопкой. То что нужно!
Теперь у нас есть действующие кнопки переключения слайдов. Осталось подобным образом реализовать плавный сдвиг контейнера с картинками, чтобы в зависимости от выделенной радио-кнопки показывать соответствующую по счёту картинку. Для этого применим такой селектор: #btn-1:checked ~ .slider-inner .slider-slides { ... } И в зависимости от того, какая кнопка выделена, будем сдвигать контейнер с картинками на нужное расстояние.
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<section> <h1>Кексогалерея</h1> <div class="slider"> <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="slider-controls"> <label for="btn-1"></label> <label for="btn-2"></label> <label for="btn-3"></label> </div> <div class="slider-inner"> <div class="slider-slides"> <img src="keks-1-small.jpg" alt="Кекс смотрит на еду"> <img src="keks-2-small.jpg" alt="Кекс смотрит на тебя"> <img src="keks-3-small.jpg" alt="Кекс не хочет никуда смотреть"> </div> </div> </div> </section> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
html, body { margin: 0; padding: 0; font-family: "Open Sans", sans-serif; color: #333333; background-color: #f5f5f5; } section { width: 450px; margin: 40px auto; background-color: white; box-shadow: 0 0 3px #cccccc; } h1 { margin: 0; padding: 10px 0; font-size: 28px; font-weight: normal; text-align: center; } .slider { position: relative; } .slider input[type=radio] { display: none; } .slider-inner { overflow: hidden; } .slider-slides { width: 300%; transition: transform 0.8s ease; } .slider-slides img { float: left; width: 450px; height: 320px; } .slider-controls { margin-bottom: 10px; text-align: center; } .slider-controls label { display: inline-block; width: 10px; height: 10px; margin: 0 3px; background-color: #cccccc; border: 4px solid white; border-radius: 50%; box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.8); transition: background-color 0.2s; cursor: pointer; } #btn-1:checked ~ .slider-controls label[for="btn-1"], #btn-2:checked ~ .slider-controls label[for="btn-2"], #btn-3:checked ~ .slider-controls label[for="btn-3"] { background-color: #666666; } #btn-1:checked ~ .slider-inner .slider-slides{ transform:translate(0); } #btn-2:checked ~ .slider-inner .slider-slides{ transform:translate(-450px); } #btn-3:checked ~ .slider-inner .slider-slides{ transform:translate(-900px); } |
Хлебные крошки
В этой серии заданий мы построим необычные хлебные крошки: ссылки в них будут выглядеть как стрелки.
Кстати, «хлебными крошками» называется навигационный блок, который показывает в каком разделе сайта вы находитесь, а также путь к этому разделу от главной страницы сайта. Крошки чем-то похожи на пути в файловой системе.
Этот элемент обычно верстают очень просто — последовательность ссылок внутри блока с классом. А вот вариантов оформления существует много. И мы разберём один из достаточно сложных.
Исходная заготовка включает в себя контейнер .breadcrumbs
с тремя ссылками. Контейнер сделан блочно-строчным, а ссылки выстроены в ряд с помощью float
. Также заданы некоторые исходные размеры, отступы и другие свойства.
Всё дополнительное оформление ссылок мы будем делать с помощью псевдоэлементов. И начнём с создания «стрелок» на концах ссылок с помощью ::after
. И для этого на первом шаге зададим псевдоэлементам базовые размеры, позиционирование и фон.
помощью псевдоэлемента ::after
мы создали в каждой ссылке по красному квадрату. Квадраты спозиционировали в правой части ссылок. Сейчас мы будем превращать их в стрелки.
Первым делом нужно будет добавить квадратам резкую тень со смещением в один пиксель — она будет контуром стрелок.
Затем мы сильно закруглим один из углов каждого квадрата. Свойство border-radius
может работать подобно margin
или padding
и задавать разные радиусы скругления для каждого угла элемента. Для этого радиусы записываются через пробел:
1 2 3 4 5 6 7 |
border-radius: 1px 2px 3px 4px; /* 1px - верхний левый угол 2px - верхний правый угол 3px - нижний правый угол 4px - нижний левый угол */ |
Обратите внимание, что правый паддинг у ссылок и расположение квадратов подобраны таким образом, чтобы текст ссылок не перекрывался скруглённой стороной квадрата.
Затем с помощью трансформаций нужно повернуть квадраты на 45°
и немного уменьшить их, так как диагональ квадрата больше высоты ссылки.
Перед вами практически готовые стрелки. Осталось только убрать вспомогательные фоны и рамки.
Для начала избавимся от вспомогательных outline
у ссылок.
Затем, чтобы стрелки слились со ссылками, изменим цвет фона у ::after
с красного на белый.
А потом изменим цвет тени псевдоэлементов, чтобы контур стрелок не был таким резким и сливался с тенью контейнера.
Напоследок зададим внешний вид ссылок и стрелок при наведении и в активном состоянии. Для этого зададим фон сразу для нескольких селекторов:
1 2 3 4 5 6 |
.breadcrumbs a:hover, .breadcrumbs a:hover::after, .breadcrumbs a.active, .breadcrumbs a.active::after { ... } |
Это нужно для того, чтобы и ссылка, и её псевдоэлемент меняли фон одновременно и визуально оставались одним целым.
Теперь давайте добавим нумерацию ссылок. Для этого используем оставшийся свободным псевдоэлемент ::before
.
Мы будем задавать номера ссылок автоматически с помощью CSS. Для этого используем следующие свойства:
counter-reset
, которое позволяет создать переменную-счётчик;counter-increment
, которое позволяет увеличивать значение счётчика;- функцию
counter()
, которая позволяет передавать значение счётчика свойствуcontent
у псевдоэлементов.
В исходном CSS для .breadcrumbs
уже добавлено свойство counter-reset: flag
. То есть наш счётчик уже создан и называется flag
.
Чтобы увеличивать счётчик, нужно добавить свойство counter-increment: flag
к каждому элементу, который будет нумероваться. А чтобы считывать значение счётчика и передавать его в псевдоэлементы, нужно задать им свойство content: counter(flag)
.
Логично и изменение нумерации, и её отображение производить в самом ::before
у ссылок:
1 2 3 4 5 |
.breadcrumbs a::before { content: counter(flag); counter-increment: flag; ... } |
Ну и конечно же добавим базовое оформление для номеров ссылок.
Давайте завершим создание хлебных крошек: дооформим нумерацию, а также немного изменим стиль первой ссылки, избавившись от слишком большого отступа слева.
Соберём резюме интересных приёмов, использованных в этой серии заданий:
- по полной были задействованы оба псевдоэлемента;
- разные размеры скругления углов в сочетании с трансформациями поворота и масштабирования — для создания стрелок;
- резкие тени — для имитации рамок, хотя того же эффекта можно было добиться с помощью
border
; - использованы свойства для создания счётчиков и автоматической нумерации:
counter-reset
иcounter-increment
; - использована функция
counter()
для отображения значения счётчиков в свойствеcontent
.
HTML:
1 2 3 4 5 |
<div class="breadcrumbs"> <a href="#">Главная</a> <a class="active" href="#">Курсы</a> <a href="#">Селекторы</a> </div> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
html, body { min-width: 400px; margin: 0; padding: 0; font-family: "PT Sans", sans-serif; font-size: 14px; text-align: center; background-color: #f5f5f5; } .breadcrumbs { display: inline-block; margin: 150px 0; color: black; box-shadow: 0 0 2px #aaaaaa; counter-reset: flag; } .breadcrumbs a { position: relative; float: left; padding-left: 60px; padding-right: 10px; text-decoration: none; line-height: 36px; color: black; background-color: white; } .breadcrumbs a::after { content: ""; position: absolute; top: 0; right: -18px; z-index: 1; width: 36px; height: 36px; background-color: white; border-radius: 50px 0 0 0; box-shadow: 1px 1px 0 1px #dddddd; transform: rotate(-45deg) scale(0.73); } .breadcrumbs a:hover, .breadcrumbs a:hover::after, .breadcrumbs a.active, .breadcrumbs a.active::after { background-color: #f1c40f; } .breadcrumbs a::before { content: counter(flag); position: absolute; top: 8px; left: 30px; line-height: 20px; box-shadow: 0 0 2px #cccccc; counter-increment: flag; width:20px; height:20px; background-color:white; border-radius:50%; } .breadcrumbs a:first-child { padding-left:46px; } .breadcrumbs a:first-child::before { left:14px; } |
Маркер на карте
В последней серии заданий мы создадим красивый маркер на карте с использованием уже знакомых приёмов.
Для начала создадим квадратную заготовку маркера и расположим его на карте.
Чтобы создать маркер в виде «капли», нужно закруглить все углы, кроме одного. Вы делали это в прошлой серии заданий.
Конечно, нужно добавить аккуратную тень.
И напоследок маркер нужно будет повернуть заострённым углом вниз.
HTML:
1 2 3 |
<div class="map"> <div class="pin">Место на карте</div> </div> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
html, body { margin: 0; padding: 0; background-color: #f5f5f5; } .map { position: relative; width: 360px; height: 360px; margin: 50px auto; background: url("map.jpg") no-repeat 50% 50% #ffffff; border: 20px solid white; box-shadow: 0 0 3px #cccccc; } .pin { position: absolute; top: 150px; left: 250px; width: 15px; height: 15px; font-size: 0; border: 10px solid #f75850; border-radius: 50% 50% 50% 0; box-shadow: -2px 2px 2px 0 #aaaaaa; transform: rotate(-45deg); } |
Просто прикол:
HTML:
1 2 3 4 5 |
<main> <div class="shield"> <div class="shield-logo"></div> </div> </main> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
html, body { width: 570px; margin: 0; padding: 0; color: #333333; background-color: #f5f5f5; } main { position: relative; display: block; width: 300px; height: 300px; margin: 0 auto; } .shield { position: relative; top: 5%; width: 90%; height: 90%; margin: 0 auto; background-color: #ffffff; box-shadow: 0 2px 3px #cccccc; } .shield, .shield::before, .shield::after { border-radius: 50%; } .shield::before { width: 75%; height: 75%; background-color: #0039a6; } .shield::after { width: 50%; height: 50%; background-color: #d52b1e; } .shield::before, .shield::after { content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .shield-logo { position: relative; top: 50%; left: 50%; z-index: 10; width: 82px; transform: translate(-41px, -20px); } .shield-logo::before, .shield-logo::after { content: ""; position: absolute; top: 0; left: 0; width: 20px; height: 20px; border: 10px solid #ffffff; border-radius: 50% 50% 0; transform: rotate(-45deg); } .shield-logo::after { right: 0; left: auto; border-radius: 50% 50% 50% 0; transform: rotate(45deg); } |