この記事はand factory.inc Advent Calendar 2025 22日目の記事です。
昨日は nqnq さんの 「Agent Skills導入とベストプラクティス」 でした ![]()
はじめに
Jetpack Compose の Material2 から Material3 へ移行した際、
ダイアログやカードの背景色が「想定と違う色」になったことはありませんか?
Material3 では、エレベーション(高さ)を影だけでなく「色のトーン差」でも表現します。
この仕組みを支えているのが tonalElevation です。
本記事では、
・tonalElevation が何をしているのか、
・なぜ Material3 では背景色が変わって見えるのか
を整理してみます。
tonalElevationとは
tonalElevation とは、「トーン(色合い)によるエレベーション表現」 です。
Material2 が主に影(ドロップシャドウ)で奥行きを表現していたのに対して、Material3 は 色のトーン差でも階層を表現します。
具体的には、コンポーネントの背景色に対してテーマの surfaceTint を半透明で重ねることで、エレベーション(高さ)を表現します。
簡単に言えば 「影ではなく、色の変化で奥行きを示す」 仕組みです。
surfaceTint
Material3では、テーマの ColorScheme に surfaceTint という色が追加されています。
デフォルトではこの surfaceTint に、テーマのアクセントカラー(多くの場合 primary)が使われます。
そしてtonalElevation を上げると、 surfaceTint がベースの surface に薄く重なり、結果として背景色が変化します。
この仕組みについては、Composeでは MaterialTheme.colorScheme.surfaceColorAtElevation で確認できます。
@Stable
fun ColorScheme.surfaceColorAtElevation(
elevation: Dp,
): Color {
if (elevation == 0.dp) return surface
val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f
return surfaceTint.copy(alpha = alpha).compositeOver(surface)
}
この関数は 「surface に surfaceTint を一定の透明度で重ねた色」を返します。
つまり tonalElevation は、ざっくり言うと 「surface の上に surfaceTint を薄く被せる量(= 色の変化量)」 です。
tonalElevation の値が大きくなるほど、surfaceTint の影響が強くなり、
背景色が少しずつ「濃く」見えるようになります。
Material2との違い
Material2 では、主に 影(ドロップシャドウ) で高さを表現していました。
ただ、ダークテーマだと背景が暗いため、影が目立ちにくく、要素の階層差が分かりづらいことがあります。
Material3 ではこの問題を解消するために、シャドウだけに頼らず 色の違い(トーン差)でも階層を表現する ようになりました。
ダークテーマでも層の違いが認識しやすくなる、というメリットがあります。
tonalElevation と shadowElevation の違い
簡単にまとめると
tonalElevation
・色の重ね合わせで奥行きを表現する
・背景色に色味を足して「持ち上がり感」を出す
・「色で奥行きをつける」イメージ
shadowElevation
・影 (ドロップシャドウ) を描画して奥行きを表現する
・コンポーネントの周囲にぼかしの影を落とし、要素が浮いているように見せる
・「光と影で奥行きをつける」イメージ
Material3 では、トーン差とドロップシャドウは用途に応じて併用されることもあります。
まとめ
Material3 では、エレベーションは影だけでなく、色のトーン差でも表現されるようになりました。
tonalElevation によって背景色が少し濃く見えることがありますが、これは Material3 の設計によるものです。
色が変わったと感じたときは、「tonalElevation がどんな役割を持っているのか」を思い出してみると、理解しやすくなると思います。
明日の and factory.inc Advent Calendar 2025 は chitomo12 さんです ![]()

