How to Make Text in a UIVisualEffectView Readable on Any Background

Whatever your personal feelings about blurred backgrounds (I happen to like them a lot, in general), there’s no denying it fits the current Apple aesthetic. Ideally, blur and vibrancy add a subtle liveliness to the UI.

Unfortunately, as we recently discovered, they can also make your text unreadable.

Wanting to add a little polish to a utilitarian data display that floats over user content, we decided to add a blur effect.

Here’s the code:

// blur
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
blurView.clipsToBounds = YES;
blurView.layer.borderColor = [[UIColor blackColor] colorWithAlphaComponent:0.4f].CGColor;
blurView.layer.borderWidth = 1.0;
blurView.layer.cornerRadius = 6.0;

// label
UILabel *label = [[UILabel alloc] init];
label.textColor = [UIColor colorWithWhite:0.4f alpha:1.0f];

// add the label to effect view
[blurView.contentView addSubview:label];

And here’s the result:

Original, legible.

This was all well and good until we opened a document with a black background.

Original on black

Right! We forgot the vibrancy! Vibrancy magically makes everything legible on blur, right? You do have to add a whole extra view (and be careful to create it properly from the blur effect), but the code really isn’t bad:

// blur
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];  // or UIBlurEffectStyleDark
UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
blurView.clipsToBounds = YES;
blurView.layer.borderColor = [[UIColor blackColor] colorWithAlphaComponent:0.4f].CGColor;
blurView.layer.borderWidth = 1.0;
blurView.layer.cornerRadius = 6.0;

// vibrancy
UIVibrancyEffect *vibrancyEffect = [UIVibrancyEffect effectForBlurEffect:blurEffect];
UIVisualEffectView *vibrancyView = [[UIVisualEffectView alloc] initWithEffect:vibrancyEffect];
[blurView addSubview:vibrancyView];

// label
UILabel *label = [[UILabel alloc] init];
// text color doesn’t matter when it’s vibrant

// make sure to add the label to the vibrancy effect view now, not the blur view
[vibrancyView.contentView addSubview:label];

This definitely looked better:

Vibrant, on black.

I was quite pleased with this until I opened the document with the white background again…

Vibrant, on white

It was now obvious that we couldn’t win. Even if we analyzed the background color and dynamically choose UIBlurEffectStyleLight or UIBlurEffectStyleDark, it was easy to create a document that would defeat either option.

Vibrant on black and white, two options.

On the cusp of giving up and reverting to the boring opaque white background we’ve always used in these situations before, rereading Eric D. Kennedy’s excellent synopsis of methods for overlaying text on images prompted an idea.

Not vibrant on all

It’s a stunningly simple fix. Just set the background color of the UIVisualEffectView (the view itself, not the contentView) to a partially opaque white. And, crucially, skip the vibrancy effect for the text. (As an extra flourish, make the text color black with 70% opacity so the background can show through just a little. And we made the border color black at 40% opacity so it doesn’t compete with the text, which is what you’ve seen in all these examples, but wasn’t something we hit upon until the end.)

// blur
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
blurView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.60];
blurView.clipsToBounds = YES;
blurView.layer.borderColor = [[UIColor blackColor] colorWithAlphaComponent:0.4f].CGColor;
blurView.layer.borderWidth = 1.0;
blurView.layer.cornerRadius = 6.0;

// label
UILabel *label = [[UILabel alloc] init];
label.textColor = [[UIColor blackColor] colorWithAlphaComponent:0.7f];
[label sizeToFit];

// add the label to effect view
[blurView.contentView addSubview:label];

It’s worth noting that the result is a lot subtler than vibrancy on well-behaved, colorful documents (vibrancy on the left, our partial-white solution on the right):

Colors vibrant and not.

It might even be boring. But the blur definitely adds a little something and the text is way more legible.

In sum, be cautious when using UIVisualEffectsViews over backgrounds you don’t control, but don’t despair. Adding a semi-opaque background color to the effect view might be all you need to get legible text you can count on.