😸

Ionic iOSのListデザインを、CSSを使って最新のiOS18のデザインに寄せる

2024/12/03に公開

iOS 16以降では、設定画面のデザインが更新され、コンテンツ部分は上下だけではなく、左右にもMarginを設定するようになりました。

appledesign15.jpg

それに対応して、Ionicでも ion-list 要素に inset プロパティを追加し、 <ion-list inset=true> とすることで、iOS 16以降のデザインに寄せることができます。デフォルトデザインの更新ではなく、プロパティ対応にしたのは、破壊的変更になり、既存デザインが壊れないようにするためです。

比較するとこんな感じです(color=lightion-toolbarion-content に設定しています)。

inset.png

これはこのコンテンツでは問題ないのですが、iOSの「設定」を再現するなら、リストのそれぞれにアイコンを設定する必要があります。また、例えば「支払いと配送先」の画面のようなデザインをしたいとき、「リストにタイトルをつける」「アイテムにnoteをつける」という要件が生まれるかと思います。

ios-design.png

そこで、デフォルトのデザインを活かしたまま、これらの要件を満たしていきましょう!

Step.1: HTML部分を設定する

実際のプロダクトで使ってるコードを抽出したものです。デフォルトの実装方法との変更点は、 ion-item-group を追加していることですね。あと、アイコンを追加していますが、これはドキュメント通りの実装方法です。

<ion-header [translucent]="true">
  <ion-toolbar color="light">
    <ion-title>
      設定
    </ion-title>
  </ion-toolbar>
</ion-header>
<ion-content color="light" [fullscreen]="true">
  <ion-header collapse="condense">
    <ion-toolbar color="light">
      <ion-title size="large">
        設定
      </ion-title>
    </ion-toolbar>
  </ion-header>

  <ion-list inset="true">
    <ion-item-group>
      <ion-item detail="true" routerLink="/main/settings/account">
        <ion-icon name="person-circle-outline" slot="start" size="small" class="menu-icon color-primary"></ion-icon>
        <ion-label i18n>アカウント</ion-label>
      </ion-item>
      <ion-item detail="true" routerLink="/main/settings/printer">
        <ion-icon name="print-outline" slot="start" size="small" class="menu-icon color-tertiary"></ion-icon>
        <ion-label i18n>プリンタ</ion-label>
      </ion-item>
      <ion-item>
        <ion-icon slot="start" size="small" class="menu-icon color-warning" name="moon"></ion-icon>
        <ion-toggle [(ngModel)]="isDark" (ionChange)="vm.changeTheme(isDark())"
        ><ng-container i18n>ダークモードを利用</ng-container></ion-toggle
        >
      </ion-item>
    </ion-item-group>
  </ion-list>
</ion-content>

このHTMLテンプレートを設定しただけだと以下のように表示されるかと思います。

step-1.png

Step.2 アイコンをデザインする

さて、ではこの表示のアイコンにスタイルをあてましょう。親要素が必ず ion-list[inset=true] になって、配置関係上、 ion-item ion-icon[slot=start] になると割り切るなら、 menu-icon というclassは不要ですが、今回はもうちょっと汎用性をもたせるために、 menu-icon というclassを追加しています。そして、配色を設定するために、それぞれの配色用のclassを用意しています。配色はIonicのテーマカラーから取得してるのでCSS変数を用いていますが、もちろん固定値でも問題ありません。

ion-icon.menu-icon {
  border-radius: 4px;
  padding: 3px;

  &.color-primary {
    background-color: var(--ion-color-primary);
    color: var(--ion-color-primary-contrast);
  }

  &.color-secondary {
    background-color: var(--ion-color-secondary-shade);
    color: var(--ion-color-secondary-contrast);
  }

  &.color-tertiary {
    background-color: var(--ion-color-tertiary);
    color: var(--ion-color-tertiary-contrast);
  }

  &.color-success {
    background-color: var(--ion-color-success-shade);
    color: var(--ion-color-success-contrast);
  }

  &.color-warning {
    background-color: var(--ion-color-warning);
    color: var(--ion-color-warning-contrast);
  }

  &.color-danger {
    background-color: var(--ion-color-danger);
    color: var(--ion-color-danger-contrast);
  }

  &.color-medium {
    background-color: var(--ion-color-medium);
    color: var(--ion-color-medium-contrast);
  }

  &.color-light {
    background-color: var(--ion-color-light);
    color: var(--ion-color-light-contrast);
  }
}

そうすると簡単にアイコンにデザインをあてることができましたね。

step-2.png

Step.3 Listにデザインを当てる

最後に、リストにデザインをあてます。まず、デフォルトの設定の一番の課題が「 ion-list[inset=true] に、背景色が設定されている」ことです。ですので、タイトルやnoteを追加しようとすると、背景色があたっているDOMの内部に表示されてしまいます。ですので、 ion-list[inset=true] の背景色を透明にし、追加してあった ion-item-group に背景色をあてるようにします。

iOSはアイテムは角丸ですが、Material Designは角丸ではないために、 ion-item-group.ios だけに border-radius をあてるようにしています。また、 ion-item のLINEは、最後のアイテムだけ非表示にするようにしています( ion-item-group > :is(ion-item):last-child )。

まぁ、そんなに特別なことはしていないので、CSSを読める方は大体わかる範囲なのではないでしょうか。

ion-content[color=light] {
  ion-list[inset=true] {
    &.list-inset {
      background: transparent;

      ion-list-header {
        ion-label {
          font-size: 0.9rem;
          font-weight: normal;
          margin: 8px 0 4px;
        }
        ion-note {
          font-size: 0.9rem;
          margin: 8px 16px 4px 0;
        }
      }

      ion-item-group.ios {
        border-radius: 10px;
        overflow: hidden;
      }

      ion-item-group > :is(ion-item):last-child {
        --border-width: 0px !important;
        --show-full-highlight: 0 !important;
        --inner-border-width: 0px !important;
        --show-inset-highlight: 0 !important;
      }

      & > ion-note {
        color: var(--ion-color-medium-tint);
        font-size: 0.9rem;
        display: block;
        margin: 8px 16px;
      }
    }
  }
}

出来上がりはこんな感じです。

step-3.png

まとめ

Ionicは、プッシュ遷移・ナビゲーションスタックというWebではパフォーマンスを気にしながら実装することがとても難しい機能を提供しています。一方で後方互換を保つために、こういった小さなデザインを網羅的にコンポーネントで用意していませんが、ベースがあるのでこうやってCSSをあてることでとても簡単に実現したいデザインを実装することができます。

last.png

「UIフレームワークに任さないといけない部分」「自分で実装できる部分」を切り分けて考えることで、より効率的にデザインを実装することができると思います。

それでは、また。

Discussion