【SVGで簡単に解決!】円弧の作成方法|アニメーションも解説

りょーすけ
りょーすけ

デザインデータに円の一部分が欠けた要素(円弧)が存在している…
これはどうやって実装すればいいのだろうか?

画像対応でも問題ありませんが、アニメーションも同時に作動させる要件だった場合はどうでしょうか?

HTML、CSSで表現する必要がありそうです。
そこで画像を使わずこのデザインを再現したいと思います。

お手本

早速ですが、お手本をご覧ください。

円が一部欠けた=円弧 が完成していますね。

ソースコードを見るとかなりシンプルになっているのが分かると思います。

See the Pen Untitled by りょーすけ (@s_ryosuke_1242) on CodePen.

HTMLの解説

円弧に関する記述、<svg class=”gradient-circle-container”> ~ <svg>

文章エリアの<div class=”message__content”> ~ </div>

に大きく分けて考えるとわかりやすいと思います。

<p class="intro">スクロールしてください<br>↓↓↓</p>
<div class="container">
  <div class="message">
    <!-- 円弧 -->
    <svg class="gradient-circle-container" width="500" height="500" viewBox="0 0 500 500">
      <defs>
        <!-- グラデーションの始点(x1,y1) 終点(x2,y2) -->
        <linearGradient id="linear-gradient" x1="0" y1="0.5" x2="1"  y2="0.5">
          <!-- 始点の色 -->
          <stop offset="0" stop-color="#FD9BB8"></stop>
          <!-- 中間の色 -->
          <stop offset="0.5" stop-color="#CF8BF3"></stop>
          <!-- 終点の色 -->
          <stop offset="1" stop-color="#A770EF"></stop>
        </linearGradient>
      </defs>
      <circle class="gradient-stroke-circle" cx="250" cy="250" r="225" stroke="url(#linear-gradient)"></circle>
    </svg>
    <!-- 文章エリア -->
    <div class="message__content">
        <h2 class="message__title">TITLE</h2>
        <p class="message__text">
            Lorem ipsum dolor sit amet,<br>
            consectetur adipiscing elit,<br>
            sed do eiusmod tempor incididunt<br>
            ut labore et dolore magna aliqua
        </p>
    </div>
  </div>
</div>

SVGを使用して円弧を作成するのが鍵となっています。

以下、SVGに関するタグや属性について説明します

<svg>のviewBoxについて

<svg>のviewBoxに関しては以下のサイトがわかりやすいです。数値を変更して様子を確かめることができます。

SVG viewBox 確認サンプル

<defs>について

<defs> これは「definitions」の略で見た目の定義をすることができます。

主にグラデーションやマスク、クリップパスなどの定義をします。

<linearGradient>について

<linearGradient id=”linear-gradient” x1=”0″ y1=”0.5″ x2=”1″ y2=”0.5″>

・idはこのあと定義された見た目を利用するために付与しておく必要があります

・x1,y1,x2,y2はそれぞれ2次元座標のことを示しています。
グラデーションの始点と終点をこの座標で指定します。
難しいと思うので以下の図をご覧ください

数字を変更してグラデーションがどのように変わるのかを観察すると使い方が分かると思います。

<circle>について

これも図で説明します。

<cricle> これはcxとcyで円の中心座標をrは半径を示しています。

stroke属性は見た目を先程<defs>で定義したグラデーションを適用しています。

半径の長さが250ではなく225になっているのは、線の太さ50を考慮しているためです

225(半径) = 250(ビューボックスの半分の大きさ) – 25(線の半分の太さ)

なぜ線の半分の太さを引き算しているか

線は中心から太くなっていくからです。

よって線の半分を引いてあげる必要があります。

CSSの解説

CSSに関しては大事なところを選択して説明します。

