Изменение цвета фона страницы сайта и его элементов
Хочу реализовать такую анимацию.
Снизу страницы поднимается вода, которая меняет цвет фона страницы и цвет ее элементов. По мере того как вода заполняет страницу, она как бы окрашивает ее элементы (цвет шрифта меняется на другой). Вопрос абстрактный т.к. не могу найти в сети примеры.
Собственно хочу узнать в какую сторону копать. Мои поиски пока не увенчались успехом. Предполагаю, что это работа с svg масками. Буду благодарен ссылкам на какие-то примеры и документацию.
Ответы (2 шт):
Могу предложить пример заполнения текста волной с изменением цвета букв.
Этот пример можно использовать, как для шапки сайта, так и для оформления визуальных эффектов веб страниц.
Можно подобрать на ваш вкус любую картинку для фона, текст, изменить цвет букв с помощью градиента.
Для реализации волны используется path svg
Анимация волны достигается перемещением path
<animateTransform attributeName="transform" type="translate" begin="0s" dur="1.5s" from="0,0" to="40,0" repeatCount="indefinite" />
- Паттерн c анимированной волной применяется к тексту
Смотрите комментарии в коде, надеюсь они помогут понять основные моменты
body,html{margin:0;padding:0;height:100%;}
body{
background:url('https://i.stack.imgur.com/Csgbl.jpg');
background-size:cover;
font-family: 'Cabin Condensed', sans-serif;
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
}
svg{font-weight:bold;max-width:600px;height:auto;}
<svg viewbox="0 0 100 20">
<defs>
<linearGradient id="gradient" x1="0" x2="0" y1="0" y2="1">
<stop offset="5%" stop-color="#326384"/>
<stop offset="95%" stop-color="#123752"/>
</linearGradient>
<pattern id="wave" x="0" y="0" width="120" height="20" patternUnits="userSpaceOnUse">
<path id="wavePath" d="M-40 9 Q-30 7 -20 9 T0 9 T20 9 T40 9 T60 9 T80 9 T100 9 T120 9 V20 H-40z" fill="url(#gradient)">
<!-- Анимация волны достигается перемещением path -->
<animateTransform attributeName="transform" type="translate" begin="0s" dur="1.5s" from="0,0" to="40,0" repeatCount="indefinite" />
</path>
</pattern>
</defs>
<!-- Паттерн c анимированной волной применяется к тексту -->
<text text-anchor="middle" x="50" y="15" font-size="17" fill="url(#wave)" fill-opacity="0.9">MY SITE</text>
<text text-anchor="middle" x="50" y="15" font-size="17" fill="url(#gradient)" fill-opacity="0.3">MY SITE</text>
</svg>
Второй пример, с другой фоновой картинкой, цветами градиента, более удлиненным текстом.
То есть, я хочу сказать, что вы легко сможете подобрать цветовую гамму по своему вкусу.
body,html{margin:0;padding:0;height:100%;}
body{
background:url('https://i.stack.imgur.com/HnYTh.jpg');
background-size:cover;
font-family: 'Cabin Condensed', sans-serif;
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
}
svg{font-weight:bold;max-width:600px;height:auto;}
<svg viewbox="0 0 100 20">
<defs>
<linearGradient id="gradient" x1="0" x2="0" y1="0" y2="1">
<stop offset="5%" stop-color="#151515"/>
<stop offset="95%" stop-color="#white"/>
</linearGradient>
<pattern id="wave" x="0" y="0" width="130" height="20" patternUnits="userSpaceOnUse">
<path id="wavePath" d="M-40 9 Q-30 7 -20 9 T0 9 T20 9 T40 9 T60 9 T80 9 T100 9 T120 9 V20 H-40z" fill="url(#gradient)">
<animateTransform attributeName="transform" type="translate" begin="0s" dur="1.5s" from="0,0" to="40,0" repeatCount="indefinite" />
</path>
</pattern>
</defs>
<text text-anchor="middle" x="52" y="15" font-size="17" fill="url(#wave)" fill-opacity="0.8">MY SITE</text>
<text text-anchor="middle" x="52" y="15" font-size="17" fill="url(#gradient)" fill-opacity="0.2">MY SITE</text>
</svg>
Добился необходимого эффекта при помощи clip-path. Кому интересно вот ссылка. Добавил заполнение по клику на кнопку. Однако не уверен пока что это именно правильный подход.
const buttonFirst = document.querySelector('.button-first');
const buttonSecond = document.querySelector('.button-second');
const containerSecond = document.querySelector('.second');
buttonFirst.addEventListener('click', () => {
containerSecond.classList.remove('draining');
containerSecond.classList.toggle('fill-water');
setTimeout(() => {
containerSecond.classList.add('filled');
}, 2500)
});
buttonSecond.addEventListener('click', () => {
containerSecond.classList.toggle('fill-water');
containerSecond.classList.toggle('draining');
setTimeout(() => {
containerSecond.classList.remove('filled');
}, 2500)
});
html, body { height: 100%; }
body {
display: flex;
justify-content: center;
align-items: center;
}
.first, .second {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
}
.button {
padding: 20px;
cursor: pointer;
font-size: 72px;
border: none;
outline: none;
}
.button-first {
color: white;
background: #007ba7;
}
.button-second {
color: #007ba7;
background: white;
}
.second {
width: 100%;
height: 280px;
background: #007ba7;
clip-path: polygon(0% 95%, 100% 95%, 100% 100%, 0% 100%);
}
.fill-water {
animation: water 3s linear 1;
}
.filled {
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
}
.draining {
animation: draining 3s linear 1;
}
@keyframes water {
from {
clip-path: polygon(0% 95%, 100% 95%, 100% 100%, 0% 100%);
}
to {
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
}
}
@keyframes draining {
from {
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
}
to {
clip-path: polygon(0% 95%, 100% 95%, 100% 100%, 0% 100%);
}
}
<div class="first">
<button class="button button-first">Push me</button>
</div>
<div class="second">
<button class="button button-second">Push me</button>
</div>