Сегодня будет простой проект в сфере фронтенда. Сделаем три вещи, которые раньше не делали:
- Наложим два слова друг на друга так, чтобы они хорошо читались.
- Через стили добавим в документ новый текст.
- Подключим специальный сервис, который будет давать нам красивые фоны для страницы.
В итоге получится что-то вроде красивой шапки сайта:
Создаём страницу
Для проекта нам понадобится самая простая HTML-страница, даже без JavaScript. Единственное, что на ней будет, — подключённый файл со стилями и пара блоков для текста. При этом если присмотреться к коду, то можно увидеть, что самого текста на странице нет. Все слова — это атрибут тега, а не его содержимое. С помощью хитрой команды мы в стилях возьмём текст оттуда и выведем его в нужное место на странице.
Если мы откроем эту страницу в браузере, то ничего не увидим, потому что между тегами нет никакого текста — а раз нет текста, то и браузер ничего не выведет и покажет белое окно.
<!DOCTYPE html>
<html lang="ru" >
<head>
<meta charset="UTF-8">
<title>Играем со шрифтами и фоном</title>
<!-- добавляем файл со стилями -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- пример текста с заливкой и прозрачными границами -->
<div class="wrapper">
<span data-text="Журнал"></span>
<span data-text="Код"></span>
</div>
<!-- и наоборот — текст без заливки, но с цветным контуром -->
<div class="wrapper invert">
<span data-text="Журнал"></span>
<span data-text="Код"></span>
</div>
</body>
</html>
Подключаем случайный фон
Особенность проекта в том, что при каждом обновлении страницы у неё случайным образом меняется фон. За это отвечает сервис Picsum.photos — когда он получает специальный запрос, то в ответ отдаёт случайную бесплатную картинку из фотостока Unsplash.
Самый простой способ получить картинку — указать в адресе её ширину и высоту, например так:
https://picsum.photos/1280/800
Когда сервер увидит такой адрес в запросе, он поймёт, что нам нужно отдать картинку 1280 пикселей по ширине и 800 по высоте. Сервер возьмёт из Unsplash случайное фото, сделает его нужного размера и отправит нам. И так будет каждый раз, когда мы будем обновлять страницу.
Добавим эту магию в файл со стилями и сразу зададим общие настройки для всей страницы:
/* Общие настройки для всей страниц */
body {
/* делаем высоту страницы на весь экран */
height: 100vh;
/* то, что не влезло в границы — скрываем */
overflow: hidden;
/* подключаем случайный фон и добавляем затемнение по кругу */
background: radial-gradient(farthest-corner, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.8)), url(https://picsum.photos/1280/800) center/cover;
/* выравниваем всё по центру */
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
/* убираем отступы */
margin: 0;
}
Сохраняем это в файле style.css, обновляем страницу и видим, что у нас появился новый фон со стильным затемнением. Тень нужна для того, чтобы наш текст читался на любом фоне — если он будет светлым, то тень сделает его темнее.
Выводим слова на экран
Сейчас наш текст хранится только в атрибутах тега span, и нам нужно его как-то оттуда извлечь и вывести на экран. Для этого в современном CSS используют команду content: attr(data-text)
, которая работает так:
- Она берёт название свойства тега из скобок и ищет его среди HTML-кода. Как только находит — возвращает значение этого свойства. В нашем случае она будет искать свойство data-text.
- Как только значение найдено, оно в виде текста возвращается в CSS, и к нему сразу применяются все стили, написанные в этом блоке.
- Этот текст выводится на экран в том месте, где по логике HTML-страницы применяется этот стиль.
Ещё мы будем использовать псевдоэлементы ::before и ::after. Они называются псевдоэлементами потому, что ведут себя, с одной стороны, как настоящие элементы на странице, а с другой — они существуют только вместе со своим родительским элементом.
Псевдоэлемент ::before создаётся и выполняется до того, как обработается родительский элемент, а ::after— сразу после родительского. Это нам пригодится для вывода и оформления текста — так мы сможем создавать обводку слов как бы в отдельном виртуальном слое и при этом управлять им как настоящим слоем.
/* общий класс для текста */
.wrapper {
/* задаём размеры текста, высоту и ширину */
font-size: 17vmin;
height: 2em;
width: 100%;
/* размещаем текст по центру блока */
display: flex;
align-items: center;
justify-content: center;
/* добавляем прозрачность для всех элементов на странице */
mix-blend-mode: screen;
}
/* стиль для тега span, который будет лежать внутри стиля wrapper */
.wrapper span {
/* цвет первого слова текста */
--color: #ffba11;
/* устанавливаем вид шрифта, его начертание и жирность */
font-family: Impact, "Anton", Haettenschweiler, "Arial Narrow Bold", sans-serif;
font-weight: 700;
font-style: italic;
/* создаём новый блок, в котором будет текст */
display: block;
/* включаем абслютное позиционирование элементов */
position: absolute;
/* используем цвет из переменной */
color: var(--color);
}
/* общие настройки псевдоклассов для тега span */
.wrapper span::before, .wrapper span::after {
/* создаём в стиле новый текст */
content: attr(data-text);
/* делаем для него новый блок */
display: block;
/* включаем для него относительное позиционирование */
position: relative;
}
/* этот псевдокласс создаёт прозрачную обводку для каждого слова */
.wrapper span::before {
position: absolute;
/* добавляем прозрачный контур к этому слову */
-webkit-text-stroke: 0.1em black;
}
Отделяем слова друг от друга
Видно, что на странице появился текст с прозрачной обводкой, но все слова одного цвета и закрывают друг друга. Нам нужно их разнести в стороны, чтобы было удобно читать, а также поменять цвет второго слова. Используем для этого CSS-свойства :first-child и :last-child — они отвечают за работу с первым и последним элементом, которые относятся к одному тегу.
Так как слова у нас хранятся в свойстве тега span, то и применять эти свойства будем к нему:
/* обрабатываем первое слово */
.wrapper span:first-child {
/* сдвигаем его чуть выше и левее, чтобы он оказался не по центру */
transform: translate(-0.255em, -0.25em);
}
/* обрабатываем второе слово */
.wrapper span:last-child {
/* цвет второго слова */
--color: #b6acff;
/* сдвигаем второе слово вправо и вниз */
transform: translate(0.255em, 0.25em);
}
Добавляем второй способ оформления
У нас получилось два одинаковых оформления, потому что мы до сих пор не прописали стиль для класса .wrapper.invert
, который мы использовали на нашей странице.
Так как у нас в описании стиля для каждого блока стоит mix-blend-mode: screen
, то это значит, что прозрачность работает так:
Чем темнее цвет, тем он прозрачнее. Белый полностью непрозрачный, а чёрный — прозрачный.
Это значит, что нам достаточно сделать второй блок слов чёрного цвета, чтобы они стали полностью прозрачными. А чтобы можно было их прочитать — добавим к ним цветную обводку:
/* делаем прозрачными слова */
.wrapper.invert span {
/* используем для этого чёрный цвет */
color: black;
}
/* с помощью псевдокласса делаем цветную обводку для каждого слова */
.wrapper.invert span::before {
-webkit-text-stroke: 0.1em var(--color);
}
Посмотреть результат на странице проекта.
<!DOCTYPE html>
<html lang="ru" >
<head>
<meta charset="UTF-8">
<title>Играем со шрифтами и фоном</title>
<!-- добавляем файл со стилями -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- пример текста с заливкой и прозрачными границами -->
<div class="wrapper">
<span data-text="Журнал"></span>
<span data-text="Код"></span>
</div>
<!-- и наоборот — текст без заливки, но с цветным контуром -->
<div class="wrapper invert">
<span data-text="Журнал"></span>
<span data-text="Код"></span>
</div>
</body>
</html>
/* Общие настройки для всей страниц */
body {
/* делаем высоту страницы на весь экран */
height: 100vh;
/* то, что не влезло в границы — скрываем */
overflow: hidden;
/* подключаем случайный фон и добавляем затемнение по кругу */
background: radial-gradient(farthest-corner, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.8)), url(https://picsum.photos/1280/800) center/cover;
/* выравниваем всё по центру */
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
/* убираем отступы */
margin: 0;
}
/* общий класс для текста */
.wrapper {
/* задаём размеры текста, высоту и ширину */
font-size: 17vmin;
height: 2em;
width: 100%;
/* размещаем текст по центру блока */
display: flex;
align-items: center;
justify-content: center;
/* добавляем прозрачность для всех элементов на странице */
mix-blend-mode: screen;
}
/* стиль для тега span, который будет лежать внутри стиля wrapper */
.wrapper span {
/* цвет первого слова текста */
--color: #ffba11;
/* устанавливаем вид шрифта, его начертание и жирность */
font-family: Impact, "Anton", Haettenschweiler, "Arial Narrow Bold", sans-serif;
font-weight: 700;
font-style: italic;
/* создаём новый блок, в котором будет текст */
display: block;
/* включаем абсолютное позиционирование элементов */
position: absolute;
/* используем цвет из переменной */
color: var(--color);
}
/* общие настройки псевдоклассов для тега span */
.wrapper span::before, .wrapper span::after {
/* создаём в стиле новый текст */
content: attr(data-text);
/* делаем для него новый блок */
display: block;
/* включаем для него относительное позиционирование */
position: relative;
}
/* этот псевдокласс создаёт прозрачную обводку для каждого слова */
.wrapper span::before {
position: absolute;
/* добавляем прозрачный контур к этому слову */
-webkit-text-stroke: 0.1em black;
}
/* обрабатываем первое слово */
.wrapper span:first-child {
/* сдвигаем его чуть выше и левее, чтобы он оказался не по центру */
transform: translate(-0.255em, -0.25em);
}
/* обрабатываем второе слово */
.wrapper span:last-child {
/* цвет второго слова */
--color: #b6acff;
/* сдвигаем второе слово вправо и вниз */
transform: translate(0.255em, 0.25em);
}
/* делаем прозрачными слова */
.wrapper.invert span {
/* используем для этого чёрный цвет */
color: black;
}
/* с помощью псевдокласса делаем цветную обводку для каждого слова */
.wrapper.invert span::before {
-webkit-text-stroke: 0.1em var(--color);
}