【STUDIO】カスタムコードを使ったインタラクティブな表示例

STUDIO

ウェブデザインの世界では、ユーザーの目を引きつけるために革新的な方法が常に求められています。今回は、STUDIOのカスタムコード機能を使用して、ウェブサイトにインタラクティブなテキストエフェクトを追加する方法をご紹介します。このテクニックは、訪問者の注意を引き、サイトに動的な要素を加えるのに最適です。早速、どのようにしてインタラクティブなテキストを作成し、ウェブサイトに統合するかを見ていきましょう。

今回ご紹介するカスタムコードを含めた過去に作成したデザインコンポーネントは、下記のWEBサイトにまとめてあります。ぜひ、体験してみてください。

パーツ作成

カスタムコードの使用方法

まずは、STUDIOのカスタムコードの使用方法についてご紹介します。

STUDIOでのカスタムコードの具体的な操作方法は、下記のブログに記載しています。もしカスタムコードの使用方法がわからない方はこちらをご覧ください!

そもそもSTUDIOとは、ノーコードでWEBサイトを作れるツールですが、ノーコードだけで対応できる範囲には限界があります。ノーコードだけでは対応できない機能を実装したい時に、このカスタムコードの機能がとても便利です。

この機能は、利用者が直接HTML、CSS、JavaScriptを編集し、ウェブサイトやアプリのデザインをカスタマイズできる機能であるため、多少のプログラミング知識が必要になり、導入のハードルは少し高くなるかもしれません。

ご自身でSTUDIOを使いこなしてWEBサイトを作成できるが、どうしても実装したいしたいデザインがあるという方は、カスタムコードで実装する部分のみ依頼するという方法もご検討してみてください!

カスタムコード例

ここからは具体的なカスタムコードの例をいくつかご紹介します。

粒子で形成されたインタラクティブな文字②

今回ご紹介する一つ目のカスタムコードは、カラフルな小さい粒子が任意のテキストを形成し、そこにマウスポインタが近づいてきた時に、テキストが崩れるというものです

WEBサイトのタイトル画面や目を引きたい部分にこのカスタムコードを配置することで、見る人の印象に残るサイトになるのではないでしょうか。

