はじめに
勉強会をご覧の皆さま
元々のテーマは「10分でわかるダークモード対応」でしたが、あちこち調べているうちにページ数が30を超えてしまい、「10分ではわからないダークモード対応」になりました🙇♂️
20分には収めます
ダークモードとは?
OSシステムレベルで設定可能な、画面表示色の設定です。

Light Modeが従来通りの白基調な画面、Dark Modeは黒基調な画面です。
何が明るく/暗くなるの?
特定の何に適用すべきという法則は無いようですが、閲覧者に見せたいコンテンツ以外のウィンドウ枠、背景などに対して適用されることが多いようです。
もちろん、メインコンテンツ(テキスト色など)も背景色に応じて調整する必要があります。
ダークモードにすると何がいいの?
- 目へのダメージを抑える
- 眩しい画面を見ることによるドライアイ、頭痛、メラトニン抑制による不眠など
 
- バッテリーの持ちが長くなる
- OLEDスクリーンで輝度が100%の場合、DarkはLightと比較して約60%のエネルギーを節約。輝度が50%の場合、約15%節約(YouTubeアプリで計測)
 
- 背景は明るいより暗いほうが、メインのコンテンツを目立たせ、作業に集中しやすくする
ダークモードにする場合のデメリットや注意点
- 直射日光の下などの明るい場所で読みづらい
- ナイトモード(ブルーライトカットの)と同じように、日没〜日の出までダークモードとする設定が用意されている
 
- テキスト色と背景色の逆転にOCRが追いついていない
- ダークモードで撮ったスクショをGoogle翻訳にかけても(現時点では)翻訳してくれない😭
 
ダークモード対応OS
- Windows 10 version 1903〜
- Mac OS Mojave(10.14)〜
- Android 10〜
- iOS 13〜
ダークモード設定方法
- Windows
- スタート -> 設定 -> 個人用設定 -> 色
 
- macOS
-  -> システム環境設定 -> 一般 -> 外観モード
 
- Android
- 設定 -> ディスプレイ -> テーマ
- Zenfoneの場合は 設定 -> ディスプレイ -> システムカラースキーム
- クイック設定パネルに追加したい場合は 画面上端を下にスワイプ -> 🖋
 
- iOS
- 設定 -> 画面表示と明るさ -> 外観モード
- コントロールセンターに追加したい場合は 設定 -> コントロールセンター -> コントロールをカスタマイズ
 
iOS/Androidアプリでのダークモード対応方法(アプリエンジニア向け)
iOS
準備
- Xcode 11以上のビルド環境
- iOS 13以上の実機orシミュレーター
iOSダークモード対応は急務!!
- iOSアプリが2020年4月以降、iOS 13 SDKビルドでの審査提出が必須となる
- iOS 13 SDKビルドはデフォルトでダークモードがONになる
- 
UIUserInterfaceStyleを使えば一時しのぎ出来るが、公式は移行を強く推している- 将来効かなくなる可能性が高い
 
