padding に負の値(マイナス値)を指定すると便利な例

SwiftUI で余白を設定するためには padding を使用しますが、正の値だけでなく負の値を指定することもできます。

負の値を指定した場合の挙動

以下は padding正の値負の値 を指定した場合の挙動の違いです。

struct ContentView: View {
    var body: some View {
        VStack {
            // 正の値
            HStack(spacing: 0) {
                box(.red).padding(8)
                box(.blue).padding(8)
            }
            // 負の値
            HStack(spacing: 0) {
                box(.red).padding(-8)
                box(.blue).padding(-8)
            }
        }
    }

    func box(_ color: Color) -> some View {
        color.opacity(0.3)
            .frame(width: 100, height: 100)
            .border(color)
    }
}


負の値を指定した場合、スクリーンショットのように正の値を指定した場合と反対方向、いわば 余白を削る ような挙動になります。

特定の要素だけ余白を無視したいケース

コンテナ全体に余白を設けつつ、 一部のコンテンツだけ余白を無視する ようなレイアウトを実現したいケースはそれなりに多いのではないでしょうか。

例えば、以下のように縦積みをベースとして、横スクロール可能なコンテンツ部分だけを はみ出させる レイアウトを考えてみます。



正攻法で行く場合、横スクロールの部分以外に padding で余白を適用する形になるでしょう。

struct ContentView: View {
    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(alignment: .leading, spacing: 24) {
                    section(title: "SwiftUI", summary: "...")
                        .padding(.horizontal, 20) // ✅ 余白

                    ScrollView(.horizontal) {
                        HStack {
                            box(.red, text: "VStack")
                            box(.blue, text: "HStack")
                            ...
                        }
                        .padding(.horizontal, 20) // スクロールコンテンツの余白
                    }
                    // 💡 ここだけ余白を設定しない

                    section(title: "Swift", summary: "...")
                        .padding(.horizontal, 20) // ✅ 余白

                    section(title: "SwiftData", summary: "...")
                        .padding(.horizontal, 20) // ✅ 余白
                }
            }
        }
    }
    
    func section(title: String, summary: String) -> some View {
        VStack(alignment: .leading, spacing: 16) {
            Text(title)
                .font(.title)
            Text(summary)
                .frame(maxWidth: .infinity, alignment: .leading)
        }
    }

    func box(_ color: Color, text: String = "") -> some View {
        color.opacity(0.3)
            .frame(width: 100, height: 100)
            .border(color)
            .overlay {
                Text(text)
            }
    }
}

こうした場合、同じ余白を設定するコードが分散してしまい、可読性やメンテナンス性を損なうケースもあります。(この例では section 関数内で padding を設定すれば共通化できますが、実際のプロダクトでは別々のコンテンツになるケースが多いでしょう)

視覚的な認識、あるいはレイアウト設計としても、

  1. 全体的に余白を設けつつ
  2. 横スクロール部分は余白を無視する

という捉え方のほうが自然に感じられる人が多いのではないでしょうか。

paddingに負の値を利用する

このようなケースでは、paddingに負の値を利用すると可読性・メンテナンス性を高められるかもしれません。

struct ContentView: View {
    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(alignment: .leading, spacing: 24) {
                    section(title: "SwiftUI", summary: "...")

                    ScrollView(.horizontal) {
                        HStack {
                            box(.red, text: "VStack")
                            box(.blue, text: "HStack")
                            ...
                        }
                        .padding(.horizontal, 20)
                    }
                    .padding(.horizontal, -20) // 💡 2. ここだけ余白を無視

                    section(title: "Swift", summary: "...")
                    section(title: "SwiftData", summary: "...")
                }
                .padding(.horizontal, 20) // ✅ 1. 全体の余白を設定
            }
        }
    }
}

まとめ

通常 padding は余白を設けるためのものですが、負の値を設定することで ”余白を削る” ような挙動をさせることもできます。

コンテナ全体に一定の余白を設けつつ、一部のコンテンツだけ余白を無視したいケースなどで利用すると、可読性やメンテナンス性の向上が期待できるかもしれません。