dark mode 小まとめ


そこいらに散らばってる話ばかりなのですが、しばらくしたら忘れてまた探すのが面倒そうなので、
iOS13(TVとかは10あたり)からのダークモードの小まとめです。

dark modeを使用しない

推奨はしてきますが、都合よく白や黒ベースのデザインを用意するのも大変ですし、
対応しないってのもアリだと思います。
Info.plistにUIUserInterfaceStyleをLightで追加します。

対応しないのなら想定外の色変わりを防止するために、iOS13/Xcode11以降でコンパイルするならつけておいたほうがよいです。

    <key>UIUserInterfaceStyle</key>
    <string>Light</string>

ここからは仕方なくdark modeに対応するとしてのお話。

iOS13で追加された色を使う

dark modeに対応したcolorを用いれば自動的に対応されます。
名称についてはドキュメントを参考したほうが良いです。

https://developer.apple.com/documentation/uikit/uicolor/ui_element_colors
https://developer.apple.com/documentation/uikit/uicolor/standard_colors

view.backgroundColor = UIColor.systemBackground

って感じですね。

dark,lightでのそれぞれの色の値を下部に添付しておきます。
ちなみにiOS13で追加なので、iOS12以下では使用できません。

xcassetsでcolor setを使う

システムで用意されていない色は別途用意しなければなりませんが、互換性の点やコード/Storyboardなどでの可用性を考慮するとxcassetsでcolor setを追加して、これで管理するのがお手軽です。

color set自体はiOS11から使用できます。
storyboardなどでの色指定にもcolor setを使用できます。
dark modeの値は上位互換で追加され、iOS11,12で実行した場合、通常色のみ使用されます。
color set自体はjsonファイルですので、何らかのグラフィックツールなどで色を持ってくる場合もscript等でお手軽に追加できます。GUIでhexcolorの指定などもできるようになってます。
xcassetではフォルダを作ると一覧しやすいです。

コードで使用する場合も互換性を気にすることなく、 UIColorの init(named:) にて使用できます。

extension UIColor {
    static let appLabel: UIColor = UIColor(named: "appLabel") ?? .purple
    static let appBackground: UIColor = UIColor(named: "appBackground") ?? .purple
    static let appSecondaryLabel: UIColor = UIColor(named: "appSecondaryLabel") ?? .purple
}

こんな感じでコードに色関連を書いておけば、自動補完も効くので便利です。

ちなみに画像もxcassetsでdark mode用の追加ができます。

コードだけで両色対応

UIColorの
init(dynamicProvider: @escaping (UITraitCollection) -> UIColor)
ですね。

let c = UIColor {
  $0.userInterfaceStyle == .dark ? UIColor(white: 0.9, alpha: 1) : UIColor(white: 0.9, alpha: 1)
}

色々省略効きすぎやそれ

webviewでの対応

基本的にwebの内容自体までdark modeに対処する必要はないかと思いますが、
WkWebViewではdark modeかの判定値は入っているので、cssにての対処でOKです。

@media (prefers-color-scheme: dark) でstyleを入れればOKです。

@media (prefers-color-scheme: dark) { 
body { background-color: black; color: white;} 
a:link { color: skyblue;}

どうしても後付でやるなら func webView(_ webview: WKWebView, didFinish _: WKNavigation!) あたりでjavascriptを投げ込みます。

let cssString = "@media (prefers-color-scheme: dark) { body { background-color: black; color: white;} a:link { color: skyblue;} "
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webview.evaluateJavaScript(jsString, completionHandler: nil)

確認

Xcodeでsimulator実行ならここですね。

systemで用意されている色と値

コードで書いて引っ張り出してみました。変更されていなければこのぐらいの値かと。

name light dark
systemRed #ff3b30 1.00 #ff453a 1.00
systemGreen #34c759 1.00 #30d158 1.00
systemBlue #007aff 1.00 #0a84ff 1.00
systemOrange #ff9500 1.00 #ff9f0a 1.00
systemYellow #ffcc00 1.00 #ffd60a 1.00
systemPink #ff2d55 1.00 #ff375f 1.00
systemPurple #af52de 1.00 #bf5af2 1.00
systemTeal #5ac8fa 1.00 #64d2ff 1.00
systemIndigo #5856d6 1.00 #5e5ce6 1.00
systemGray #8e8e93 1.00 #8e8e93 1.00
systemGray2 #aeaeb2 1.00 #636366 1.00
systemGray3 #c7c7cc 1.00 #48484a 1.00
systemGray4 #d1d1d6 1.00 #3a3a3c 1.00
systemGray5 #e5e5ea 1.00 #2c2c2e 1.00
systemGray6 #f2f2f7 1.00 #1c1c1e 1.00
label #000000 1.00 #ffffff 1.00
secondaryLabel #3c3c43 0.60 #ebebf5 0.60
tertiaryLabel #3c3c43 0.30 #ebebf5 0.30
quaternaryLabel #3c3c43 0.18 #ebebf5 0.18
link #007aff 1.00 #0984ff 1.00
placeholderText #3c3c43 0.30 #ebebf5 0.30
separator #3c3c43 0.29 #545458 0.29
opaqueSeparator #c6c6c8 1.00 #38383a 1.00
systemBackground #ffffff 1.00 #000000 1.00
secondarySystemBackground #f2f2f7 1.00 #1c1c1e 1.00
tertiarySystemBackground #ffffff 1.00 #2c2c2e 1.00
systemGroupedBackground #f2f2f7 1.00 #000000 1.00
secondarySystemGroupedBackground #ffffff 1.00 #1c1c1e 1.00
tertiarySystemGroupedBackground #f2f2f7 1.00 #2c2c2e 1.00
systemFill #787880 0.20 #787880 0.20
secondarySystemFill #787880 0.16 #787880 0.16
tertiarySystemFill #767680 0.12 #767680 0.12
quaternarySystemFill #747480 0.08 #767680 0.08
lightText #ffffff 0.60 #ffffff 0.60
darkText #000000 1.00 #000000 1.00