SSCF - お問い合わせフォームの統一規格

SSCF - お問い合わせフォームの統一規格
基準

38

27 分。

定義

SSCF規格は、お問い合わせフォームのセマンティクス、アクセシビリティ、および動作ロジックに関する要件を規定しています。

構造と意味

form要素とフィールドのグループ化

  • 関連するデータの収集と送信には、ネイティブのform要素を使用する。フォームの意味付け、キーボード操作、ブラウザー標準の送信機能が利用できる。
  • 関連するフィールドはfieldsetとlegendでグループ化する。fieldsetはフィールドが論理的なまとまりを形成する場合に使用し、個々のフィールドを一つずつ囲む必要はない。
  • legendはグループの名前を示し、fieldsetの最初の子要素として配置する。
  • POSTでデータを送信する場合、formにmethod="post"を明示し、送信先をactionで指定する。ファイルを含むフォームにはenctype="multipart/form-data"も設定する。
  • 外部連携の秘密情報やサービスキーをクライアント側のコードに含めない。データは保護されたサーバー側の処理先に送り、検証と外部システムとの通信を行う。

フォームコントロールの名前と属性

  • 送信対象の各フィールドに一意なidと意味のあるnameを設定する。idはラベルとの関連付けに使い、nameは送信データ内のフィールド名となる。
  • inputにはtext、email、tel、checkbox、file、number、rangeなど、適切なtypeを指定する。selectとtextareaにtype属性はなく、要素自体が操作方法を定める。
  • requiredは、そのシナリオで本当に必須となるフィールドにのみ付ける。任意項目には使用しない。
  • autocompleteにはname、email、tel、given-name、family-nameなど適切なトークンを指定する。ブラウザーによる保存済みデータの入力候補を支援し、フィールドの目的を示せる。
  • placeholderは任意である。短い形式例を示す用途には使えるが、常に見えるlabelの代わりや、唯一の説明としては使わない。
  • 可視のlabelは、forとidを一致させるか、フィールドをラベル内に含めて関連付ける。ラベルを操作すると対応するコントロールにフォーカスが移る。

セマンティックなフォーム構造の例:

<form action="/ja/contact" method="post" enctype="multipart/form-data" data-contact-form>
  <fieldset>
    <legend>連絡先</legend>

    <div class="form-field">
      <label for="name">名前</label>
      <input
        id="name"
        name="name"
        type="text"
        autocomplete="name"
        placeholder="例:アンナ"
        required
      />
    </div>

    <div class="form-field">
      <label for="email">メールアドレス</label>
      <input
        id="email"
        name="email"
        type="email"
        autocomplete="email"
        placeholder="name@example.com"
        required
      />
    </div>

    <div class="form-field">
      <label for="message">メッセージ</label>
      <textarea
        id="message"
        name="message"
        placeholder="お問い合わせ内容を簡潔に入力"
        required
      ></textarea>
    </div>
  </fieldset>

  <div class="form-consent">
    <label class="form-consent__label">
      <input id="data-consent" name="dataConsent" type="checkbox" required />
      <span>データ処理への同意</span>
    </label>
    <a href="/ja/policy" target="_blank" rel="noopener noreferrer">
      データ処理条件(新しいタブで開く)
    </a>
  </div>

  <button class="form-submit" type="submit">送信</button>
  <p role="status" aria-live="polite" data-form-status></p>
</form>

チェックボックスとラベルのテキストをlabelで囲んでいるため、テキストを押してもチェック状態を切り替えられる。a要素はラベルの外に置き、独立した操作要素として扱う。同一サイト内のページを新しいタブで開くのは必要な場合に限り、その動作を事前に明示する。target="_blank"を使う場合はrel="noopener noreferrer"を設定する。

フィールドの状態と検証

視覚状態

  • 初期状態では、エラーや操作中を示すスタイルのない通常のフィールドを表示する。
  • フォーカス状態は通常状態と明確に区別し、キーボード操作時の視認可能なインジケーターを維持する。
  • エラーを色だけで伝えない。テキストによる説明を表示し、独自のプログラム検証ではフィールドにaria-invalid="true"を設定する。
  • aria-describedbyでエラーメッセージを該当フィールドに関連付ける。問題と修正方法を示し、メールアドレスに必要な形式などを説明する。
  • エラーを検出する前にaria-invalid="true"を設定しない。値が修正されたら状態を更新または解除する。
  • すべてのフィールドに成功状態を表示する必要はない。表示する場合は、緑色の枠だけに頼らず、テキストや別のインジケーターでも意味を伝える。

