SvelteKitならではの書き方を学ぶ!テンプレート構文と最適化のポイント
大平 恵美
大平 恵美
2025-02-07
SvelteKitの特徴的な書き方について解説します。 {#if} を使った条件分岐、テンプレート構文のシンプルさ、デフォルト値の設定、セキュリティ対策など、SvelteKitならではの開発スタイルを学びます。サムネイル画像表示の例を通じて、より効率的で読みやすいコードを書く方法を紹介します。
あなた:

あなたはプロのフロントエンドエンジニアです。 SvelteKitで開発をしていてセットアップは完了してます。

  {#if imageUrl}
    <div class="mb-2">
      <a href={link} target="_blank" class="block">
        <img src={imageUrl} alt={title} class="border border-gray-300 rounded-lg p-1 shadow-sm object-cover w-full h-48"/>
      </a>
    </div>
  {/if}

このコードについて解析してください。

ChatGPT:

このコードは、SvelteKit でサムネイル画像を表示するコンポーネントの一部です。以下にコードの詳細な解析を行います。


1. 基本的な構造

{#if imageUrl}
  <div class="mb-2">
    <a href={link} target="_blank" class="block">
      <img src={imageUrl} alt={title} class="border border-gray-300 rounded-lg p-1 shadow-sm object-cover w-full h-48"/>
    </a>
  </div>
{/if}

このコードは Svelteのテンプレート構文 を使用して、 imageUrl が存在する場合にのみ、サムネイル画像を表示するようになっています。


2. 各要素の解説

部分 説明
{#if imageUrl} ... {/if} imageUrl の値が存在する場合に div を描画する。
<div class="mb-2"> 余白(margin-bottom: 0.5rem)を適用した div で、サムネイル全体を囲む。
<a href={link} target="_blank" class="block"> 画像をクリックすると link に遷移し、新しいタブ (target="_blank") で開く。
<img src={imageUrl} alt={title} ... /> imageUrl の画像を表示し、alttitle を設定してアクセシビリティを向上。

3. CSSクラスの解説

このコードでは、Tailwind CSS を使用してスタイルを適用しています。

クラス 説明
border border-gray-300 画像に 1pxgray-300 ボーダーを追加。
rounded-lg 角を丸くする(border-radius: 8px 相当)。
p-1 画像の内側に 4px のパディングを追加。
shadow-sm 画像に小さな影をつける。
object-cover 画像の比率を保ちながらコンテナ全体をカバー。
w-full 画像の幅を親要素に合わせる。
h-48 画像の高さを h-48192px)に固定する。

4. 改良の提案

alt 属性のフォールバック

現在、alt={title} ですが、title がない場合は空の alt="" になってしまう可能性があります。安全にフォールバックするなら:

<img src={imageUrl} alt={title || 'サムネイル画像'} />

height を動的に調整

高さが h-48 で固定されているため、画像のアスペクト比によっては意図しないトリミングが発生するかもしれません。h-auto に変更するか、aspect-ratio を指定すると柔軟になります。

<img src={imageUrl} alt={title || 'サムネイル画像'} class="border border-gray-300 rounded-lg p-1 shadow-sm object-cover w-full h-auto aspect-[16/9]" />

このように aspect-[16/9] を適用すれば、アスペクト比 16:9 を維持できます。


target="_blank" のセキュリティ対策

外部リンクを新しいタブで開く際、rel="noopener noreferrer" を付けることで セキュリティリスク を軽減できます。

<a href={link} target="_blank" rel="noopener noreferrer" class="block">

これにより、悪意のある外部サイトが window.opener を利用して親タブを操作するリスクを回避できます。


5. 最適化されたコード

上記の改良をすべて適用した最終コードは以下のようになります。

{#if imageUrl}
  <div class="mb-2">
    <a href={link} target="_blank" rel="noopener noreferrer" class="block">
      <img 
        src={imageUrl} 
        alt={title || 'サムネイル画像'} 
        class="border border-gray-300 rounded-lg p-1 shadow-sm object-cover w-full h-auto aspect-[16/9]"
      />
    </a>
  </div>
{/if}

まとめ

imageUrl の有無を確認してサムネイルを表示
Tailwind CSS を利用してスタイルを適用
alt のフォールバックを追加し、アクセシビリティを向上
aspect-ratio を設定して画像のトリミングを回避
rel="noopener noreferrer" を追加してセキュリティ対策

これで、より安全かつ柔軟なサムネイルコンポーネントになります!

あなた:
{#if imageUrl}{/if}

私は以前JavaScriptでコードを書いたことがありますが、こういう書き方もあるのですね。

ChatGPT:

そうですね!Svelte の {#if}JavaScript の if ステートメントとは異なる構文 ですが、テンプレート内で条件分岐を簡潔に記述できる 強力な機能です。


Svelte の {#if} 構文

Svelte では、テンプレート内で if 文を書く場合、次のように {#if 条件} ... {/if} という構文を使います。

{#if 条件}
  <!-- 条件が true のときに表示 -->
{/if}

たとえば、以下のように imageUrl が存在する場合のみ img を表示できます。

{#if imageUrl}
  <img src={imageUrl} alt="サムネイル画像">
{/if}

JavaScript の if 文との違い

JavaScript の通常の if 文と比較すると、Svelte の {#if}テンプレートの一部を直接制御できる という点が大きな違いです。

① JavaScript の if

if (imageUrl) {
  console.log(`<img src="${imageUrl}" alt="サムネイル画像">`);
}

この場合、if ブロック内で HTML を文字列として扱うか、DOM を直接操作しなければなりません。

② Svelte の {#if} を使った場合

{#if imageUrl}
  <img src={imageUrl} alt="サムネイル画像">
{/if}

この書き方なら、 不要な img 要素が描画されない ため、クリーンなコードになります。


{#if}elseelseif を追加

JavaScript の if-else のように、{#if} には {:else}{:else if} も使えます。

例:画像がない場合の代替テキスト

{#if imageUrl}
  <img src={imageUrl} alt="サムネイル画像">
{:else}
  <p>画像がありません</p>
{/if}

例:条件分岐を追加

{#if status === 'loading'}
  <p>読み込み中...</p>
{:else if status === 'error'}
  <p>エラーが発生しました</p>
{:else}
  <p>コンテンツが表示されました</p>
{/if}

JavaScript で Svelte の {#if} に相当する書き方

もし JavaScript で同じことをやる場合、React や Vue では && や三項演算子を使います。

React の場合

{imageUrl && <img src={imageUrl} alt="サムネイル画像" />}

または:

{imageUrl ? <img src={imageUrl} alt="サムネイル画像" /> : <p>画像がありません</p>}

Vue の場合

<img v-if="imageUrl" :src="imageUrl" alt="サムネイル画像">
<p v-else>画像がありません</p>

Svelte の {#if} のメリット

HTML の中に直感的に条件分岐を書ける
不要な要素が DOM に残らない
JavaScript らしいコードを書かなくても簡潔に記述できる


まとめ

Svelte の {#if}HTML テンプレート内で直接使える条件分岐 で、JavaScript の if 文とは少し違う構造を持っています。ただし、慣れると React の { condition && <Component /> } よりもシンプルで読みやすい ので、Svelte らしい書き方として使いこなすと便利です!

この {#if} の使い方に慣れると、Svelte のテンプレート構文をより深く理解できるようになりますよ!

あなた:
alt={title || 'サムネイル画像'}

これはtitieで表示できるものがない場合、'サムネイル画像'を表示するとのことですが、子コンポーネントでデフォルト値を設定するので必要ないかと思いますが。

ChatGPT:

その通りです!もし title のデフォルト値を 子コンポーネント側で設定している なら、alt={title || 'サムネイル画像'} のフォールバック処理は不要になります。


不要な場合の理由

export let title = 'サムネイル画像';

上記のように 子コンポーネント(親から title を受け取る側)で export let title = 'サムネイル画像'; のようにデフォルト値を設定している場合title は必ず 'サムネイル画像' 以上の値を持つので、alt={title} だけでOKです。

<img src={imageUrl} alt={title} />

これで問題ありません。


フォールバックが必要な場合

ただし、デフォルト値が設定されていない場合や、titlenullundefined になる可能性がある場合は、フォールバックを入れたほうが安全です。

<img src={imageUrl} alt={title || 'サムネイル画像'} />

これにより、title が空 (undefinednull"") のときに 'サムネイル画像' を代わりに使えます。


どちらが適切か?

デフォルト値を export let title = 'サムネイル画像'; で定義している場合alt={title} だけでOK
デフォルト値を定義していない or 親から nullundefined が渡る可能性がある場合alt={title || 'サムネイル画像'} を使うのが安全


結論

子コンポーネント側でデフォルト値を設定しているなら、alt={title} だけでシンプルに書くのがベスト! 🎯