Flutter ImageFiltered Localization: Blur and Visual Filters for Multilingual Apps
ImageFiltered applies image filter effects like blur, dilation, and erosion to its child widget. When combined with localization, ImageFiltered creates accessible blur overlays, privacy masks, focus effects, and loading states that adapt to different languages and provide appropriate accessibility descriptions. This guide covers comprehensive strategies for localizing ImageFiltered widgets in Flutter multilingual applications.
Understanding ImageFiltered Localization
ImageFiltered widgets require localization for:
- Privacy overlays: Blurred content with localized unlock messages
- Focus effects: Background blur with focused content descriptions
- Loading states: Blurred placeholders with loading announcements
- Modal backdrops: Blur effects with accessible dialog descriptions
- Depth of field: Emphasizing content with visual hierarchy
- Accessibility labels: Describing blur effects for screen readers
Basic ImageFiltered with Localized Content
Start with a simple blur overlay example:
import 'package:flutter/material.dart';
import 'dart:ui';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class LocalizedImageFilteredDemo extends StatelessWidget {
const LocalizedImageFilteredDemo({super.key});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(title: Text(l10n.imageFilterDemoTitle)),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.blurEffectsDescription,
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 24),
Expanded(
child: Center(
child: Stack(
alignment: Alignment.center,
children: [
// Blurred background
ClipRRect(
borderRadius: BorderRadius.circular(16),
child: ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
child: Image.network(
'https://picsum.photos/400/300',
fit: BoxFit.cover,
width: double.infinity,
height: 250,
),
),
),
// Focused content overlay
Semantics(
label: l10n.blurredBackgroundAccessibility,
child: Container(
padding: const EdgeInsets.all(24),
margin: const EdgeInsets.all(32),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface.withOpacity(0.9),
borderRadius: BorderRadius.circular(12),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.photo_filter,
size: 48,
color: Theme.of(context).colorScheme.primary,
),
const SizedBox(height: 16),
Text(
l10n.focusedContentTitle,
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
l10n.focusedContentDescription,
textAlign: TextAlign.center,
),
],
),
),
),
],
),
),
),
],
),
),
);
}
}
ARB File Structure for ImageFiltered
{
"imageFilterDemoTitle": "Image Filters",
"@imageFilterDemoTitle": {
"description": "Title for image filter demo page"
},
"blurEffectsDescription": "Blur effects create visual depth and focus",
"blurredBackgroundAccessibility": "Blurred background image with focused content overlay",
"focusedContentTitle": "Featured Content",
"focusedContentDescription": "This content stands out against the blurred background"
}
Premium Content Blur
Create a paywall with blurred preview:
import 'package:flutter/material.dart';
import 'dart:ui';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class LocalizedPremiumBlur extends StatelessWidget {
final bool isPremium;
final Widget content;
final VoidCallback onUpgrade;
const LocalizedPremiumBlur({
super.key,
required this.isPremium,
required this.content,
required this.onUpgrade,
});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
if (isPremium) {
return content;
}
return Semantics(
label: l10n.premiumContentLockedAccessibility,
child: Stack(
children: [
// Blurred content preview
ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: IgnorePointer(child: content),
),
// Unlock overlay
Positioned.fill(
child: Container(
color: Colors.black.withOpacity(0.3),
child: Center(
child: Container(
margin: const EdgeInsets.all(32),
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 20,
offset: const Offset(0, 4),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.lock,
size: 48,
color: Theme.of(context).colorScheme.primary,
),
const SizedBox(height: 16),
Text(
l10n.premiumContentTitle,
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
l10n.premiumContentDescription,
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: onUpgrade,
icon: const Icon(Icons.star),
label: Text(l10n.upgradeButton),
),
const SizedBox(height: 8),
TextButton(
onPressed: () {},
child: Text(l10n.learnMoreButton),
),
],
),
),
),
),
),
],
),
);
}
}
class PremiumContentDemo extends StatefulWidget {
const PremiumContentDemo({super.key});
@override
State<PremiumContentDemo> createState() => _PremiumContentDemoState();
}
class _PremiumContentDemoState extends State<PremiumContentDemo> {
bool _isPremium = false;
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
title: Text(l10n.premiumDemoTitle),
actions: [
Switch(
value: _isPremium,
onChanged: (value) => setState(() => _isPremium = value),
),
],
),
body: LocalizedPremiumBlur(
isPremium: _isPremium,
onUpgrade: () => setState(() => _isPremium = true),
content: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.exclusiveArticleTitle,
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 16),
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
'https://picsum.photos/600/300',
width: double.infinity,
height: 200,
fit: BoxFit.cover,
),
),
const SizedBox(height: 16),
Text(
l10n.exclusiveArticleContent,
style: Theme.of(context).textTheme.bodyLarge,
),
],
),
),
),
);
}
}
Loading State Blur
Create a loading indicator with blur:
import 'package:flutter/material.dart';
import 'dart:ui';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class LocalizedLoadingBlur extends StatefulWidget {
final bool isLoading;
final Widget child;
final String? loadingMessage;
const LocalizedLoadingBlur({
super.key,
required this.isLoading,
required this.child,
this.loadingMessage,
});
@override
State<LocalizedLoadingBlur> createState() => _LocalizedLoadingBlurState();
}
class _LocalizedLoadingBlurState extends State<LocalizedLoadingBlur>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _blurAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
_blurAnimation = Tween<double>(begin: 0, end: 5).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
);
if (widget.isLoading) {
_controller.forward();
}
}
@override
void didUpdateWidget(LocalizedLoadingBlur oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.isLoading != oldWidget.isLoading) {
if (widget.isLoading) {
_controller.forward();
} else {
_controller.reverse();
}
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Stack(
children: [
AnimatedBuilder(
animation: _blurAnimation,
builder: (context, child) {
if (_blurAnimation.value == 0) {
return child!;
}
return ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: _blurAnimation.value,
sigmaY: _blurAnimation.value,
),
child: child,
);
},
child: widget.child,
),
if (widget.isLoading)
Positioned.fill(
child: Semantics(
label: widget.loadingMessage ?? l10n.loadingAccessibility,
child: Container(
color: Colors.black.withOpacity(0.1),
child: Center(
child: Card(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
const SizedBox(height: 16),
Text(
widget.loadingMessage ?? l10n.loadingMessage,
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
),
),
),
),
),
),
],
);
}
}
class LoadingBlurDemo extends StatefulWidget {
const LoadingBlurDemo({super.key});
@override
State<LoadingBlurDemo> createState() => _LoadingBlurDemoState();
}
class _LoadingBlurDemoState extends State<LoadingBlurDemo> {
bool _isLoading = false;
Future<void> _simulateLoad() async {
setState(() => _isLoading = true);
await Future.delayed(const Duration(seconds: 2));
if (mounted) {
setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(title: Text(l10n.loadingBlurDemoTitle)),
body: LocalizedLoadingBlur(
isLoading: _isLoading,
loadingMessage: l10n.savingChangesMessage,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.settingsTitle,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 16),
SwitchListTile(
title: Text(l10n.notificationsLabel),
value: true,
onChanged: (_) {},
),
SwitchListTile(
title: Text(l10n.darkModeLabel),
value: false,
onChanged: (_) {},
),
SwitchListTile(
title: Text(l10n.autoSaveLabel),
value: true,
onChanged: (_) {},
),
],
),
),
),
const Spacer(),
ElevatedButton(
onPressed: _simulateLoad,
child: Text(l10n.saveChangesButton),
),
],
),
),
),
);
}
}
Privacy Mask Blur
Create privacy-focused blur for sensitive content:
import 'package:flutter/material.dart';
import 'dart:ui';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class LocalizedPrivacyMask extends StatefulWidget {
final Widget child;
final bool isSensitive;
final bool initiallyRevealed;
const LocalizedPrivacyMask({
super.key,
required this.child,
this.isSensitive = true,
this.initiallyRevealed = false,
});
@override
State<LocalizedPrivacyMask> createState() => _LocalizedPrivacyMaskState();
}
class _LocalizedPrivacyMaskState extends State<LocalizedPrivacyMask> {
late bool _isRevealed;
@override
void initState() {
super.initState();
_isRevealed = widget.initiallyRevealed;
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
if (!widget.isSensitive || _isRevealed) {
return widget.child;
}
return Semantics(
label: l10n.sensitiveContentHiddenAccessibility,
child: GestureDetector(
onTap: () => setState(() => _isRevealed = true),
child: Stack(
alignment: Alignment.center,
children: [
ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: 15, sigmaY: 15),
child: widget.child,
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface.withOpacity(0.8),
borderRadius: BorderRadius.circular(20),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.visibility_off, size: 20),
const SizedBox(width: 8),
Text(l10n.tapToRevealLabel),
],
),
),
],
),
),
);
}
}
class BankAccountCard extends StatelessWidget {
final String accountNumber;
final String balance;
const BankAccountCard({
super.key,
required this.accountNumber,
required this.balance,
});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.account_balance,
color: Theme.of(context).colorScheme.primary,
),
const SizedBox(width: 8),
Text(
l10n.bankAccountLabel,
style: Theme.of(context).textTheme.titleMedium,
),
],
),
const SizedBox(height: 16),
Text(
l10n.accountNumberLabel,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 4),
LocalizedPrivacyMask(
child: Text(
accountNumber,
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontFamily: 'monospace',
),
),
),
const SizedBox(height: 16),
Text(
l10n.currentBalanceLabel,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
const SizedBox(height: 4),
LocalizedPrivacyMask(
child: Text(
balance,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.primary,
),
),
),
],
),
),
);
}
}
class PrivacyDemo extends StatelessWidget {
const PrivacyDemo({super.key});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(title: Text(l10n.privacyDemoTitle)),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.privacyDemoDescription,
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 24),
const BankAccountCard(
accountNumber: '1234 5678 9012 3456',
balance: '\$12,345.67',
),
],
),
),
);
}
}
Modal Dialog Blur
Create blurred background for modals:
import 'package:flutter/material.dart';
import 'dart:ui';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class LocalizedBlurredModal extends StatelessWidget {
final Widget child;
final VoidCallback onClose;
final String? title;
const LocalizedBlurredModal({
super.key,
required this.child,
required this.onClose,
this.title,
});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Stack(
children: [
// Blurred background
Positioned.fill(
child: GestureDetector(
onTap: onClose,
child: ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: Container(
color: Colors.black.withOpacity(0.3),
),
),
),
),
// Modal content
Center(
child: Semantics(
label: title ?? l10n.modalAccessibility,
child: Material(
borderRadius: BorderRadius.circular(16),
child: Container(
constraints: const BoxConstraints(
maxWidth: 400,
maxHeight: 500,
),
margin: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (title != null)
Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: Text(
title!,
style: Theme.of(context).textTheme.titleLarge,
),
),
IconButton(
onPressed: onClose,
icon: const Icon(Icons.close),
tooltip: l10n.closeModalTooltip,
),
],
),
),
Flexible(child: child),
],
),
),
),
),
),
],
);
}
}
class ModalBlurDemo extends StatefulWidget {
const ModalBlurDemo({super.key});
@override
State<ModalBlurDemo> createState() => _ModalBlurDemoState();
}
class _ModalBlurDemoState extends State<ModalBlurDemo> {
bool _showModal = false;
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(title: Text(l10n.modalBlurDemoTitle)),
body: Stack(
children: [
// Main content
ListView(
padding: const EdgeInsets.all(16),
children: [
Card(
child: ListTile(
leading: const Icon(Icons.person),
title: Text(l10n.profileSettingsLabel),
trailing: const Icon(Icons.chevron_right),
onTap: () => setState(() => _showModal = true),
),
),
const SizedBox(height: 8),
Card(
child: ListTile(
leading: const Icon(Icons.notifications),
title: Text(l10n.notificationSettingsLabel),
trailing: const Icon(Icons.chevron_right),
),
),
const SizedBox(height: 8),
Card(
child: ListTile(
leading: const Icon(Icons.security),
title: Text(l10n.securitySettingsLabel),
trailing: const Icon(Icons.chevron_right),
),
),
],
),
// Modal overlay
if (_showModal)
LocalizedBlurredModal(
title: l10n.editProfileTitle,
onClose: () => setState(() => _showModal = false),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
decoration: InputDecoration(
labelText: l10n.nameLabel,
border: const OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextField(
decoration: InputDecoration(
labelText: l10n.emailLabel,
border: const OutlineInputBorder(),
),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => setState(() => _showModal = false),
child: Text(l10n.cancelButton),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: () => setState(() => _showModal = false),
child: Text(l10n.saveButton),
),
],
),
],
),
),
),
],
),
);
}
}
Variable Blur Depth
Create depth-based blur effects:
import 'package:flutter/material.dart';
import 'dart:ui';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class LocalizedDepthBlur extends StatelessWidget {
final double blurAmount;
final Widget child;
final String depthLabel;
const LocalizedDepthBlur({
super.key,
required this.blurAmount,
required this.child,
required this.depthLabel,
});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
if (blurAmount == 0) {
return child;
}
return Semantics(
label: l10n.depthBlurAccessibility(depthLabel),
child: ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: blurAmount,
sigmaY: blurAmount,
),
child: child,
),
);
}
}
class DepthBlurDemo extends StatefulWidget {
const DepthBlurDemo({super.key});
@override
State<DepthBlurDemo> createState() => _DepthBlurDemoState();
}
class _DepthBlurDemoState extends State<DepthBlurDemo> {
int _focusedIndex = 1;
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final items = [
(l10n.cardBackground, 0.0, Colors.blue),
(l10n.cardMiddle, 0.0, Colors.green),
(l10n.cardForeground, 0.0, Colors.orange),
];
return Scaffold(
appBar: AppBar(title: Text(l10n.depthBlurDemoTitle)),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Text(
l10n.depthBlurInstructions,
style: Theme.of(context).textTheme.bodyLarge,
),
),
Expanded(
child: Center(
child: SizedBox(
width: 300,
height: 400,
child: Stack(
alignment: Alignment.center,
children: List.generate(3, (index) {
final distance = (index - _focusedIndex).abs();
final blurAmount = distance * 5.0;
final offset = (index - 1) * 30.0;
final scale = 1.0 - (distance * 0.1);
return Positioned(
top: 50 + offset,
child: GestureDetector(
onTap: () => setState(() => _focusedIndex = index),
child: LocalizedDepthBlur(
blurAmount: blurAmount,
depthLabel: items[index].$1,
child: Transform.scale(
scale: scale,
child: Card(
elevation: _focusedIndex == index ? 16 : 4,
child: Container(
width: 250,
height: 150,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
gradient: LinearGradient(
colors: [
items[index].$3,
items[index].$3.withOpacity(0.7),
],
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
items[index].$1,
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
_focusedIndex == index
? l10n.inFocusLabel
: l10n.outOfFocusLabel,
style: const TextStyle(
color: Colors.white70,
),
),
],
),
),
),
),
),
),
);
}),
),
),
),
),
Padding(
padding: const EdgeInsets.all(16),
child: SegmentedButton<int>(
segments: [
ButtonSegment(value: 0, label: Text(l10n.cardBackground)),
ButtonSegment(value: 1, label: Text(l10n.cardMiddle)),
ButtonSegment(value: 2, label: Text(l10n.cardForeground)),
],
selected: {_focusedIndex},
onSelectionChanged: (selected) {
setState(() => _focusedIndex = selected.first);
},
),
),
],
),
);
}
}
Complete ARB File for ImageFiltered
{
"@@locale": "en",
"imageFilterDemoTitle": "Image Filters",
"blurEffectsDescription": "Blur effects create visual depth and focus",
"blurredBackgroundAccessibility": "Blurred background with focused content overlay",
"focusedContentTitle": "Featured Content",
"focusedContentDescription": "This content stands out against the blurred background",
"premiumDemoTitle": "Premium Content",
"premiumContentLockedAccessibility": "Premium content is blurred and locked",
"premiumContentTitle": "Premium Content",
"premiumContentDescription": "Subscribe to unlock exclusive articles and features",
"upgradeButton": "Upgrade Now",
"learnMoreButton": "Learn More",
"exclusiveArticleTitle": "Exclusive Industry Insights",
"exclusiveArticleContent": "This exclusive content provides deep insights into industry trends and best practices. Premium members gain access to detailed analysis, expert interviews, and actionable strategies.",
"loadingBlurDemoTitle": "Loading Blur",
"loadingAccessibility": "Loading content",
"loadingMessage": "Loading...",
"savingChangesMessage": "Saving changes...",
"settingsTitle": "Settings",
"notificationsLabel": "Push Notifications",
"darkModeLabel": "Dark Mode",
"autoSaveLabel": "Auto-save",
"saveChangesButton": "Save Changes",
"privacyDemoTitle": "Privacy Mask",
"privacyDemoDescription": "Sensitive information is blurred for privacy. Tap to reveal.",
"sensitiveContentHiddenAccessibility": "Sensitive content is hidden. Tap to reveal.",
"tapToRevealLabel": "Tap to reveal",
"bankAccountLabel": "Bank Account",
"accountNumberLabel": "Account Number",
"currentBalanceLabel": "Current Balance",
"modalBlurDemoTitle": "Modal Dialog",
"modalAccessibility": "Modal dialog",
"closeModalTooltip": "Close",
"profileSettingsLabel": "Profile Settings",
"notificationSettingsLabel": "Notification Settings",
"securitySettingsLabel": "Security Settings",
"editProfileTitle": "Edit Profile",
"nameLabel": "Name",
"emailLabel": "Email",
"cancelButton": "Cancel",
"saveButton": "Save",
"depthBlurDemoTitle": "Depth of Field",
"depthBlurInstructions": "Tap a card to bring it into focus",
"depthBlurAccessibility": "{label} at depth level",
"@depthBlurAccessibility": {
"placeholders": {"label": {"type": "String"}}
},
"cardBackground": "Background",
"cardMiddle": "Middle",
"cardForeground": "Foreground",
"inFocusLabel": "In focus",
"outOfFocusLabel": "Out of focus"
}
Best Practices Summary
- Provide accessibility labels: Always describe what blurred content represents
- Allow content reveal: Provide ways to see blurred content when appropriate
- Animate blur transitions: Smooth blur changes are less jarring
- Consider performance: Heavy blur can impact rendering performance
- Use appropriate blur amounts: Higher values for privacy, lower for focus
- Maintain semantic meaning: Don't rely solely on blur for critical information
- Test across devices: Blur performance varies on different hardware
- Combine with overlays: Add text descriptions over blurred areas
- Respect user preferences: Some users may have motion sensitivity
- Provide alternative access: Ensure blurred content has non-visual alternatives
Conclusion
ImageFiltered enables powerful blur effects for privacy masks, loading states, modal backdrops, and depth-of-field focus effects that enhance multilingual applications. By providing proper accessibility labels and reveal mechanisms, you can build applications that use blur effectively while remaining accessible to all users. The key is balancing visual effects with usability and ensuring that important information remains accessible.
Remember to test your blur effects on various devices to ensure acceptable performance and verify that content behind blur overlays remains accessible through alternative means.