エラーメッセージ付きフィールドの例:

<div class="form-field form-field--error">
  <label for="email">メールアドレス</label>
  <input
    id="email"
    name="email"
    type="email"
    autocomplete="email"
    aria-invalid="true"
    aria-describedby="email-error"
    required
  />
  <p id="email-error">有効な形式のメールアドレスを入力してください。</p>
</div>

検証のタイミングと送信ボタンの無効化

  • required、type="email"、min、max、patternなどのHTML標準制約は、シナリオに合う場合に使用する。独自検証は必要なルールだけを追加する。
  • クライアント側の検証は即時のフィードバックに使うが、重要な制約はサーバー側でも再検証する。クライアントの値は変更されたり、画面を経由せず送信されたりする可能性がある。
  • フィールドを操作する前、フォーカスを外す前、送信を試みる前にエラーを表示するのは避ける。未入力のフィールドに早すぎるエラーが出るのを防げる。
  • 簡単なローカル検証は通常、入力時、フォーカスを外した時、または送信時に追加の遅延なく実行する。高負荷またはネットワーク経由の検証には、入力が止まってから約300 msのdebounceを使えるが、フォーカス離脱時や送信前の即時検証の代わりにはならない。
  • 原則として送信ボタンは利用可能な状態にし、検証を実行して修正点を把握できるようにする。値が無効になるたびにボタンを無効化すると、理由が分からず修正しづらくなる場合がある。
  • プロジェクト方針で条件を満たすまでボタンを無効にする場合は、その条件を近くに明示し、フィールドとエラーを修正可能な状態にする。disabledはエラーメッセージの代わりにはならない。
  • 複数のエラーがある状態で送信を試みた場合は、分かりやすい概要または各フィールドのエラーを表示する。必要に応じて最初の無効なフィールドにフォーカスを移す。

Safariと自動入力

  • iPhoneのSafariでは、フォーカスされたフォームコントロール自体の文字サイズを16px以上にし、フォーカス時のページ自動拡大を避ける。
  • viewportの制限によってページの拡大を無効にしない。ブラウザーの拡大機能を利用できる状態にする。
  • 明確な理由がない限り自動入力を無効にしない。個人情報のフィールドにはname、email、telなど正確なautocomplete値を設定する。
  • ブラウザーの自動入力スタイルがデザインと競合する場合は、:autofillと:-webkit-autofillに十分なコントラストの文字色と背景色を設定する。読みやすさやフォーカス表示を損なう形でシステム表示を隠さない。

フィールドと自動入力の基本スタイル:

.form-field input,
.form-field select,
.form-field textarea,
.phone-field input {
  font-size: 16px;
}

.form-field input:focus-visible,
.form-field select:focus-visible,
.form-field textarea:focus-visible,
.phone-field input:focus-visible {
  outline: 2px solid #2457d6;
  outline-offset: 2px;
}

.form-field [aria-invalid="true"] {
  border-color: #b42318;
}

.form-field input:autofill,
.form-field input:-webkit-autofill,
.phone-field input:autofill,
.phone-field input:-webkit-autofill {
  -webkit-text-fill-color: #161616;
  box-shadow: 0 0 0 1000px #fff inset;
}

例の色はコントラスト確認済みのデザイントークンに置き換える。16pxは入力欄内の文字に適用する。ラベルやプレースホルダーのサイズを変えても入力文字のサイズは変わらない。

フィールドの種類とモバイル入力

