# Shrink Images for Accessibility in SwiftUI

Have you ever built a screen layout where there's a big `Image` above a couple of `Text` views? There's a good chance that you have because this layout pattern is commonly used in places like app intro screens and onboarding screens. Something kind of like this:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1708458260975/cd861164-742a-4527-a5de-ce0ec93b17f7.png align="center")

There are often more elements on the screen than what my screenshot shows, but I want to keep this demo simple. 😊

The most recent time I was building screens like that, I was testing how the layout responded to Dynamic Type (i.e. bigger/smaller device font size setting). And it was in that exact moment when I realized that the most important part of my layout was the ***copy*** being shown in the `Text` views and ***not*** the `Image`. Because the images－in my specific situation－did not provide any informational value to the user. And I really wanted the user to be able to focus on reading the *text* without having the *image* get in the way when using larger Dynamic Type sizes. With this realization, my brain immediately thought, "OK, what I need to do is leverage Dynamic Type to ***shrink*** the height of the **image** as the Dynamic Type size ***grows***." I had actually never thought about doing this before, and I also don't think it's a documented approach in the [HIG](https://developer.apple.com/design/human-interface-guidelines) or anything, but it seemed to make sense in *my* situation at the time and I already knew the exact tools to use in SwiftUI to make it a reality. So I decided to go ahead with it. And that's the approach I wanted to explore in today's article!

In order to accomplish this, we only need to use 3 things:

1️⃣. The awesome `Environment` variable called `dynamicTypeSize` to access the user's current font size;

```swift
@Environment(\.dynamicTypeSize) private var currentDynamicTypeSize
```

(I love how easily we can access Dynamic Type information! 😃)

2️⃣. A `@State` property to hold a calculated image height－based on the `currentDynamicTypeSize`;

```swift
@State private var calculatedImageHeight: Double = .zero // arbitrary initial value
```

3️⃣. Somewhere to `switch` on the `currentDynamicTypeSize`, like the `.onChange` modifier or the `.onAppear` modifier (I chose `.onChange`, but you do you), where we can calculate and set the `calculatedImageHeight`.

```swift
.onChange(of: currentDynamicTypeSize, initial: true, { _, newValue in
    switch newValue {
        ...
        // case .small, .medium, .large － etc.
        // Calculate and set the image height here
    }
})
```

And with those 3 key things, all we have left to do is calculate a *height* based on the different Dynamic Type sizes and then use it on the `Image`! To do that, we can let Xcode auto-fill in all the `case`s in the `switch` statement so we can see all the possible Dynamic Type sizes, and then do a quick little multiplication arithmetic to come up with a value for `calculatedImageHeight`.

The end goal is to have the `calculatedImageHeight` be a certain *percentage* of a *predetermined* base image height. Let's choose `268` for this demo. (e.g. if we want the *calculated* height to be 75% of 268, that's `0.75 * 268`) So, we can choose the Dynamic Type sizes that fit our particular situation, decide on a "scale factor" percentage for each case, then multiply `baseImageHeight` by the `scaleFactor`—and that's our `calculatedImageHeight`! Here's an example of how that could look:

```swift
.onChange(of: currentDynamicTypeSize, initial: true, { _, newValue in
    let scaleFactor: Double

    switch newValue {
    case .xSmall, .small, .medium, .large:
        scaleFactor = 1.0
    case .xLarge:
        scaleFactor = 0.9
    case .xxLarge:
        scaleFactor = 0.75
    case .xxxLarge:
        scaleFactor = 0.55
    default:
        scaleFactor = 0.3
    }

    let baseImageHeight = 268.0
    calculatedImageHeight = baseImageHeight * scaleFactor
})
```

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This is <strong><em>not </em></strong>an exhaustive list of every Dynamic Type size. These are sizes and values used for this demo. And, yep, you could totally put that <code>baseImageHeight</code> into a constant up near the <code>@State</code> variable, if you wanted to. Some people might like having it near the calculation, while others might like it up top near the related <code>calculatedImageHeight</code> property. I'm not picking a side here. This is nice for the demo, so let's not worry about it, k?</div>
</div>

Notice, as the Dynamic Type size gets ***bigger***, we use ***smaller*** percentages: 90%, down to 75%, down to 55%, and then to 30%. For this demo, I decided to cap the scaling off after `.xxxLarge` by putting 30% into the `default` case. So in the end, any Dynamic Type size ***smaller*** than `.xLarge` uses 100% of the base image height; anything ***bigger*** than `.xxxLarge` uses 30% of the base image height; and a few other percentages for the cases in between.

Now we're ready to apply `calculatedImageHeight` to the `Image` and see what happens!

```swift
Image(.balloons)
    .resizable()
    .scaledToFit()
    .frame(maxHeight: calculatedImageHeight) // 🎉 ✅
```

And hey, it works! Here's the result as a GIF:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1708461349796/d4567e3c-ebec-4faf-ad30-aef78d603422.gif align="center")

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Play around with the <code>scaleFactor</code> percentages to see what feels best to you. These example percentages are for demo purposes.</div>
</div>

I understand that there's a chance another approach exists to achieve this exact same thing. 😄 I do think, though, that this approach is a fun way to leverage Dynamic Type to achieve a specific－and hopefully *improved*－user experience.

That's all! See ya later, rollerblader!

Come say "Hi!" on [Twitter](https://twitter.com/ScottSmithDev) or [Mastodon](https://mastodon.social/@ScottSmithDev)! Or don't. 😄
