【SwiftUI】UIButtonで理解するUIデザイントレンド
※ この記事は ZOZO Advent Calendar 2022 カレンダーVol.4の10日目の記事になります。
こんにちは、 ogijun です。
Swiftをコードでざっくり理解第3弾、今回はUIデザインについて書いていきます。
iOSのデザイントレンドといえば、僕の中では立体的で実写的なデザインがフラットなデザインに変わったiOS7が強く印象に残っています。
最近のUIデザインは比較的フラットデザインのエッセンスを継承しているのでiOS7ほどの衝撃はありませんが、実は少しずつトレンドは移り変わっていることをご存じでしょうか。
今回は、今までのUIデザイントレンドを時系列順にUIButtonを実装しながら特徴を理解してみます。
※ 各デザインの実装例はgithubにて公開中です。参考にどうぞ。
スキューモーフィズム
スマートフォンが登場した頃によく採用されていたUIデザインはスキューモーフィズムでした。
スキューモーフィズム(リッチデザイン)とは、ユーザに馴染みのないものの外見を馴染みのあるものにすることにより直感的に理解できるようにするデザインのことを指します。(参考: スキューモーフィズム(スキューモフィック))
iPhoneが発表された当時は「ガラスの画面上をタップしてボタンを押す」といった動作に慣れているユーザーは少なく、現実にあるような立体的なボタンのデザインにすることで「これはボタンであり、押すことができる」というアフォーダンスを示しています。
この頃のUIButtonは外枠に凹みがあるような色をのせ、上部分が少し明るい色で立体感を演出していました。
また、Labelにも少し影がかかっており、今実装するとこんなに大変です。
実装例
struct SkeuomorphismButton: View {
// 上半分の光沢感をGradientで表現
let gradientView: LinearGradient = LinearGradient(gradient: Gradient(colors: [Color.init(red: 1, green: 0, blue: 0, opacity: 0.55), Color.init(red: 1, green: 0, blue: 0, opacity: 0.65)]), startPoint: .top, endPoint: .center)
var body: some View {
Button(action: {
print("button tapped")
}){
Text("Skeuomorphism Button")
.font(.system(size: 25))
.fontWeight(.bold)
// shadowで凹みを表現
.shadow(color: .black, radius: 0, x: 0, y: -1)
.foregroundColor(.white)
.padding()
.background( ZStack {
RoundedRectangle(cornerRadius: 16)
.foregroundColor(.white)
// 上半分
RoundedRectangle(cornerRadius: 16)
.foregroundStyle(gradientView)
// 下半分
RoundedRectangle(cornerRadius: 16)
.trim(from: 0, to: 0.5)
.foregroundColor(.red)
})
// 外枠
.overlay(RoundedRectangle(cornerRadius: 16)
.stroke(.gray, lineWidth: 4)
// shadowで凹みを表現
.shadow(color: .black, radius: 0, x: 0, y: -1)
)
}
}
}
出来上がったデザイン
この頃の特徴は太い外枠があることでしょう。後述する他のデザインに比べると、スキューモーフィズムデザインのボタンが一番押し込んだときに深く押し込めそうな見え方をしています(筆者の個人的に)。
上記の実装では、ボタンの上半分と下半分の微妙な色の違い(光沢感)を表現するためにZStackでRoundedRectangleを重ね、下半分は上半分をtrimすることで実現しました。
フラットデザイン
スキューモーフィズムによってスマートフォンの使い方に慣れてきたiOS7から、Appleがフラットデザインを採用するようになり世界中のアプリやWebサイトが一気にフラットデザインへと変わりました。
フラットデザインでは、ボタンによっては背景色や枠のないLabelだけのボタンや、影のない枠だけのボタンが使われるようになりました。
フラットデザインのメリットとして大きいのは、シンプルな構成になることで実装のしやすさが上がることでしょう。スキューモーフィズムのように複雑に陰影を組まなくてもよくなることで、エンジニアだけでも簡単に実装できるようになったり、以下のようにコード量が大幅に減ってデザインを当てる効率が高くなるなどの恩恵を受けられました。
実装例
struct FlatDesignButton: View {
var body: some View {
Button(action: {
print("button tapped")
}){
Text("Flat Design Button")
.font(.system(size: 25))
.fontWeight(.ultraLight)
.foregroundColor(.blue)
.padding()
.border(.blue, width: 0.5)
}
}
}
出来上がったデザイン
実際にコードを見てみると、フラットデザインのボタンが今回挙げているデザインの中でも最も少ないコード量で実装できることがわかります。
iOS7の時代はultraLightやlightといった軽めのfontWeightが使われているのも特徴でした。
スキューモーフィズムのときのようにボタンであることが一目では分からなくなりましたが、文字色を青色にすることでハイパーリンクのように「押せるものである」ことを表現しています。
ニューモーフィズム
iOS 7がリリースされたのは2013年のことですが、そこからはフラットデザインのデメリットを改良したデザイン(いわゆるフラットデザイン2.0(参考: フラットデザイン2.0は2018年のトレンドとなるか)、マテリアルデザイン(参考: Material Design) 等)が主流となりました。 iOSも8,9,10,11とだんだんとのっぺりした平面的なUIから少し立体的な部分も増えてきていることがわかります。
2020年ごろから、フラットデザインとは別種のニューモーフィズムというデザインが台頭してきました。
ニューモーフィズムは背景と同色のボタンを背景から押し出されたように影を使って表現するのが特徴で、ミニマルな印象を抱きます。
ベースとなる色を決めれば、あとは明度を上げたり下げたりするだけでボタンを作成できるため、フラットデザインほどシンプルではないものの比較的簡単に実装が可能です。
実装例
struct NeumorphismButton: View {
let bgColor = Color.init(red: 0.92, green: 0.93, blue: 0.94)
let grayColor = Color.init(white: 0.8, opacity: 1)
var body: some View {
ZStack {
// whiteの影を使うため若干グレーがかった背景を使う
bgColor.ignoresSafeArea()
Button(action: {
print("button tapped")
}){
Text("Newmorphism Button")
.font(.system(size: 25, weight: .semibold, design: .rounded))
.foregroundColor(.gray)
.padding()
.background(
RoundedRectangle(cornerRadius: 30)
.foregroundStyle(bgColor)
// 上側の凸をshadowで表現
.shadow(color: .white, radius: 10, x: -7, y: -7)
// 下側の凸をshadowで表現
.shadow(color: grayColor, radius: 10, x: 7, y: 7)
)
.overlay(
RoundedRectangle(cornerRadius: 30)
.stroke(.gray, lineWidth: 0)
)
}
}
}
}
出来上がったデザイン
個人的には一番好きなデザインですが、結局ニューモーフィズムデザインを採用したアプリはWebサイトは少ない印象があります。
その一番の理由としては、ユーザビリティの観点でパッと見た時に使い辛いことが挙げられるでしょう。
また、ベース色として白色(〜淡いグレー色)が使われることが多く、UIにオリジナリティを持たせることが難しいこともデメリットであると考えられます。
グラスモーフィズム
2020年末ごろからは、Mac OS v11 BigSurが採用したことでグラスモーフィズムというデザインが主流になっていきました。
グラスモーフィズムとは、要素の背景を磨りガラスを通して覗いているようなぼかしを入れるデザインのことで、透明度によってレイヤーの重なりも表現されることが特徴です。
磨りガラスのような要素を作るということは、背景には色があることが前提になります。これまでの単色だったフラットデザインやニューモーフィズムから一転して、グラスモーフィズムでは鮮やかなグラデーションが背景に使われることが多くなりました。
実装例
struct GlassmorphismButton: View {
let frontGradientView: LinearGradient = LinearGradient(gradient: Gradient(colors: [.yellow, .red]), startPoint: .topLeading, endPoint: .bottomTrailing)
let backGradientView: LinearGradient = LinearGradient(gradient: Gradient(colors: [.red, .blue]), startPoint: .topLeading, endPoint: .bottomTrailing)
var body: some View {
ZStack {
Circle()
.frame(width: 200, height: 200)
.offset(x: 50, y: 50)
.foregroundStyle(backGradientView)
Circle()
.frame(width: 200, height: 200)
.offset(x: -50, y: -50)
.foregroundStyle(frontGradientView)
Button(action: {
print("button tapped")
}){
Text("Glassmorphism Button")
.font(.system(size: 25, weight: .semibold, design: .default))
.foregroundColor(.white)
.padding()
.background(
RoundedRectangle(cornerRadius: 30)
// ぼかし効果
// .ultraThinMaterialはiOS15から対応
.foregroundStyle(.ultraThinMaterial)
// ドロップシャドウで立体感を表現
.shadow(color: .init(white: 0.4, opacity: 0.4), radius: 5, x: 0, y: 0)
)
.overlay(
// strokeでガラスの縁を表現
RoundedRectangle(cornerRadius: 30)
.stroke(Color.init(white: 1, opacity: 0.5), lineWidth: 1)
)
}
}
}
}
出来上がったデザイン
ボタンの実装を見てみると、RoundedRectangle.foregroundStyleにiOS15から対応したMaterial structureの .ultraThinMaterial
を適用することでblur表現を実現しています。
Material structureを使わない場合、白背景にOpacityを設定することで同様の表現が可能になります。
また、ポイントとしては縁に1ptの白色の stroke
を設定しています。これによりガラス感・ボタン感をより増すことができますね。
クレイモーフィズム
2022年からは、3Dオブジェクトをふんだんに使ったクレイモーフィズムというデザイントレンドが現れています。
クレイモーフィズムは、粘土のようなマットな質感を持ち、丸みのある3D要素を特徴としたデザインです(参考: 新しいUIデザインのトレンド「クレイモーフィズム」)。
zennも比較的クレイモーフィズムのような柔らかいUIが採用されていますね。
3D要素は複雑なものの場合、BlenderやMayaなどのCGソフトによって作成されたものを適用させる場合が多く、世界観をつけるUIデザインとしての難易度はこれまでのデザインよりも高い印象があります。
フラットデザイン等とは対照的に陰影表現が比較的強く、ボタン自体にも丸みを帯びたような光沢感を乗せる必要があります。
実装例
struct ClaymorphismButton: View {
let bgColor = Color.init(red:0.90, green: 0.92, blue: 0.98)
let buttonColor = Color.init(red: 0.38, green: 0.28, blue: 0.86)
let lightColor = Color.init(red: 0.54, green: 0.41, blue: 0.95)
let shadowColor = Color.init(red: 0.25, green: 0.17, blue: 0.75)
let radius = CGFloat(25)
var body: some View {
ZStack {
bgColor.ignoresSafeArea()
Button(action: {
print("button tapped")
}){
Text("Claymorphism Button")
.font(.system(size: 20, weight: .semibold, design: .default))
.foregroundColor(.white)
.padding(.horizontal, 35)
.padding(.vertical, 20)
.background(
RoundedRectangle(cornerRadius: radius)
.fill(
// shadowでボタン上部に光沢を持たせる
// .innerはiOS16から対応
.shadow(.inner(color: lightColor, radius: 6, x: 4, y: 4))
// shadowでボタン下部に影を落とす
.shadow(.inner(color: shadowColor, radius: 6, x: -2, y: -2))
)
.foregroundColor(buttonColor)
// ボタンのshadowはボタンの色に合わせる
.shadow(color: buttonColor, radius: 20, y: 10)
)
}
}
}
}
出来上がったデザイン
注意点としては、 .shadow(.inner(color()))
はiOS16からのみ対応である点です。
.inner
プロパティを持つShadowStyle structureを .shadow
に適用させることで、要素の内側に影(や光沢)を持たせることが可能になります。
iOS15未満の場合、内側に影を落とす場合は .overlay
で下記のようにすると似たような表現を作ることができました。
.overlay(
RoundedRectangle(cornerRadius: radius)
.stroke(.white, lineWidth: 4)
.shadow(color: .white, radius: 6, x: 5, y: 5)
.clipShape(RoundedRectangle(cornerRadius: 25))
.shadow(color: .gray, radius: 6, x: -5, y: -5)
.clipShape(RoundedRectangle(cornerRadius: radius)
)
)
ただし、この実装では .stroke(.white, lineWidth: 4)
で枠線をひき、その影をボタン内に落とすことで陰影を表現しているため、ボタン自体に影を落とすと白い枠線が浮き出てしまいます。
.stroke
を引かずにボタン内に影を落とすには少し複雑な実装が必要になるため、 .inner
が使えるようになったのはだいぶありがたいですね。
まとめ
今回はiOSが発表されたときから採用されているスキューモーフィズムを始め、5種類のデザイントレンドを実際にSwiftUIで表現してみました。
ボタン一つでもここまで与える印象が変わるのは面白いですね。 特にクレイモーフィズムはSwiftUIで実装している記事がなかったので、この記事が少しでも役に立てば嬉しいなと思います。
デザイントレンドを意識しながら、自分だけの世界観をもったアプリを作りましょう!
改めて、今回の記事で作成したコードはgithubで公開中です。参考にどうぞ。
Discussion