電話番号

  • 電話番号にはtype="tel"とautocomplete="tel"を使用する。inputmode="tel"を追加すると、モバイル端末に適切なソフトウェアキーボードを提案できる。
  • 国際電話番号の桁数に一律の固定値はない。「11桁以上」や「ちょうど11桁」を要求する検証は、国や形式をまたいで適用できない。
  • 選択された国の番号計画に基づいて検証し、送信時にはE.164など合意された形式に正規化する。マスクは表示形式を整えるものであり、番号の存在や到達可能性を保証しない。
  • 同じ数字の繰り返しだけでは、無効な番号を確実に判定できない。このようなヒューリスティックを一律の入力禁止にせず、スパム対策はサーバー側で別途行う。
  • 国を切り替えた際は、国番号と表示形式の両方を更新する。国際形式の番号の入力や貼り付けで数字が欠落したり、国番号が二重になったりしないようにする。
  • 記号や国番号の数字を手入力禁止にしない。国際番号を直接入力または貼り付けられるようにする。選択国の国番号が固定されている場合、重複した国番号は追加せず正規化する。
  • 選択中の国番号を編集できない場合、フォーカス時のカーソルは国番号の直後に置く。ただし、番号の選択・置換、国際番号の貼り付け、国の切り替えは可能にする。これはフォーカス時のカーソル位置を指し、フォーム読み込み時のautofocusとは異なる。ロシアでは国内プレフィックス8と国際プレフィックス+7は同じマスクとして扱わず、選択された形式に正規化する。
  • 初期国はユーザー設定、サイトのロケール、または明示的な選択に基づいて設定できる。IPによる判定には別サービスが必要で、誤判定もあり得るため、手動選択や番号入力を妨げない。
  • 番号の途中で入力、貼り付け、選択、削除を行った場合も、カーソル位置を適切に維持する。ライブラリが書式とカーソルを管理する場合、入力イベントごとに手動で移動させない。
  • 電話番号の入力だけでは、本人が番号を所有していることを確認できない。到達可能性や所有者の確認には、認証コードなど別の手順が必要となる。

プロジェクトでのReact実装

Reactプロジェクトでは国際電話入力に@react-input/maskではなくreact-international-phoneを使用する。提示されたuseMask({ mask, replacement })は@react-input/maskのAPIであり、電話入力パッケージのAPIではない。電話入力にはPhoneInputを使い、番号の書式化、国の選択、カーソル位置の管理を行う。IPによる国判定はパッケージの組み込み機能ではなく、番号検証やユーザー自身の選択の代わりにもならない。

import { useState } from 'react';
import { PhoneInput } from 'react-international-phone';
import 'react-international-phone/style.css';

export const PhoneField = () => {
  const [phone, setPhone] = useState('');

  return (
    <div className="phone-field">
      <label htmlFor="phone">電話番号</label>
      <PhoneInput
        defaultCountry="ru"
        forceDialCode
        value={phone}
        onChange={(phone) => setPhone(phone)}
        inputProps={{
          id: 'phone',
          name: 'phone',
          type: 'tel',
          autoComplete: 'tel',
          inputMode: 'tel',
          required: true,
        }}
      />
    </div>
  );
};

react-international-phoneは入力と書式化を担当するが、現在のドキュメントでは電話番号の検証ライブラリとしては扱われていない。番号計画に基づく検証にはgoogle-libphonenumberなどの専用ライブラリを使い、サーバー側でも検証する。

import { PhoneNumberUtil } from 'google-libphonenumber';

const phoneUtil = PhoneNumberUtil.getInstance();

const isValidPhone = (phone) => {
  try {
    return phoneUtil.isValidNumber(phoneUtil.parseAndKeepRawInput(phone));
  } catch (error) {
    return false;
  }
};

形式や番号計画の確認だけでは、その番号が有効であることや送信者本人のものであることは証明できない。

Select、textarea、ファイルアップロード

  • 選択肢の表示には、原則としてネイティブの<select>を使用する。キーボード操作やプラットフォーム標準の挙動が組み込まれている。
  • ネイティブの<select>では満たせない具体的な要件がある場合に限り、独自のリストを実装する。適切なARIAパターンに沿って、アクセシブルな名前、展開・選択状態、キーボード操作、予測可能なフォーカス管理を実装する。
  • レイアウトを損なわない限り<textarea>のサイズ変更を可能にする。縦方向の変更を制限する場合はresize: verticalなど妥当な方法を使う。無条件のresize: noneは長文入力を難しくする場合がある。
  • 許可するファイル形式、最大サイズ、ファイル数を定義する。accept属性はファイル選択画面で候補を示すだけであり、安全性を検証するものではない。
  • ファイルの種類とサイズはサーバー側でも再検証する。MIMEヘッダーやファイル名だけを信用せず、許可する拡張子を制限し、ファイル名と保存先を安全に扱う。
  • 選択後はファイル名とサイズを含む添付一覧を表示する。必要に応じて進捗、エラー、ファイルごとの削除操作も表示する。