まずダークモードの見え方を確認しよう!
StoryboardやXibのInterface Builder上でLight/Darkを切り替える
デバッグ実行中にLight/Darkを切り替える
Darkにして、どうなったか。弊社案件の場合
- テキストが自動で白くなったが背景も白い。文字が読めない!
- 背景が自動で黒くなったがテキストも黒(
- 濃緑基調のグラフィックが黒い背景では見えづらい
- QRコードが真っ黒黒助
何故そうなるのか
- 場所によってiOS System Colorsを使ったり使わなかったりするため
- 大人数のプロジェクトでありがちな統一感の甘さ
- とはいえiOSのStoryboardを完璧な統一感で作った人は見たことありませんが…😅
対応作業
カラーセットを使う場合
- ハードコードしている色をAssets CatalogのColor Setに移行する
- Color SetのAppearancesにてDarkを追加する
   
- Dark Appearanceにフォーカスを合わせ色設定する
- 色は従来のsRGB方式以外に、iOS System Colorsも選択可能
- 
darkTextColorやsystemBackgroundColorなど
- 使うとOS側が色の濃さを自動調整してくれる。便利!
- 詳しくは参考記事の実践 iOS13ダークモード対応に、わかりやすく書かれています
 
- 
カラーセットを使わない場合
- アプリ起動中にLight/Darkを切り替えられても即反映させたいので、次のいずれかの方法で実装
- dynamicColor方式
extension UIColor {
    private class func dynamicColor(light: UIColor, dark: UIColor) -> UIColor {
        if #available(iOS 13, *) {
            return UIColor { (traitCollection) -> UIColor in
                if traitCollection.userInterfaceStyle == .dark {
                    return dark
                } else {
                    return light
                }
            }
        }
        return light
    }
    public static var textColor: UIColor {
        return dynamicColor(
            light: UIColor(displayP3Red: 0, green: 9, blue: 11, alpha: 1),
            dark: UIColor(displayP3Red: 255, green: 246, blue: 244, alpha: 1)
        )
    }
}
- dynamicProvider方式
extension UIColor {
    @available(iOS 13.0, *)
    convenience init(light: UIColor, dark: UIColor) {
        self.init {
            if $0.userInterfaceStyle == .dark {
                return dark
            } else {
                return light
            }
        }
    }
    @available(iOS 13.0, *)
    public static let textColor = UIColor(
        light: UIColor(displayP3Red: 0, green: 9, blue: 11, alpha: 1),
        dark: UIColor(displayP3Red: 255, green: 246, blue: 244, alpha: 1)
    )
}
こちらはSDKバージョンの制限を受けますが、initとして処理を書けて、定数をimmutableにできます。
Android
準備
- Android Studio 3.3以上のビルド環境
- Android 10(Q)以上の実機orシミュレーター
まずダークモードの見え方を確認しよう!
Design View上でLight/Darkを切り替える
- Night Mode -> Nightを選択
開発者向けオプションを使う
- システム -> 詳細設定 -> 開発者向けオプション -> フォースダークのオーバーライド
- アプリの実装を変えずダークモードをシミュレートできる
Darkにして、どうなったか。弊社案件の場合
- Design View上では何も変わらなかった…
- Android版は?android:attr/textColorPrimaryなどのシステムカラーを使っていなかったから
- Androidチームはデザイン指示書に厳密に従ったので、システムカラーを使わなかった
 
- Android版は
- でも、開発者向けオプションだといい感じのダークモードになった
- iOSで起きてた問題は一切起きなかった(細かい部分を見ると直したい色はあったが)
- Android10の強制ダークモードは割としっかりダークしてくれるの例と同じような結果だった
 
対応作業
- 
styles.xmlやcolors.xmlを別々に用意する
- Light:res/values/*
- Dark:res/values-night/*
- 共通のものはLight側にまとめよう
- Darkの方には、夜間モードかフォースダークを適用する(後述)
- 
2つの重ね掛けはできないらしい 
- 
もしくは、iOSのSystem Colorsに相当するテーマの属性やマテリアルデザイン コンポーネントを利用することもできる。厳密にカラー指定しない場合はこちらがオススメ 
- 
色のハードコードは厳禁らしい 
夜間モード機能を使う
- アプリを新規作成すると自動でTheme.AppCompat.Light系のテーマが適用されているが、Dark側のスタイルにはTheme.AppCompat.DayNightを適用する
res/values-night/themes.xml
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar" />
フォースダーク機能を使う
- 各ビューを分析して自動でダークカラーに変えてくれる機能
- 先述の開発者向けオプションを使った確認では、こちらがシミュレートされる
res/values-night/themes.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:forceDarkAllowed">true</item>
</style>
- 自動で変えたくないビューには、AppTheme以外のstyleを用意して適用すればよい
Androidのダークモードサポートは色々手厚い!
- より詳しく知りたい場合、こちらを参照
WebViewの場合は?
- Web側CSSで対応するらしい(StackOverflowより)
まとめ
- ダークモードは目とバッテリーに優しく、集中できる!
- iOSは2020/04まで(03末?)にダークモードを対応するか、一時しのぎでLightに固定しなければならない
- まずは動かしてみないと修正規模がわからない
 
- Androidはフォースダークで対応するのが手っ取り早そう
最後に大事なこと
- ダークモード対応はエンジニアファーストで提案しよう!
- 顧客やPMは、iOS SDKの事情でダークモード対応が必要なんて知る由もない
 
- 工数削減のために、自動調整してくれるシステムカラーは最大限活用しよう!
- 活用すれば、20画面あっても半日で終わるから怖くない(ヤバいAppは知りません)
 
- デザイナーにも必要な情報を公開しよう!
- 一言「ダークモード版の素材と指示書お願いします」で受けてくれるデザイナーは奇跡の存在です(個人の所感)
 
やっぱり言わせてください
参考
- Use Dark Mode on your iPhone, iPad, or iPod touch
- How to use Dark Mode on your Mac
- The Benefits of Dark Mode: Why should you turn off the lights?
- ダークテーマ | Android デベロッパー | Android Developers
- Dark Mode - How to support Dark Mode for iOS 13 using Xcode
- 実践 iOS13ダークモード対応
- Android10の強制ダークモードは割としっかりダークしてくれる





