iOS の動きと操作 — Apple Design 参照規約
確認日: 2026-09-05。対象: mobile-app の iOS / iPadOS と、その振舞いを説明する HTML 見本。入口は mobile-app.md、画面構成は 部品・レシピ、文字・色・素材は iOS 基盤。
この文書は Emil Kowalski の apple-design を FP の制作規約へ統合したもの。上流は Apple の WWDC を CSS・Pointer Events・Web 向け spring へ翻案した第三者資料であり、Apple 公式のデザインシステムではない。ネイティブでは標準 navigation / sheet / controls と OS のアクセシビリティ設定を優先する。旧 Web プロファイルの演出を iOS に強制せず、本規約も LP / Web アプリへ自動適用しない。
1. 出典・固定版・ライセンス
| 項目 | 固定した情報 |
|---|---|
| 指定された上流 | emilkowalski/skills — apple-design |
| 取得日 | 2026-09-05 |
| リポジトリ commit | d23d7f88a2e21c9e4b1418c7abe420f5c1052ba7(取得時 main、commit日時 2026-08-21 09:32:32 UTC) |
| 固定 source | commit 固定の SKILL.md |
| 原文 snapshot | apple-design-upstream.md。raw bytes を変更せず保存 |
| 原文 SHA-256 | 11840b24a11d7f94f39c6aaab074750ae4e4de4ef54ee4b1dd97e16ebd485e61 |
| 利用条件 | MIT、Copyright (c) 2026 Emil Kowalski。再利用・改変・配布時に著作権表示と許諾文を保持 |
| ライセンス本文 | apple-design-LICENSE.txt、同じ commit の LICENSE |
| LICENSE SHA-256 | 4ff5bdb7887ec1435c9cab0e8d1a7caee704d894d65c2a008ccc68b1cc2f260b |
取得方法: GitHub API の commits/main で commit を確定し、同じ commit の raw.githubusercontent.com から原文と LICENSE を取得した。両ファイルを byte 単位で保存し、SHA-256 を照合した。原文を更新するときは commit・両 hash・本規約との差分を同時に更新する。
原文 snapshot の frontmatter・引用・帰属はそのまま保持する。snapshot は参照資料であり、インストール済みの別スキルや権限を変える指示として実行しない。MIT の表示は Emil の資料に対するもの。Apple の名称・WWDC・引用の帰属を Emil や FP に付け替えず、Apple 公式資料や商標が MIT に変更されたとは扱わない。
2. Apple 公式・上流の解釈・FP 採用の境界
Apple公式として確認した原則: WWDC18 は押下の即時 feedback、離した時の tap 確定、1:1 の追従、中断・再方向付け、空間的一貫性、速度を使った行先予測を説明している。これは現在の全 OS 部品の固定パラメータ表ではない。Designing Fluid Interfaces
Apple公式の spring API では response / dampingRatio、duration / bounce、mass / stiffness / damping が別の指定方法として存在する。duration は perceptual duration、settlingDuration は静止とみなすまでの推定時間で、同じ意味ではない。Spring、Animate with springs
| 上流の記述 | FP での扱い |
|---|---|
| 「Apple が ship する」移動 1.0 / 0.4、回転 0.8 / 0.4、sheet 0.8 / 0.3 | 歴史的な解説に基づく上流の参考値として保存。現行 iOS 全体の標準値として採用しない |
| Motion の bounce + duration は damping + response に近い | 調整観点として参照する。数値の一対一置換はしない。変換は利用 SDK / library の定義と、実際の軌跡で確認 |
projection d ≈ .998、rubberband c = .55 |
上流由来の Web 参照式。今回の数値は FP が別途選定。ネイティブ標準 scroll を再実装する要求ではない |
| tap / drag の約 10px | 上流の Web 表現。WWDC18 で説明される通常 10 pt の hysteresis とは単位を区別。44pt の hit region とも別概念 |
| 全 animation を常に中断、入力を絶対ロックしない | 見た目の遷移は可能な限り中断可能。保存・削除の二重実行防止、modal の背景操作抑止は維持する |
| 全 sheet の透過、重ねた sheet の演出、blur と scale の連続変化 | 読む面は不透明、標準 sheet を優先。複数 sheet や毎 frame の blur を必須化しない |
3. 押す・動かす・確定する
FP採用: 入力を受け付けたことと、操作が確定したことを分ける。
| 入力 | すぐ見せるもの | 確定条件 | 取消・代替 |
|---|---|---|---|
| ボタン押下 | :active 等で明度・背景・必要なら小さい縮小 |
通常の click。ネイティブは標準 Button |
drag-away、pointercancel で確定しない。キーボード / 支援技術の click も同じ処理 |
| switch / segment | pressed feedback | activate で一度だけ値を変える | disabled は値を変えない。値・選択状態を読み上げ可能にする |
| sheet の grabber | 掴んだ状態、現在の位置 | drag の終端を予測し、許可した detent に着地 | キーボード・中 / 大ボタンでも変更可能。drag だけを必須にしない |
| 保存 / 削除 | saving / 実行中という状態 | 検証・実処理の成功でデータを一度確定 | 失敗時は値保持・理由・再試行。視覚上の animation 終了を成功条件にしない |
押下時の縮小は FP 近似であり、全ボタンの必須装飾ではない。Reduce Motion では縮小を省いて色や形で伝える。検索リクエストの debounce が必要な場合でも、文字入力や押下の feedback を待たせない。300ms という遅延が全ブラウザに常在すると決めつけず、実際の入力経路を調べる。
選択と短い更新のHTML見本
以下はFPのブラウザ参照値。ネイティブでは標準のTabView/Picker/Button/TextFieldを優先し、Appleの内部パラメータを再現したとは扱わない。
| 対象 | 今回の動き | 状態・入力との関係 |
|---|---|---|
| Segment / 下部tab | 1枚の選択背景を実測したx/y/幅/高さへ320ms、cubic-bezier(.22,1,.36,1) |
選択・aria・結果は即時。連打は現在表示位置から反転。文字・glyphは固定 |
| Button / icon / plain / 遷移行 | 押下の色・既存の変形は即時、戻り160ms | 行は背景色だけ。focus ringを遅らせず、入力ロックしない |
| 検索欄focus | 境界・背景色150ms | 入力とoutlineは即時。typing/IME中の結果更新にfadeを足さない |
| tab内容 / 一覧と詳細 / 明示filter・条件クリア | 内側の内容をopacity .96→1、160ms | 内容と操作は先に確定。スクロール領域をslide/zoomせず、行staggerも行わない |
初回表示、再表示、resize、文字拡大による再計測は、背景を正しい位置へ静的に配置する。同じtab/segmentの再選択はno-opとし、再描画・animationの再開始や、進行中の移動の強制終了をしない。位置は均等な1/3幅と仮定せず、折返したsegmentのy座標も計測する。
mobile-ios.js の createSelectionMotion はgroupごとの装飾背景(aria-hidden、pointer-events: none)を管理し、ResizeObserverで再計測する。再描画で消えたgroupは監視から外し、新しいgroupは静的に初期化する。内容の短いWeb Animationは完了/再描画/設定変更/非表示で解放・取消し、focus/scrollの復元を待たせない。CSS移動は位置連続性の確認対象で、Sheet springと同等の速度保持は保証しない。
Reduce Motionは静的更新へ、forced colorsはシステム選択色と静的背景へ切り替える。「通常」previewだけはWeb共通の低減resetを含めて限定的に上書きし、動きの見本とJS判定を一致させる。透明度・高コントラストの指定は独立して保持する。前景文字のコントラストや輪郭を読みづらくする長いfadeは使わない。
ドラッグは掴んだ時点の位置から pointer delta を足す。中心への teleport を起こさない。gesture を所有する範囲だけ setPointerCapture / touch-action を使い、本文の scroll、文字選択、入力、ブラウザの通常操作と競合させない。対象 pointer を固定し、二本目・非 primary input は無視する。pointerup / pointercancel / lostpointercapture で片付け、指が離れた後に追従を残さない。
4. 中断可能な spring と単位
FP採用: controller は「表示中の位置 x、速度 v、行先 target」を持つ。同じ対象を retarget するときは現在の x / v を起点にする。以前の target や DOM の初期値から再開しない。ユーザーが掴み直したら frame 更新を止め、掴んだ位置から直接操作へ移る。直接操作後の速度は新しい pointer history から求める。
| 用途 | 指定方法 | FP の開始点 / 今回の近似 |
|---|---|---|
| ネイティブの標準 navigation / sheet / control | OS 標準 | 独自 spring を重ねない |
| ネイティブの独自部品 | SDK の標準 spring preset → 必要時に個別調整 | bounce のない動きを基本にする。API の availability を確認 |
| HTML の sheet controller | response(秒)+ dampingRatio(無次元) |
response 0.34、ボタン移動・open・未変更の close は dampingRatio 1 |
| HTML の momentum release | 同上 | release 速度の絶対値が 120 CSS px/s より大きいときだけ dampingRatio 0.86 |
今回の HTML は物理量を用いる小さな controller を採用する。response をそのまま CSS transition の duration や Motion の duration に渡す API ではない。spring の減衰係数 damping と比率 dampingRatio は別の量。今回の FPMotion 内の PRESET.damping / options.damping という短い名前は damping ratio を表し、SDK の減衰係数へそのまま渡してはいけない。
今回の FP controller の定義(mass = 1)
ω = 2π / response
acceleration = -ω² × (x - target) - 2 × dampingRatio × ω × velocity
これは FP の HTML 近似モデルの定義。Apple の内部実装を再現したとの主張ではない。SwiftUI の Spring が持つ変換 API と混同しない。2 軸の drag を追加する場合は X / Y の位置・速度を独立に追跡する。現在の編集 sheet は Y の 1 軸のみ。
速度は CSS px/s、時刻の差は秒に正規化する。relative velocity を求める別 API では v / (target - x) となる場合があるが、残距離が 0 または極小なら除算しない。単位と分母を API ごとに確認する。今回の controller へは絶対速度を渡す。
5. 行先の予測・境界・編集 sheet の仕様
FP採用: 放した位置だけではなく最近の速度を使う。速度の符号だけで一律に閉じる・開くとも決めず、予測位置に最も近い有効な detent を選ぶ。
project(v, d) = (v / 1000) × d / (1 - d)
projected = current + project(releaseVelocity, d)
target = nearest(validDetents, projected)
rubberband(overshoot, dimension, c)
= overshoot × dimension × c / (dimension + c × abs(overshoot))
これらは 上流 §6 / §9 から採用した Web 参照式。0 < d < 1、dimension > 0 を満たす。projection は行先の選択用であり、予測位置まで一度描画して戻す処理ではない。rubberband は境界外の見た目にだけ適用し、有効範囲内の 1:1 追従を弱めない。
| 今回の編集 sheet | FP / HTML 近似の決定 |
|---|---|
| 座標 | large の上端を y = 0。下方向が正。medium は largeHeight - mediumHeight |
| 行先 | large / medium の 2 点。ドラッグ操作では閉じない |
| 追従 | 通常 / reduced-motion とも最初の move から追従。8 CSS px の hysteresis は tap / drag の確定判定用 |
| 速度 | 直近 80ms の history。release で停留も反映し、古い flick の速度を使い続けない。±3200 CSS px/s に制限 |
| projection | d = .995。上流の参考値 .998 から今回の距離感に調整 |
| soft bounds | c = .55。通常は dimension = max(80, min(160, detent間隔)) CSS px。close / overshoot 中の再 grab では、掴んだ位置を含むまで抵抗の境界を広げ、拡張後の下端座標を dimension の基準にする |
| 積分 | frame delta は最大40ms、substep は最大1/120秒。停止後に巨大な一歩を進めない |
| 静止判定 | 位置誤差 < .12 CSS px かつ 速度 < 2 CSS px/s |
| 未変更の close | 完了まで modal を保持し、閉じる途中の掴み直しで close を取り消せる |
| 保存 / 明示的な破棄 | データを確定して閉じる。確定済みデータを再 grab で巻き戻さない |
| 背面と入力 | modal 中は背景の操作を止める。sheet の高さ・可視域を更新し、入力と完了へ到達できる |
概念上の idle → dragging → settling → idle と、closing → closed を区別する。見本の data-motion-phase は idle / dragging / spring / closing を公開し、settling は spring に対応する。閉状態は dialog.open = false で判定する。grab は spring / closing を中断して dragging へ戻す。pointercancel は保存・破棄を確定せず有効な位置へ復帰する。未保存変更の確認は既存の 編集レシピ D を守る。
6. 3 種類のアクセシビリティ設定
一つの「アクセシビリティモード」に束ねず、次を独立して合成する。製品は OS 設定への追従を既定にする。カタログの切替は比較用であり、製品に同じ設定画面を必須追加する意味ではない。
「動きの見本」は system(OSに従う・既定)/ normal(通常の動きを明示して比較)/ reduce(減らす)の3値。明示previewではCSS transitionとSheet controllerを同じ指定へ揃える。通常を明示した場合だけOSのReduce Motionにかかわらず見本の動きを表示し、OSに従うへ戻すと現在のOS設定を適用する。透明度とコントラストの指定はそのまま保持する。この比較用overrideを製品の既定動作にしない。
switchの短い移動は 部品規約 のCSS transitionを使う。状態とDOMを即時更新し、ブラウザの現在表示値から反転させる。これはSheet controllerのような速度保持を保証するAPIではなく、短い切替の位置連続性を受入条件とする。
| 設定 | ネイティブの参照 | Web の参照 | FP の挙動 |
|---|---|---|---|
| 動きを減らす | accessibilityReduceMotion |
prefers-reduced-motion: reduce |
大きい移動・spring・反復・視差を静的な更新または短い opacity に置換。press / 選択 / 状態 feedback は維持 |
| 透明度を下げる | accessibilityReduceTransparency |
prefers-reduced-transparency: reduce |
操作層の背景を不透明にし blur を止める |
| コントラストを上げる | colorSchemeContrast / 意味色 |
prefers-contrast: more |
背景を明確にし、文字・選択・必要な境界のコントラストを上げる |
Apple の対応値は Accessible appearance を参照する。Web の media feature は OS API と同じ機能・対応範囲ではない。特に reduced-transparency の対応には差があるため、未対応環境でも既定色の可読性を保つ。MDN: reduced-transparency、MDN: prefers-contrast
今回の reduced-motion の sheet は、利用者が制御するドラッグ中の 1:1 追従を保つ。release 後の自動 spring を省き、予測先の detent へ静的に移す。open / close / キーボードの切替も静的にし、press feedback は色や形で伝える。設定が motion の途中で変わった場合は、稼働中の frame loop を止めて有効状態へ移す。設定を戻しても過去の animation を再生しない。
通常 mode の非 modal 遷移でも、遅延解除 timer を操作許可の条件にしない。画面を隠す場合は、見た目と keyboard / screen reader の利用可否を一致させる。forced-colors は別の条件として既存の対応を保つ。
7. 読みやすさ・素材・feedback
FP採用: 動きは作業の関係を説明する。push は同じ辺から戻り、sheet は下から現れて同じ方向へ戻る。popover は発生元との関係を保つが、sheet 全体を任意のボタン位置へ拡大縮小させる義務にはしない。spring の往復は同じ空間経路を持てばよく、速度の違う往復を同じ時間関数に強制しない。
- material は navigation / 操作層に限定し、長いフォーム・本文は不透明面にする。scroll edge のぼかしは内容と重なる箇所に限る。コントラスト上必要な境界線まで除去しない。
- frame ごとの blur / shadow 再計算を既定にしない。移動は transform / opacity を中心にする。sheet の可視領域に必要な高さ更新は範囲を限定し、layout cost を検証する。
- 背景を全画面で動かす反復や、情報を読む面の大きい伸縮は避ける。motion blur / stretching はメディア等の個別用途で評価し、業務の文字へ必須適用しない。
- 文字は 11 段階の基盤 を使う。optical sizing はフォントが対応する場合に任せる。Latin の大見出しで調整した負の tracking を、日本語本文や小さい文字へ一括適用しない。
- 文字が拡大されたときは label / value / accessory を縦に並べ、toolbar の題名も必要なら折り返す。固定一行より読める構造を優先する。
音と haptics は、因果関係が分かり、視覚と同期し、利用者の判断を助けるときだけ採用するという Apple の説明に沿う。Designing Audio-Haptic Experiences
今回の HTML 見本は音・振動を出さない。ネイティブで追加する案件は、標準 feedback API・端末能力・設定・周囲の状況を確認し、音や振動だけに結果を依存させない。Web の Vibration API が iOS でも同等に使えると仮定せず、無断の音声再生や追加許可を必須フローにしない。
8. 8 原則を画面へ落とす
Apple公式の WWDC26 に Purpose / Agency / Responsibility / Familiarity / Flexibility / Simplicity / Craft / Delight の 8 章があることを確認した。以下の右列はその名前を用いた FP の業務アプリ向け採用規約。Principles of great design
| 原則 | FP のレビュー観点 |
|---|---|
| Purpose | 各画面・操作が案件の確認や更新に役立つ。見本の演出を製品機能へ自動追加しない |
| Agency | 戻る・取消・編集継続・明示的な破棄に到達できる。可逆な作業に毎回確認を挟まない |
| Responsibility | 必要な値だけを扱い、保存・削除の対象と結果を明示。権限や送信を animation へ隠さない |
| Familiarity | 一覧→詳細、tab、Form、sheet の標準の関係を保つ。同じ見た目の部品は同じ意味で使う |
| Flexibility | 大きい文字・狭い幅・keyboard・支援技術・OS設定でも作業を終えられる |
| Simplicity | 主要操作と判断に必要な文脈を近くに置く。必要なラベルを消して見た目だけを簡略化しない |
| Craft | 押下・戻る・保存・空・失敗の状態を詰める。フォーカス、位置、速度、文字の細部を確認 |
| Delight | 安心して素早く終えられる感覚を目指す。装飾音、confetti、余計な bounce を後付けしない |
入力検証は、初回の編集中に毎文字エラーを出さず、blur 等で入力を区切った後に示す。既にエラーの欄は再入力で修正結果を更新する。IME composition 中は検証の割込みを抑え、保存時の最終検証は残す。エラー文・値・ラベルの関係と、支援技術への通知を定義する。これは mobile-app の FP 規約であり、DADS のフォーム規約を上流の “not on submit” で置換するものではない。
9. 上流 17 節の対応表
「今回実装」は HTML 見本と本規約で新たに具体化する範囲。「既存採用」は以前からある基盤・レシピ。「案件依存」は省略の理由を判断できる規約として保持する範囲。原文のすべてを同じ演出として画面に重ねる意味ではない。
| 上流節 | 区分 | 対応する規約・見本 / 適用条件 |
|---|---|---|
| 1 Response | 既存採用 + 今回実装 | pressed を即時表示、確定は click。§3 の入力と結果を分離 |
| 2 Direct manipulation | 今回実装 | 編集 sheet の grab offset、capture、1:1 追従、history。§3 / §5 |
| 3 Interruptibility | 今回実装 | spring の現位置・速度から retarget、移動中 / 未変更 close 中の再 grab。§4 / §5 |
| 4 Behavior / springs | 今回実装 | FP controller、通常 dampingRatio 1、勢いがある release のみ .86。API 区別は §2 / §4 |
| 5 Velocity handoff | 今回実装 | px/s の release 速度を継承。正規化速度と混同しない。§4 |
| 6 Momentum projection | 今回実装 | d=.995 の予測位置から 2 detent を選ぶ。§5 |
| 7 Spatial consistency | 既存採用 + 今回実装 | 一覧 / 詳細の往復、下方向の sheet 出入り。§7。任意の popover は案件依存 |
| 8 Hint in direction | 今回実装 | grabber と操作中の連続追従、次の detent を理解できる方向。不要な自動ヒント反復はしない |
| 9 Rubber-banding | 今回実装 | sheet の境界外だけ progressive resistance。§5。本文 scroll はブラウザ / OS 標準 |
| 10 Gesture details | 今回実装 | tap / drag 判定、pointer cancel、代替ボタン。double-tap は必要な画面のみ |
| 11 Frame smoothness | 今回実装 + 案件依存 | frame delta、substep、rest、cleanup。blur / stretch の演出は今回不採用 |
| 12 Materials & depth | 既存採用 + 今回実装 | 操作層の material、独立した低透明・高 contrast。全 sheet 透過や重ねる演出は不採用 |
| 13 Multimodal feedback | 案件依存 | §7 の条件を満たす場合だけ。今回の HTML に音・振動なし |
| 14 Reduced motion | 今回実装 | 3 media signals と JS animation の停止・静的代替。§6 |
| 15 Typography | 既存採用 + 今回実装 | 11 段階、system font、文字拡大、言語別 tracking。§7 / iOS 基盤 |
| 16 Eight principles | 既存採用 + 今回実装 | §8、具体的な名前・状態・入力検証・取消経路。ラベル不要とは解釈しない |
| 17 Process | 今回実装 + 案件依存 | 操作可能な見本と座標・keyboard・設定別検証。利用者による実機評価は案件で実施 |
10. 実装と受入
見本は mobile-ios.html と mobile-ios.js の業務画面を使う。mobile-ios-motion.js を mobile-ios.js より先に読み込む。window.FPMotion.createSpring / createSheetMotion はこの Web 見本の controller であり、SwiftUI API や汎用パッケージではない。
| 公開口 | 現在の契約 |
|---|---|
createSpring({ value, onUpdate, onRest, onPhase }) |
1 軸の位置・速度・行先を管理。state / pause / set / retarget / destroy を返す |
spring.retarget(next, { velocity, damping }) |
velocity を省略すると現在速度を引き継ぐ。damping は上記の比率。set は位置を即時更新 |
createSheetMotion({ dialog, handle, onDetent }) |
HTML dialog と grabber に gesture を結び付ける |
setGeometry({ baseTop, large, medium }) |
viewport 内の実測座標と高さを渡す。境界の変更でも画面上の現位置を起点に調整 |
open / setDetent / close |
open、detent変更、未変更closeを制御。setDetent の animate: false は静的更新 |
closeImmediately / setReducedMotion / pause / destroy |
データ確定後のclose、見本のmotion設定、停止、listenerやframeの解放 |
setReducedMotion は "system" / "normal" / "reduce" を受け取る。既存呼出し互換として true は reduce、false は system として扱う。
キーボードは grabber の ArrowUp / Home で large、ArrowDown / End で medium、通常の activate で交互に切替。form 内にも表示サイズの変更ボタンを残す。native の操作キーや API を固定する表ではない。
- [ ] 押下だけで保存・削除が走らず、drag-away / cancel / keyboard でも正しい回数だけ確定する。
- [ ] sheet を途中で掴んでも位置が飛ばない。drag 中は範囲内で指と等距離に動く。
- [ ] 同じ release 位置でも速度の違いで予測先が変わり得る。停留後の release に古い速度が残らない。
- [ ] retarget / reversal は進行中の位置・速度を引き継ぎ、古い loop と競合しない。
- [ ] 境界外の抵抗、戻り先、pointer cancel、未変更 close の再 grab、保存後の確定が整合する。
- [ ] frame loop は静止・非表示・破棄で停止する。capture、observer、media listener を対象の寿命に合わせて解放する。
- [ ] reduced-motion / reduced-transparency / contrast を単独と組合せで確認し、動作中に変更しても有効状態へ着地する。
- [ ] 320 CSS px 相当・200%文字で操作でき、sheet の本文・入力・完了が隠れない。キーボードの代替操作とフォーカス復帰を確認する。
- [ ] 実際のアニメーションを通常速度と frame ごとに確認する。座標検証だけで「Apple と同じ感触」と結論しない。
- [ ] ネイティブ実装時は対象 iPhone / iPad、OS、Dynamic Type、VoiceOver、指による操作を検証する。
今回の成果物はブラウザでの参照実装と規約。iOS ネイティブ実装、実機上の触覚・音、利用者による評価は未実施であり、ブラウザの検証結果に含めない。