範囲スライダー

  • 範囲内の数値を選ぶには、動作が要件に合う場合、ネイティブの<input type="range">を使う。意味付け、フォーカス、キーボード操作、ポインター操作が標準で備わっている。
  • 正確な値の入力が重要な場合は、関連するtype="number"フィールドを併設できる。範囲、ステップ、現在値は一つの状態を元に同期する。
  • 「スライダー+数値入力」の組み合わせでは、送信する値を一つに定める。同じパラメーターをフォームデータに誤って重複して含めない。
  • スライダーにはアクセシブルなラベルと、適切なmin、max、step、初期valueを設定する。位置だけでは十分に理解できない場合は現在値をテキストでも示す。
  • ネイティブスライダーはキーボードとポインター操作に対応する。独自コントロールではポインター、タッチ、キーボード、フォーカス、アクセシブルな名前、支援技術への値の通知を個別に実装する。
  • cursor: pointerは操作可能であることを示す補助として使える。cursor: grabやcursor: grabbingは実際にドラッグできる場合に限って使い、タッチやキーボード操作の代わりにしない。
  • ネイティブコントロールはブラウザーの実装に従ってトラック上のクリックを処理する。独自スライダーはページスクロールを妨げず、マウスとタッチのどちらでも指定位置に移動できるようにする。

数値入力とスライダーを連動させる例:

<div class="form-field">
  <label for="budget-range">予算</label>
  <input
    id="budget-range"
    type="range"
    min="0"
    max="100000"
    step="5000"
    value="50000"
    aria-describedby="budget-current-value"
  />
  <output id="budget-current-value" for="budget-range">50,000円</output>

  <label for="budget-value">金額を直接入力(円)</label>
  <input
    id="budget-value"
    name="budget"
    type="number"
    min="0"
    max="100000"
    step="5000"
    value="50000"
    inputmode="numeric"
    required
  />
</div>

両方のコントロールはインターフェース内の同じ値を更新する。この例では数値フィールドだけにnameがあるため、値は一度だけ送信される。

ネイティブコントロールを同期する例:

const rangeInput = document.querySelector('#budget-range');
const numberInput = document.querySelector('#budget-value');
const budgetOutput = document.querySelector('#budget-current-value');

const formatBudget = (value) => new Intl.NumberFormat('ja-JP').format(Number(value)) + '円';

const updateBudgetOutput = () => {
  budgetOutput.value = formatBudget(rangeInput.value);
};

rangeInput.addEventListener('input', () => {
  numberInput.value = rangeInput.value;
  updateBudgetOutput();
});

numberInput.addEventListener('change', () => {
  if (!numberInput.validity.valid) return;

  rangeInput.value = numberInput.value;
  numberInput.value = rangeInput.value;
  updateBudgetOutput();
});

スライダーを動かすと数値フィールドが更新される。入力した数値は、入力確定後にmin、max、stepの制約を満たす場合に限りスライダーと同期する。

input[type="range"] {
  cursor: pointer;
}

input[type="range"]:active {
  cursor: grabbing;
}

アクセシビリティとキーボード操作

  • フォームコントロールはTabとShift+Tabで予測可能な順序に操作できるようにし、可視フォーカスを消さない。
  • ネイティブの<select>はOSとブラウザーのキーボード規則に従う。独自リストでは選択肢間の移動や選択を含め、一貫したキーボード操作を実装する。
  • フォーカス中のチェックボックスはSpaceで切り替える。ネイティブ要素が状態を伝えるため、重複したARIA属性は不要である。
  • すべてのフィールドにアクセシブルな名前を設定し、通常は<label>を使用する。aria-labelまたはaria-labelledbyは可視ラベルがない場合や不十分な場合に限って使用する。
  • ARIAは不足する名前、状態、関係を補うために使う。「すべてのinputやbuttonに必要」という理由だけで追加しない。役割を再宣言するよりネイティブの意味付けを優先する。
  • エラーを色以外でも判別できるようにする。メッセージを表示してフィールドとプログラム的に関連付け、フォーム全体の変更を通知する場合も予期しないフォーカス移動を避ける。
  • 通常はボタンのテキストがアクセシブルな名前になる。アイコンのみのボタンにはaria-labelまたはaria-labelledbyで分かりやすい名前を付ける。
  • チェックボックスとラベルのテキストを<label>で囲むと、テキスト全体を押して状態を切り替えられる。ポリシーへのリンクはラベルの外に置き、操作可能なリンクを中に入れない。
  • チェックボックスを必須にするかどうかはフォームの目的と製品要件による。ポリシーへのリンクがあるだけで、すべての同意チェックを必須にするわけではない。
  • エラーと成功のメッセージは短く、分かりやすく、見つけやすくする。動的な状態通知にはrole="status"とaria-live="polite"を持つ独立した領域を使用できる。