*{
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}
.intro{
  font-size:40px;
  text-align:center;
}
.container{
    width: 100%;
    min-height: 100vh;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* ===============================================
# message
=============================================== */
.message{
    width: 100%;
    height: fit-content;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
}
.message__title{
    font-size: 50px;
    text-align: center;
    font-family: 'Signika Negative';
}
.message__text{
    font-size: 18px;
    text-align: center;
    font-family: 'Signika Negative';
    margin-top: 24px;
}
/* ===============================================
# circle
=============================================== */
.gradient-circle-container{
    max-width: 540px;
    width: 100%;
    height: auto;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
    padding: 0 20px;
    z-index: -1;/*テキストを選択できるように */
}
.gradient-stroke-circle {
    fill: none;/* 塗りつぶしをなしにする */
    stroke-width: 50;/* 円の線の太さ50 */
    stroke-dasharray: 1060 1413;/* 円の線のスタイルを指定。ここでは、線を75%(1060)と円周を(1413)に設定 */
    stroke-linecap: round;/* 円の線端を丸くする */
    /* transform: rotate(-90deg); /* 円を-90度回転させる 反転させたいときに使用 */
    /* transform-origin: center center; /* 回転の中心点を円の中心に設定 */
}

コメント文でmessageと書かれている箇所より下は文章に関する見た目を調整しています。

一方で、circleと書かれている箇所より下は円弧部分の見た目を決定する記述です。

円弧の位置

文章と円弧を重ねて表示させるために

円弧を形成するsvg(.gradient-circle-container)に対して

絶対配置position:absolute;と移動プロパティのtransform:translate();を使用して中央に配置しています。

z-index:-1;にしている理由

円弧が手前に来るのを防ぎテキストを選択できるようにするためです

絶対配置を使用したときは必ず上下(表裏)関係を意識するようにしておきましょう。

円弧の見た目

すでにコメント文で記述されている通り、各行にて円弧の見た目に関する設定をしています

.gradient-stroke-circle {
    fill: none;/* 塗りつぶしをなしにする */
    stroke-width: 50;/* 円の線の太さ50 */
    stroke-dasharray: 1060 1413;/* 円の線のスタイルを指定。ここでは、線を75%(1060)と円周を(1413)に設定 */
    stroke-linecap: round;/* 円の線端を丸くする */
    /* transform: rotate(-90deg); /* 円を-90度回転させる 反転させたいときに使用 */
    /* transform-origin: center center; /* 回転の中心点を円の中心に設定 */
}

stroke-dasharrayが見慣れないかもですが、破線を表現するのに使えるプロパティです。

普段はstroke-dasharray:10 5;のように指定して長さ10,空白5の破線を表現という使い方をします

See the Pen 破線のデモ by りょーすけ (@s_ryosuke_1242) on CodePen.

これを応用してstroke-dasharray: 円の長さ 円周;にすることで円弧を表現することが出来ます。

つまりアニメーションを適用したい場合はstroke-dasharray: 円の長さ 円周;の「円の長さ」部分を変更すると良いです。

円周の計算方法

通常円周は直径×円周率で計算しますが

線の太さstroke-widthを考慮して計算する必要があります。

svgのwidthは500 stroke-widthは50

つまり、直径は400として計算してあげます。

アニメーションの作成方法

GSAPを使用してアニメーションを作成します。

GSAPって何?という方は以下の記事をご参照ください。

【高機能】アニメーションライブラリ GSAPの使い方 – おすすめ導入方法はCDN

また、今回はスクロール位置に応じてアニメーションを発火させたいのでGSAPのScrollTriggerプラグインを使用します。

【初心者向け】GSAPのScrollTriggerの使い方を解説!【JavaScriptの知識ほぼ不要】

GSAPはJavaScriptのライブラリのため、JavaScriptを記述することになります。

window.addEventListener('DOMContentLoaded',function(){
    const tl = gsap.timeline({
        scrollTrigger:{
        trigger:'.message',
        start:'center center',
    }});
    tl
    .fromTo('.message__content > *',{autoAlpha:0,y:20},{autoAlpha:1,y:0,stagger:.3})
    .fromTo('.gradient-circle-container',{rotate:'-120deg',x:'-50%',y:'-50%'},{duration:1.5,rotate:'0deg',x:'-50%',y:'-50%'},'<')
    .fromTo('.gradient-stroke-circle',{autoAlpha:0,'stroke-dasharray':'0 1256'},{autoAlpha:1,'stroke-dasharray':'942 1256',duration:1},'<')
})

timelineでアニメーションを管理

GSAPの利点のひとつであるtimelineを使用してアニメーションを管理します。

上から
・テキストのフェードアップ
・円弧の回転
・円弧の線を伸ばす
というアニメーションになっています。

tl
.fromTo('.message__content > *',{autoAlpha:0,y:20},{autoAlpha:1,y:0,stagger:.3})
.fromTo('.gradient-circle-container',{rotate:'-120deg',x:'-50%',y:'-50%'},{duration:1.5,rotate:'0deg',x:'-50%',y:'-50%'},'<')
.fromTo('.gradient-stroke-circle',{autoAlpha:0,'stroke-dasharray':'0 1413'},{autoAlpha:1,'stroke-dasharray':'1060 1413',duration:1},'<')

ひとつ注意点ですが、.gradient-circle-containerに対してx:’-50%’,y:’-50%’という指定をしています。

これはGSAP側で回転時にtransform:trasnlate(206px,206px);という固定値が自動で設定されてしまうため
強制的に相対値-50%となるように設定しています。

→つまりレスポンシブ時に位置ズレが起きないようにしています。

'stroke-dasharray':'1060 1413'

stroke-dasharrayの1413は円周、1060は円周の75%の値です。

アニメーションの発火タイミング

.messageが画面中央に到達したときにアニメ

ーションが発火するように設定します。

const tl = gsap.timeline({
    scrollTrigger:{
    trigger:'.message',
    start:'center center',
}});

まとめ

今回は一部分が欠けた円(=円弧)の作成方法について解説しました。

GSAPを使用することで楽にアニメーションを実装することが出来ます。

ぜひCodePenにあるソースコードをもとに数値を変えてみたりして理解に繋げていただければと思います。