HTML、CSS、JavaScriptはこちら
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>幻想的な粒子テキスト</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
            background: #282828;
        }

        canvas {
            position: absolute;
            top: 0;
            left: 0;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        let width = canvas.width = window.innerWidth;
        let height = canvas.height = window.innerHeight;
        let particles = [];

        const mouse = {
            x: null,
            y: null,
            radius: 150
        }

        window.addEventListener('mousemove', event => {
            mouse.x = event.x;
            mouse.y = event.y;
        });

        const textSettings = {
            text: 'ABCDE',
            fontSize: 300,
            fontFamily: 'Verdana',
            offsetX: 0,
            offsetY: 100
        };

        class Particle {
            constructor(x, y) {
                this.x = x;
                this.y = y;
                this.size = 3;
                this.baseX = this.x;
                this.baseY = this.y;
                this.density = (Math.random() * 40) + 5;
                // パステルカラーの粒子
                this.color = `hsla(${Math.random() * 360}, 100%, 75%, 0.8)`;
            }

            draw() {
                ctx.fillStyle = this.color;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.closePath();
                ctx.fill();
            }

            update() {
                let dx = mouse.x - this.x;
                let dy = mouse.y - this.y;
                let distance = Math.sqrt(dx * dx + dy * dy);
                let forceDirectionX = dx / distance;
                let forceDirectionY = dy / distance;
                let maxDistance = mouse.radius;
                let force = (maxDistance - distance) / maxDistance;
                let directionX = forceDirectionX * force * this.density;
                let directionY = forceDirectionY * force * this.density;

                if (distance < maxDistance) {
                    this.x -= directionX;
                    this.y -= directionY;
                } else {
                    if (this.x !== this.baseX) {
                        let dx = this.x - this.baseX;
                        this.x -= dx / 10;
                    }
                    if (this.y !== this.baseY) {
                        let dy = this.y - this.baseY;
                        this.y -= dy / 10;
                    }
                }
            }
        }

        function createText() {
            ctx.fillStyle = 'white';
            ctx.font = `${textSettings.fontSize}px ${textSettings.fontFamily}`;
            const textWidth = ctx.measureText(textSettings.text).width;
            const x = (width / 2) - (textWidth / 2) + textSettings.offsetX;
            const y = (height / 2) + textSettings.offsetY;
            ctx.fillText(textSettings.text, x, y);

            return ctx.getImageData(0, 0, width, height);
        }

        function init() {
            particles = [];
            const textCoordinates = createText();

            const step = 10;

            for (let y = 0; y < textCoordinates.height; y += step) {
                for (let x = 0; x < textCoordinates.width; x += step) {
                    if (textCoordinates.data[(y * 4 * textCoordinates.width) + (x * 4) + 3] > 128) {
                        particles.push(new Particle(x, y));
                    }
                }
            }
        }

        function animate() {
            ctx.clearRect(0, 0, width, height);

            for (let i = 0; i < particles.length; i++) {
                particles[i].draw();
                particles[i].update();
            }

            requestAnimationFrame(animate);
        }

        window.addEventListener('resize', () => {
            width = canvas.width = window.innerWidth;
            height = canvas.height = window.innerHeight;
            init();
        });

        init();
        animate();
    </script>
</body>
</html>

粒子で形成されたインタラクティブな文字④

二つ目のカスタムコードは、先ほどのものと似ていますが、粒子がテキストを形どり、一定間隔で切り替わるというものです。今回の作成例では、「ABCDE」と「FGHIJ」というテキストをループさせています。

こちらもWEBサイトのトップページで表示する際に、ユーザーを引き込むインタラクティブなタイトルテキストとしてもおすすめです。

HTML、CSS、JavaScriptはこちら
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>粒子で形成されるテキスト</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
            background: transparent;
        }
        canvas {
            position: absolute;
            top: 0;
            left: 0;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        let width = canvas.width = window.innerWidth;
        let height = canvas.height = window.innerHeight;
        let particles = [];

        const mouse = {
            x: null,
            y: null,
            radius: 150
        };

        window.addEventListener('mousemove', event => {
            mouse.x = event.x;
            mouse.y = event.y;
        });

        const textSettings = {
            texts: ['ABCDE', 'FGHIJ'], // テキストの配列
            currentTextIndex: 0, // 現在のテキストのインデックス
            fontSize: 300,
            fontFamily: 'Verdana',
            offsetX: 0,
            offsetY: 0
        };

        // 切り替わり速度(小さいほど速い)
        const transitionSpeed = 10;

        class Particle {
            constructor(x, y) {
                this.x = x;
                this.y = y;
                this.size = 3;
                this.baseX = x;
                this.baseY = y;
                this.density = (Math.random() * 40) + 5;
                this.targetX = x;
                this.targetY = y;
                this.visible = true;
            }

            draw() {
                if (!this.visible) return;
                ctx.fillStyle = 'white';
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.closePath();
                ctx.fill();
            }

            update() {
                let dx = mouse.x - this.x;
                let dy = mouse.y - this.y;
                let distance = Math.sqrt(dx * dx + dy * dy);
                let forceDirectionX = dx / distance;
                let forceDirectionY = dy / distance;
                let maxDistance = mouse.radius;
                let force = (maxDistance - distance) / maxDistance;
                let directionX = forceDirectionX * force * this.density;
                let directionY = forceDirectionY * force * this.density;

                if (distance < maxDistance) {
                    this.x -= directionX;
                    this.y -= directionY;
                } else {
                    if (this.x !== this.targetX) {
                        dx = this.x - this.targetX;
                        this.x -= dx / transitionSpeed;
                    } else if (!this.visible) {
                        this.x -= dx / transitionSpeed; // 目標位置に到達したら徐々に移動
                    }
                    if (this.y !== this.targetY) {
                        dy = this.y - this.targetY;
                        this.y -= dy / transitionSpeed;
                    } else if (!this.visible) {
                        this.y -= dy / transitionSpeed; // 目標位置に到達したら徐々に移動
                    }
                }
            }
        }

        function createText(text) {
            ctx.fillStyle = 'white';
            ctx.font = `${textSettings.fontSize}px ${textSettings.fontFamily}`;
            const textWidth = ctx.measureText(text).width;
            const x = (width / 2) - (textWidth / 2) + textSettings.offsetX;
            const y = (height / 2) + (textSettings.fontSize / 2) + textSettings.offsetY;
            ctx.fillText(text, x, y);
            return ctx.getImageData(0, 0, width, height);
        }

        function init() {
            particles = [];
            ctx.clearRect(0, 0, width, height);
            const textCoordinates = createText(textSettings.texts[textSettings.currentTextIndex]);

            const step = 5;
            for (let y = 0; y < textCoordinates.height; y += step) {
                for (let x = 0; x < textCoordinates.width; x += step) {
                    if (textCoordinates.data[(y * 4 * textCoordinates.width) + (x * 4) + 3] > 128) {
                        particles.push(new Particle(x, y));
                    }
                }
            }
        }

        function animate() {
            ctx.clearRect(0, 0, width, height);
            for (let i = 0; i < particles.length; i++) {
                particles[i].draw();
                particles[i].update();
            }
            requestAnimationFrame(animate);
        }

        function updateText(newText) {
            ctx.clearRect(0, 0, width, height);
            const textCoordinates = createText(newText);

            const step = 5;
            let particleIndex = 0;

            for (let y = 0; y < textCoordinates.height; y += step) {
                for (let x = 0; x < textCoordinates.width; x += step) {
                    if (textCoordinates.data[(y * 4 * textCoordinates.width) + (x * 4) + 3] > 128) {
                        if (particleIndex < particles.length) {
                            particles[particleIndex].targetX = x;
                            particles[particleIndex].targetY = y;
                            particles[particleIndex].visible = true;
                            particleIndex++;
                        } else {
                            particles.push(new Particle(x, y)); // 新しい粒子を追加
                        }
                    }
                }
            }

            // 余分な粒子を非表示にする
            for (let i = particleIndex; i < particles.length; i++) {
                particles[i].visible = false;
            }
        }

        window.addEventListener('resize', () => {
            width = canvas.width = window.innerWidth;
            height = canvas.height = window.innerHeight;
            init();
        });

        init();
        animate();

        // テキストを定期的に切り替える
        setInterval(() => {
            textSettings.currentTextIndex = (textSettings.currentTextIndex + 1) % textSettings.texts.length;
            updateText(textSettings.texts[textSettings.currentTextIndex]);
        }, 5000); // 5秒ごとにテキストを切り替える
    </script>
</body>
</html>

ゆらゆらと上る青白い光のアニメーション

三つ目にご紹介するカスタムコードは、青白い光が下から上に移動していくようなアニメーションになります。下記の例のように背景の色を青系にすると水中のようにも見えます。

WEBサイト全体の動きのある背景としても使えそうです。

HTML、CSS、JavaScriptはこちら
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ゆらゆらと上る青白い光のアニメーション</title>
<style>
@keyframes floatUp {
  0% {
    transform: translateY(0); /* 画面の下から開始 */
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
  100% {
    transform: translateY(-100vh); /* 画面の上へ移動 */
    opacity: 0;
  }
}

body {
  margin: 0;
  overflow: hidden;
  background: transparent; /* 背景を透明にする */
}

.light {
  position: absolute;
  background-color: rgba(173, 216, 230, 0.7); /* 青白い色固定 */
  border-radius: 50%; /* 円形にする */
  box-shadow: 0 0 10px 2px rgba(173, 216, 230, 0.9); /* 光にぼかしを追加 */
  animation: floatUp 5s infinite ease-in; /* アニメーションを適用 */
}

/* 光ごとにアニメーションを微妙に変える */
.light:nth-child(2n) {
  animation-duration: 6s; /* アニメーションの時間 */
}

.light:nth-child(3n) {
  animation-duration: 7s;
}

.light:nth-child(4n) {
  animation-duration: 8s;
}
</style>
</head>
<body>

<script>
// 光の要素を動的に作成
for (let i = 0; i < 50; i++) {
  let size = Math.random() * 5 + 3; // 光の大きさをランダムに設定 (3pxから8px)
  let light = document.createElement('div');
  light.className = 'light';
  light.style.left = `${Math.random() * 100}vw`; // 光の初期位置をランダムに設定
  light.style.bottom = `${-100 * Math.random()}px`; // 光の初期位置をランダムに設定
  light.style.animationDelay = `${Math.random() * 5}s`; // アニメーション開始の遅延をランダムに設定
  light.style.width = `${size}px`; // 光の幅をランダムに設定
  light.style.height = `${size}px`; // 光の高さをランダムに設定
  document.body.appendChild(light);
}
</script>

</body>
</html>

動く背景グラデーション

四つ目にご紹介するカスタムコードは、マウスポインタの位置によって、背景のグラデーションが少し動く機能と、白いぼんやりとした光がマウスポインタを追従するというものの組み合わせになります。

やんわりとした優しい雰囲気のWEBサイトやポートフォリオを作りたいという場合、グラデーションやぼんやりとした光を活用することで、理想の雰囲気になりそうですね。

HTML、CSS、JavaScriptはこちら
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>動く背景グラデーション</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
        }

        #background {
            position: absolute;
            width: 100%;
            height: 100%;
            background: linear-gradient(45deg, #6ab1d7, #33d6a6);
            transition: background 0.5s ease;
        }

        .light-effect {
            position: absolute;
            border-radius: 50%;
            pointer-events: none;
            mix-blend-mode: overlay;
            background: radial-gradient(circle, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0) 70%);
            transition: width 0.2s ease, height 0.2s ease, top 0.2s ease, left 0.2s ease;
            z-index: 1;
        }
    </style>
