Water Effect

About

This lightweight water/liquid effect was made using SVG filters and pure JavaScript.


Nuance

The technology is very new, and not all browsers support it.

HTML

In HTML we have to create an SVG filter.

                        <!DOCTYPE html>
<html lang="en">
<head>
    <title>SVG Filter Water Effect</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div class="block water-1">
        <div class="title">
            <h1>Cool effect, huh?</h1>
            <div class="options">
                <div class="option is-active" data-value="water-1">Image Water</div>
                <div class="option" data-value="water-2">Gradient Water</div>
                <div class="option" data-value="clouds">Clouds</div>
                <div class="option" data-value="gradient">Gradient</div>
            </div>
        </div>
    </div>

    <!-- This is the filter that is defined inside the SVG element. -->
    <svg version='1.1' xmlns='http://www.w3.org/2000/svg' style="display: none;">
        <defs>
            <filter id='wave'>
                <feturbulence basefrequency='0 0' id='turbulence' numoctaves='1' result='noise' seed='13'></feturbulence>
                <fedisplacementmap id='displacement' in2='noise' in='SourceGraphic' scale='126'></fedisplacementmap>
            </filter>
        </defs>
    </svg>
<script src="js/script.js"></script>
</body>
</html>
                    

CSS

In CSS we must set the SVG filter id to the filter property.

                        * {
    margin: 0;
    padding: 0;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}

html,
body {
    height: 100%;
}

.block {
    position: relative;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    width: 100%;
    height: 100%;
    overflow: hidden;
}

.block:before {
    content: '';
    position: absolute;
    top: -100px;
    bottom: -100px;
    left: -100px;
    right: -100px;
    background: -o-repeating-linear-gradient(102deg, #c0cdd7 0px, #c0cdd7 150px, #c7bea5 200px);
    background: repeating-linear-gradient(-12deg, #c0cdd7 0px, #c0cdd7 150px, #c7bea5 200px);

    -webkit-filter: url(#wave); /* Here we set filter property to the element */
            filter: url(#wave);
    z-index: 1;
}

.block.water-1:before {
    background: transparent;
    background-image: url(https://cdn.pixabay.com/photo/2015/07/02/10/23/water-828746_960_720.jpg);
    background-size: cover;
    background-position: center center;
}

.block.water-2:before {
    background: -o-repeating-linear-gradient(102deg, #008ec9 10%, #05419f 20%, #008ec9 30%);
    background: repeating-linear-gradient(-12deg, #008ec9 10%, #05419f 20%, #008ec9 30%);
}

.block.clouds:before {
    background: -o-repeating-linear-gradient(102deg, #E6E6E1 0%, #657C90 10%, #3778A2 30%, #E6E6E1 40%, #657C90 50%, #E6E6E1 70%);
    background: repeating-linear-gradient(-12deg, #E6E6E1 0%, #657C90 10%, #3778A2 30%, #E6E6E1 40%, #657C90 50%, #E6E6E1 70%);
}

.block.gradient:before {
    background: -o-repeating-linear-gradient(102deg, #c0cdd7 0px, #d773a0 150px, #c7bea5 200px, #008ec9 400px, #05419f 500px, #008ec9 700px, #c7bea5 750px, #d773a0 800px, #008ec9 850px, #c0cdd7 1100px);
    background: repeating-linear-gradient(-12deg, #c0cdd7 0px, #d773a0 150px, #c7bea5 200px, #008ec9 400px, #05419f 500px, #008ec9 700px, #c7bea5 750px, #d773a0 800px, #008ec9 850px, #c0cdd7 1100px);
}

.title {
    position: relative;
    z-index: 3;
    text-align: center;
    padding: 0 30px;
    font-family: Arial, sans-serif;
    color: #FFFFFF;
}

h1 {
    font-size: 3rem;
}

/* You don't need the code below, it's for options (Water Image, Water Gradient, Clouds Gradient, Gradient) */

.options {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    margin-top: 20px;
}

.options .option {
    padding: 10px 20px;
    -webkit-box-flex: 1;
    -ms-flex-positive: 1;
    flex-grow: 1;
    text-align: center;
    cursor: pointer;

    border: 2px solid transparent;
    -webkit-transition: border-color .5s;
    -o-transition: border-color .5s;
    transition: border-color .5s;
}

.options .option.is-active {
    border-color: #FFFFFF;
}

@media (max-width: 768px) {
    .options {
        -webkit-box-orient: vertical;
        -webkit-box-direction: normal;
        -ms-flex-direction: column;
        flex-direction: column;
    }
}
                    

JavaScript

To animate the SVG filter we have to change the value of the baseFrequency attribute of this filter.


The animation will be rendered recursively using requestAnimationFrame method.

                        (function () {
    let step = 0.0001,
        filter = document.querySelector("#turbulence"),
        rad = Math.PI / 180;

    function filterAnimation() {
        step += 0.25;
        x = 0.005 + 0.001 * Math.cos(step * rad);
        y = 0.01 + 0.005 * Math.sin(step * rad);

        xy = x.toString() + ' ' + y.toString();
        filter.setAttributeNS(null, 'baseFrequency', xy);
        window.requestAnimationFrame(filterAnimation);
    }

    window.requestAnimationFrame(filterAnimation);
})();

// You don't need the code below, it's to switch between options (Water Image, Water Gradient, Clouds Gradient, Gradient)

(function () {
    let block = document.querySelector('.block');
    let options = document.querySelectorAll('.option');

    options.forEach((option) => {

        option.addEventListener('click', (e) => {
            block.className = 'block ' + e.target.dataset.value;

            options.forEach((option) => { option.classList.remove('is-active'); });
            e.target.classList.add('is-active');
        });

    });
})();