送信と結果の状態

送信状態

  • 送信前のボタンには「送信」など明確な操作名を表示する。
  • ネットワークリクエスト中の重複送信を防ぐ。ボタンに一時的にdisabledを設定し、フォームの状態をaria-busy="true"で示すことができる。
  • 処理状況はボタンとは別に、たとえばrole="status"の領域で通知する。無効化されたボタン内のテキスト変更は、支援技術で確実に通知されない場合がある。
  • サーバーが成功を確認した後に「フォームを送信しました」などのメッセージを表示する。フォームをリセットするのは確認後とし、エラー時は利用者が消去を求めない限り入力値を保持する。
  • 成功メッセージを根拠なく5秒後に自動で隠さない。タイマーでボタン表示を初期状態に戻す場合も、メッセージを読み取れる時間は確保する。
  • 状態メッセージの自動非表示はスパム対策ではない。送信頻度制限、重複リクエスト対策、不正利用の検証はサーバー側で行う。

ボタンを実際に無効化する場合は、利用可能な状態と視覚的に区別する。カーソルや透明度は視覚的な補助にすぎず、送信できない理由はテキストでも理解できるようにする。

.form-submit:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

サーバー側の処理と外部連携

  • 送信前にすべてのフィールドをクライアント側で検証し、重要なルールはサーバーでも再検証する。サーバーは検証フラグ、disabledの値、画面上の制約を信用しない。
  • データはHTTPS経由のPOSTで送信する。CSRF対策、送信頻度制限、冪等性などの適用は、脅威モデルと処理先の認証方式に応じて判断する。
  • 複数のシステムへデータを送る場合、ブラウザーからアプリケーション自身のサーバー側処理先に送信する。Bitrix、Directus、Telegramなど外部連携のキーをページのJavaScriptに含めない。
  • Promise.allSettled()は複数の独立したPromiseの結果を報告するが、処理を原子的なトランザクションにしたり、一部失敗時に完了済み処理を取り消したりはしない。何を受付完了とするか、失敗した配信をどう再試行するか、重複をどう防ぐかはサーバー側で定義する。
  • ユーザーには主要な操作の結果を通知する。リクエストの保存や確実なキュー登録など、システムが定めた受付条件をサーバーが確認した場合にのみ成功を表示する。
  • 送信失敗時は入力値を消去せず、次の対応を説明する。サーバーから返されたフィールド単位のエラーは該当するコントロールに関連付ける。

サーバー側の処理先へフォームを送信する例:

const form = document.querySelector('[data-contact-form]');
const submitButton = form.querySelector('[type="submit"]');
const formStatus = form.querySelector('[data-form-status]');
let isSubmitting = false;

form.addEventListener('submit', (event) => {
  event.preventDefault();

  if (isSubmitting || !form.reportValidity()) return;

  isSubmitting = true;
  submitButton.disabled = true;
  form.setAttribute('aria-busy', 'true');
  formStatus.textContent = '送信中…';

  fetch(form.action, {
    method: 'POST',
    body: new FormData(form),
    headers: { Accept: 'application/json' },
  })
    .then((response) => {
      if (!response.ok) throw new Error('Form submission failed');

      form.reset();
      formStatus.textContent = 'フォームを送信しました。';
    })
    .catch(() => {
      formStatus.textContent = 'フォームを送信できませんでした。接続を確認して、もう一度お試しください。';
    })
    .then(() => {
      isSubmitting = false;
      submitButton.disabled = false;
      form.removeAttribute('aria-busy');
    });
});

この例では、マークアップにdata-contact-form、送信ボタン、状態通知領域があることを前提とする。実際の処理ではサーバーエラー、タイムアウト、再試行も扱う。クライアント側のコードから外部連携先へ直接アクセスしない。