</head>
<body>
    <div id="background"></div>
    <script>
        document.addEventListener('mousemove', (event) => {
            const mouseX = event.clientX / window.innerWidth;
            const mouseY = event.clientY / window.innerHeight;

            const background = document.getElementById('background');
            background.style.background = `linear-gradient(${mouseX * 360}deg, #6ab1d7, #33d6a6)`;

            const lightEffect = document.querySelector('.light-effect');
            if (!lightEffect) {
                const effect = document.createElement('div');
                effect.className = 'light-effect';
                effect.style.width = '200px';
                effect.style.height = '200px';
                effect.style.position = 'absolute';
                document.body.appendChild(effect);
            } else {
                lightEffect.style.top = `${event.clientY - 100}px`;
                lightEffect.style.left = `${event.clientX - 100}px`;
            }
        });
    </script>
</body>
</html>

ランダムに動き回る粒子と線アニメーション

五つ目にご紹介するカスタムコードは、ランダムに動き回る粒子と線によるアニメーションです。粒子同士が一定の距離にいる間だけ粒子と粒子を結ぶ線が表示されるような仕組みになっており、大小さまざまなサイズの粒子が動き回るので、とてもインパクトのある背景画像になるかと思います。

HTML、CSS、JavaScriptはこちら
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>洗練されたキャンバス背景</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
            background: #000;
        }

        canvas {
            position: absolute;
            top: 0;
            left: 0;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        let width = canvas.width = window.innerWidth;
        let height = canvas.height = window.innerHeight;
        const particles = [];
        const particleCount = 100;
        let mouseX = width / 2;
        let mouseY = height / 2;

        window.addEventListener('resize', () => {
            width = canvas.width = window.innerWidth;
            height = canvas.height = window.innerHeight;
        });

        class Particle {
            constructor() {
                this.x = Math.random() * width;
                this.y = Math.random() * height;
                this.size = Math.random() * 5 + 1;
                this.speedX = Math.random() * 3 - 1.5;
                this.speedY = Math.random() * 3 - 1.5;
            }

            update() {
                this.x += this.speedX;
                this.y += this.speedY;

                if (this.size > 0.2) this.size -= 0.1;
            }

            draw() {
                ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fill();
            }
        }

        function init() {
            for (let i = 0; i < particleCount; i++) {
                particles.push(new Particle());
            }
        }

        function handleParticles() {
            for (let i = 0; i < particles.length; i++) {
                particles[i].update();
                particles[i].draw();

                for (let j = i; j < particles.length; j++) {
                    const dx = particles[i].x - particles[j].x;
                    const dy = particles[i].y - particles[j].y;
                    const distance = Math.sqrt(dx * dx + dy * dy);

                    if (distance < 300) {
                        ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
                        ctx.lineWidth = 0.2;
                        ctx.beginPath();
                        ctx.moveTo(particles[i].x, particles[i].y);
                        ctx.lineTo(particles[j].x, particles[j].y);
                        ctx.stroke();
                    }
                }

                if (particles[i].size <= 0.2) {
                    particles.splice(i, 1);
                    i--;
                    particles.push(new Particle());
                }
            }
        }

        function animate() {
            ctx.clearRect(0, 0, width, height);
            handleParticles();
            requestAnimationFrame(animate);
        }

        init();
        animate();

        document.addEventListener('mousemove', (event) => {
            mouseX = event.clientX;
            mouseY = event.clientY;
        });
    </script>
</body>
</html>

動くカラフルな粒子と線(マウスポインタが近寄ると集まる)

六つ目にご紹介するカスタムコードは、カラフルな粒子と線がランダムに動き回るものになります。さらに、マウスポインタが粒子に近づくと、周辺の粒子がマウスポインタの位置に集まってきます。

PCでWEBサイトを閲覧する際、こういったインタラクティブな要素があると、なんとなく注目してしまったり、それらの要素を覚えていたりすることはないでしょうか?

HTML、CSS、JavaScriptはこちら
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>洗練されたインタラクティブなキャンバス背景</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
            background: #282828;
        }

        canvas {
            position: absolute;
            top: 0;
            left: 0;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        let width = canvas.width = window.innerWidth;
        let height = canvas.height = window.innerHeight;
        const particles = [];
        const particleCount = 100;
        let mouseX = -1;
        let mouseY = -1;

        window.addEventListener('resize', () => {
            width = canvas.width = window.innerWidth;
            height = canvas.height = window.innerHeight;
        });

        class Particle {
            constructor() {
                this.x = Math.random() * width;
                this.y = Math.random() * height;
                this.size = Math.random() * 5 + 1;
                this.speedX = Math.random() * 2 - 1;
                this.speedY = Math.random() * 2 - 1;
                this.color = `hsla(${Math.random() * 360}, 50%, 50%, 0.8)`; // 色彩をHSLAでランダムに
            }

            update() {
                // マウスの位置に基づいて粒子を移動
                let dx = mouseX - this.x;
                let dy = mouseY - this.y;
                let distance = Math.sqrt(dx * dx + dy * dy);
                let forceDirectionX = dx / distance;
                let forceDirectionY = dy / distance;

                let maxDistance = 100;
                let force = (maxDistance - distance) / maxDistance;
                let directionX = forceDirectionX * force * 2;
                let directionY = forceDirectionY * force * 2;

                if (distance < maxDistance) {
                    this.x += directionX;
                    this.y += directionY;
                } else {
                    this.x += this.speedX;
                    this.y += this.speedY;
                }

                // 画面の端に達したら反対方向へ
                if (this.x < 0 || this.x > width) this.speedX = -this.speedX;
                if (this.y < 0 || this.y > height) this.speedY = -this.speedY;
            }

            draw() {
                ctx.fillStyle = this.color;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fill();
            }
        }

        function init() {
            for (let i = 0; i < particleCount; i++) {
                particles.push(new Particle());
            }
        }

        function handleParticles() {
            for (let i = 0; i < particles.length; i++) {
                particles[i].update();
                particles[i].draw();

                for (let j = i + 1; j < particles.length; j++) {
                    const dx = particles[i].x - particles[j].x;
                    const dy = particles[i].y - particles[j].y;
                    const distance = Math.sqrt(dx * dx + dy * dy);

                    if (distance < 100) {
                        ctx.strokeStyle = particles[i].color; // 同じ色彩を使用
                        ctx.lineWidth = 0.2;
                        ctx.beginPath();
                        ctx.moveTo(particles[i].x, particles[i].y);
                        ctx.lineTo(particles[j].x, particles[j].y);
                        ctx.stroke();
                    }
                }
            }
        }

        function animate() {
            ctx.fillStyle = 'rgba(0, 0, 0, 0.02)';
            ctx.fillRect(0, 0, width, height);
            handleParticles();
            requestAnimationFrame(animate);
        }

        init();
        animate();

        document.addEventListener('mousemove', (event) => {
            mouseX = event.clientX;
            mouseY = event.clientY;
        });

        document.addEventListener('mouseout', () => {
            mouseX = -1;
            mouseY = -1;
        });
    </script>
</body>
</html>

【宣伝】ココナラで出品中のサービス紹介

最後に、私がココナラで提供しているサービスについてご紹介します。STUDIOを使ったウェブデザインの作成を行うサービスを出品しています。

今回ご紹介したようなカスタムコードを始め、さまざまなデザインをご提案し、オリジナリティあふれる魅力的なWEBサイトを作成させていただきます。

もし、この記事を読んで少しでも興味を持っていただけたら、ぜひ私のページをチェックしてみてください。

ココナラ[coconala]
ココナラは、あなたのできることを500円から出品できて、「誰かの役に立ちたい」「好きを仕事にしたい」「自分の力を試したい」を実現するサイトです。

カスタムコードを活用した事例だけではないですが、以前作成したWEBサイトの参考例です。
ご興味があればご覧ください。
https://simple-template1.studio.site
https://simple-template2.studio.site
https://webdesign-parts.studio.site/13

まとめ

今回は、STUDIOを使用してウェブサイト上でインタラクティブなテキストを作成する方法についてご紹介しました。この方法を利用すれば、テキストに生命を吹き込み、ユーザーの興味を引きつけることができます。カスタムコード機能を使えば、テンプレートに縛られることなく、創造性を発揮して独自のデザインを実現できます。私の出品しているココナラのサービスでは、このようなカスタムコードを用いたWEBサイト、ポートフォリオサイトの作成も承ります!ぜひご検討下さい。

コメント