テスト

  • <form>が正しく使われ、<fieldset>と<legend>が関連するフィールドだけをグループ化していることを確認する。
  • 各フィールドに常時表示のラベル、一意なid、該当する場合は適切なtype、送信対象ならnameがあることを確認する。
  • ネイティブのrequired、入力形式、autocompleteの動作、ラベルと任意のplaceholderの違いを確認する。
  • 初期、フォーカス、エラーの各状態が区別できることを確認する。エラーを色だけで伝えず、説明テキストと関連付ける。
  • 理由なく操作前にエラーを表示せず、適切なタイミングで検証し、送信時にも再検証する。
  • 送信が進まない理由が分かるようにする。無効なボタンだけをエラーや必要操作の表示にしない。
  • マウス、タッチ、キーボードを使った操作を確認する。Tab、Shift+Tab、チェックボックスのSpace、ネイティブと独自selectのキーボード操作も含める。
  • iPhoneではフィールドへのフォーカス時にページが自動拡大しないこと、タッチ端末で適切なキーボードが表示されることを確認する。
  • 自動入力された値の可読性、コントラスト、フォーカス、フィールド状態が保たれることを確認する。
  • 選択国と国際形式に応じた電話番号を検証する。貼り付け、削除、カーソル移動、国の切り替え、数字が繰り返される番号も確認する。
  • IPによる国判定を使う場合、暫定的な初期値として動作し、手動選択とフォールバックが利用できることを確認する。
  • 独自select、電話番号の国選択、独自スライダーをキーボードと支援技術で確認する。
  • ファイルの許可形式、サイズ、数、一覧表示、削除、サーバー側検証、アップロード失敗を確認する。
  • 数値フィールドとスライダーが入力、ドラッグ、上下限、ステップの変更時に同期し、合意された形式で値が送信されることを確認する。
  • 送信時の連続操作、ネットワーク・サーバーエラー、失敗時の値保持、成功後のリセット、状態通知を確認する。
  • 複数の外部連携がある場合、一部失敗と再試行時の重複防止を確認する。

SSCFチェックリスト

カテゴリー主な要件目的
意味構造<form>、<fieldset>、<legend>、label、適切なコントロール型分かりやすい構造とネイティブ動作
データ一意なid、送信値のname、シナリオに応じたrequiredフィールド値を正しく送信する
自動入力正確なautocompleteトークン、ヒントとしてのplaceholder入力を速く分かりやすくする
検証クライアント側のフィードバックとサーバー側の再検証クライアントを信用せずエラーを見つける
状態初期、フォーカス、エラー、送信中、結果。色だけに頼らないフォームの状態を理解できるようにする
電話番号国別の書式、正規化、独立した有効性検証国内外の番号に対応する
特殊フィールドネイティブselectとrange、アクセシブルなtextarea、サーバー検証済みファイル予測可能なデータ入力
アクセシビリティラベル、エラーとの関連付け、キーボード、適切なARIAの意味付け多様な方法で操作・理解できるようにする
送信サーバーへのPOST、保護された外部連携、一部失敗の処理信頼できる送信と分かりやすい結果

関連記事

  • Reactコンポーネントの構造

    各Reactコンポーネントがどのような外観であるべきか、私の考え

    421

    13 分。

  • SST - タブに関する統一規格

    SST規格は、タブのセマンティクス、アクセシビリティ、および動作ロジックに関する要件を規定しています

    62

    11 分。

  • SSF-U - フルスクリーン表示の統一規格

    SSF-U規格は、フルスクリーン表示のセマンティクス、アクセシビリティ、および動作ロジックに関する要件を規定しています

    248

    3 分。

  • SSA - アコーディオンの統一標準

    SSA規格は、アコーディオンのセマンティクス、アクセシビリティ、および動作ロジックに関する要件を定めています

    258

    4 分。

  • ウェブサイトにおける悪い慣行

    ウェブデザインにおける致命的なミスの分析。スライダー、自動再生、重いページがコンバージョン率やGoogleでの検索順位を低下させる理由

    232

    2 分。

  • SSP - ページネーションの統一規格

    SSP規格は、ページネーションのセマンティクス、アクセシビリティ、および動作ロジックに関する要件を規定しています

    240

    3 分。

  • すべての記事

ご連絡ください