Tailwind CSS Backdrop Sepia
Backdrop Sepia allows a content’s backdrop to adopt a sepia-toned effect. It is especially useful for enhancing the aesthetic appeal of web interfaces by adding a warm vintage tone to background imagery or video content.
Tailwind CSS provides backdrop-sepia
and backdrop-sepia-0
utilities to easily add and remove backdrop sepia effects. In this guide, we will learn how to use backdrop sepia in Tailwind CSS, including conditional applications, customization techniques, and practical code examples.
Class | Properties | Example |
---|---|---|
backdrop-sepia-0 | backdrop-filter: sepia(0); | <div className="backdrop-sepia-0"></div> |
backdrop-sepia | backdrop-filter: sepia(100%); | <div className="backdrop-sepia"></div> |
Overview of Backdrop Sepia
Adding the Backdrop Sepia
To apply the sepia tone to an element's backdrop, use the backdrop-sepia
utility.
export default function BackdropSepiaExample() { return ( <div className="h-screen w-screen bg-cover bg-center" style={{ backgroundImage: `url('https://images.unsplash.com/photo-1508873699372-7aeab60b44ab')` }}> <div className="backdrop-sepia bg-white/30 flex items-center justify-center h-screen"> <p className="text-lg">Backdrop Sepia Effect</p> </div> </div> ); }
Resetting Backdrop Filter
To remove the backdrop sepia from an element, use backdrop-sepia-0
utility. If you want to remove all the backdrop filters, use the backdrop-filter-none
utility.
export default function NoBackdropFilterExample() { return ( <div className="h-screen w-screen bg-cover bg-center" style={{ backgroundImage: `url('https://images.unsplash.com/photo-1508873699372-7aeab60b44ab')` }}> <div className="backdrop-filter-none backdrop-sepia bg-white/30 flex items-center justify-center h-screen"> <p className="text-lg">No Filters Applied</p> </div> </div> ); }
States and Responsiveness
Hover and Focus States
Tailwind provides state modifiers like hover
, focus
, etc. to conditionally apply an utility only when these states are active. To apply the backdrop sepia to a certain state, prepend the state modifier to the utility, e.g., hover:backdrop-sepia
.
export default function HoverStateExample() { return ( <div className="h-screen w-screen bg-cover bg-center" style={{ backgroundImage: `url('https://images.unsplash.com/photo-1508873699372-7aeab60b44ab')` }}> <div className="hover:backdrop-sepia bg-white/30 flex items-center justify-center h-screen"> <p className="text-lg">Hover to add backdrop sepia</p> </div> </div> ); }
Breakpoint Modifiers
Tailwind CSS also provides breakpoint modifiers(sm
, md
, etc.) to apply or remove the backdrop sepia according to the screen width. To apply the backdrop sepia to a certain breakpoint or above, prepend the breakpoint modifier to the utility, e.g., md:backdrop-sepia
.
export default function ResponsiveBackdropExample() { return ( <div className="h-screen w-screen bg-cover bg-center" style={{ backgroundImage: `url('https://images.unsplash.com/photo-1508873699372-7aeab60b44ab')` }}> <div className="md:backdrop-sepia bg-white/30 flex items-center justify-center h-screen"> <p className="text-lg text-center px-10">Backdrop sepia is applied on the <code>md</code> breakpoint.</p> </div> </div> ); }
Custom Backdrop Sepia
Extending the Theme
Tailwind lets you customize the theme file to create new utilities beyond the default ones. Inside your tailwind.config.js
, modify the backdropSepia
property under the theme.extend
configuration.
In the below example, you have access to the custom utilities- backdrop-sepia-15
and backdrop-sepia-90
:
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; export default function CustomSepiaLevels() { return ( <div className="h-screen w-screen bg-cover bg-center" style={{ backgroundImage: `url('https://images.unsplash.com/photo-1508873699372-7aeab60b44ab')` }}> <div className="backdrop-sepia-90 bg-white/30 flex items-center justify-center h-screen"> <p className="text-lg">Custom backdrop sepia effect</p> </div> </div> ); }
Using Arbitrary Values
Tailwind also lets you define arbitrary values directly in your classes for one-off use cases. Just use the square bracket syntax [value]
wherever you need it, e.g., backdrop-sepia-[.5]
.
export default function ArbitrarySepiaValue() { return ( <div className="h-screen w-screen bg-cover bg-center" style={{ backgroundImage: `url('https://images.unsplash.com/photo-1508873699372-7aeab60b44ab')` }}> <div className="backdrop-sepia-[.5] bg-white/30 flex items-center justify-center h-screen"> <p className="text-lg">Arbitrary backdrop sepia effect</p> </div> </div> ); }
Real World Examples
Vintage Photo Gallery Modal
A modal photo gallery with a vintage sepia effect applied to the backdrop on click, displaying historical landmark photos with descriptions.
import { useState } from "react"; const HistoricalGallery = () => { const data = [ { id: 1, src: "https://images.unsplash.com/photo-1511739001486-6bfe10ce785f", title: "Eiffel Tower, 1889", description: "Symbol of Paris during World's Fair", }, { id: 2, src: "https://images.unsplash.com/photo-1587135941948-670b381f08ce", title: "Taj Mahal, 1653", description: "Monument of eternal love", }, { id: 3, src: "https://images.unsplash.com/photo-1552832230-c0197dd311b5", title: "Colosseum, 80 AD", description: "Ancient Roman amphitheater", }, { id: 4, src: "https://images.unsplash.com/photo-1615811648503-479d06197ff3", title: "Petra, 312 BC", description: "Rose city carved in stone", }, { id: 5, src: "https://images.unsplash.com/photo-1547150492-da7ff1742941", title: "Great Wall, 220 BC", description: "Ancient Chinese fortification", }, { id: 6, src: "https://images.unsplash.com/photo-1415804941191-bc0c3bbac10d", title: "Machu Picchu, 1450 AD", description: "Lost city of the Incas", }, ]; const [selectedImage, setSelectedImage] = useState(null); return ( <div className="p-4 h-screen overflow-y-auto"> <div className="grid grid-cols-2 gap-2"> {data.map((item) => ( <div key={item.id} onClick={() => setSelectedImage(item)} className="cursor-pointer hover:opacity-80 relative group" > <div className="w-full h-40 bg-cover bg-center rounded transition-transform duration-300 group-hover:scale-105" style={{ backgroundImage: `url(${item.src})` }} ></div> </div> ))} </div> {selectedImage && ( <div className="fixed inset-0 flex items-center justify-center z-50"> <div className="absolute inset-0 bg-black/30 backdrop-blur-sm backdrop-sepia transition-opacity duration-300 z-40"></div> <div className="relative bg-white p-4 rounded-lg max-w-md shadow-lg z-50"> <div className="w-full h-48 bg-cover bg-center rounded" style={{ backgroundImage: `url(${selectedImage.src})` }} ></div> <h3 className="text-lg font-semibold mt-2">{selectedImage.title}</h3> <p className="text-sm text-gray-600">{selectedImage.description}</p> <button onClick={() => setSelectedImage(null)} className="absolute top-2 right-2 text-gray-600 hover:text-gray-800" > × </button> </div> </div> )} </div> ); }; export default HistoricalGallery;
Recipe Card Collection
A collection of recipe cards with a sepia-toned backdrop effect when viewing detailed instructions.
import {useState} from "react"; const RetroRecipes = () => { const data = [ { id: 1, title: "Grandma's Apple Pie", time: "90 mins", difficulty: "Medium", image: "https://images.unsplash.com/photo-1572383672419-ab35444a6934", ingredients: ["Apples", "Sugar", "Flour", "Butter", "Cinnamon"], instructions: "Mix ingredients, bake at 350°F" }, { id: 2, title: "Classic Beef Stew", time: "180 mins", difficulty: "Hard", image: "https://images.unsplash.com/photo-1534939561126-855b8675edd7", ingredients: ["Beef", "Carrots", "Potatoes", "Onions", "Broth"], instructions: "Brown meat, add vegetables, simmer" }, { id: 3, title: "Chocolate Cookies", time: "45 mins", difficulty: "Easy", image: "https://images.unsplash.com/photo-1499636136210-6f4ee915583e", ingredients: ["Chocolate", "Flour", "Sugar", "Eggs", "Vanilla"], instructions: "Mix, shape, bake at 375°F" }, { id: 4, title: "Chicken Soup", time: "120 mins", difficulty: "Medium", image: "https://images.unsplash.com/photo-1547592166-23ac45744acd", ingredients: ["Chicken", "Carrots", "Celery", "Noodles", "Herbs"], instructions: "Boil chicken, add vegetables" }, { id: 5, title: "Banana Bread", time: "60 mins", difficulty: "Easy", image: "https://images.unsplash.com/photo-1596241913027-34358037e159", ingredients: ["Bananas", "Flour", "Sugar", "Eggs", "Nuts"], instructions: "Mash bananas, mix, bake" }, { id: 6, title: "Tomato Pasta", time: "30 mins", difficulty: "Easy", image: "https://images.unsplash.com/photo-1563379926898-05f4575a45d8", ingredients: ["Pasta", "Tomatoes", "Garlic", "Basil", "Olive Oil"], instructions: "Boil pasta, make sauce" } ]; const [selectedRecipe, setSelectedRecipe] = useState(null); return ( <div className="p-4 h-screen overflow-y-auto"> <div className="grid grid-cols-2 gap-3"> {data.map((recipe) => ( <div key={recipe.id} className="bg-white rounded-lg shadow-sm p-2 cursor-pointer" onClick={() => setSelectedRecipe(recipe)} > <img src={recipe.image} alt={recipe.title} className="w-full h-24 object-cover rounded" /> <h4 className="text-sm font-semibold mt-1">{recipe.title}</h4> <p className="text-xs text-gray-500">{recipe.time}</p> </div> ))} </div> {selectedRecipe && ( <div className="fixed inset-0 flex items-center justify-center"> <div className="absolute inset-0 backdrop-blur-md backdrop-sepia-[.4]"></div> <div className="relative bg-white p-4 rounded-lg max-w-xs shadow-xl border border-dashed border-black/70"> <img src={selectedRecipe.image} alt={selectedRecipe.title} className="w-full h-32 object-cover rounded" /> <h3 className="text-lg font-semibold mt-2">{selectedRecipe.title}</h3> <div className="text-xs mt-2"> <p className="font-semibold">Ingredients:</p> <ul className="list-disc pl-4"> {selectedRecipe.ingredients.map((ing, idx) => ( <li key={idx}>{ing}</li> ))} </ul> <p className="font-semibold mt-2">Instructions:</p> <p>{selectedRecipe.instructions}</p> </div> <button onClick={() => setSelectedRecipe(null)} className="absolute top-2 right-2 text-gray-600" > × </button> </div> </div> )} </div> ); }; export default RetroRecipes;
Product Comparison
A split-screen product comparison where the backdrop-sepia effect helps highlight the selected side.
import { useState } from "react"; const ProductComparison = () => { const data = [ { id: 1, name: "Pro Camera X1", brand: "PhotoTech", price: "$1299", image: "https://images.unsplash.com/photo-1516035069371-29a1b244cc32", specs: ["50MP Sensor", "8K Video", "Weather Sealed", "5-axis IBIS"], rating: 4.8 }, { id: 2, name: "Pro Camera X2", brand: "CameraPro", price: "$1499", image: "https://images.unsplash.com/photo-1502920917128-1aa500764cbd", specs: ["61MP Sensor", "8K Video", "Weather Sealed", "6-axis IBIS"], rating: 4.9 }, { id: 3, name: "Pro Camera X3", brand: "PhotoMaster", price: "$999", image: "https://images.unsplash.com/photo-1500634245200-e5245c7574ef", specs: ["45MP Sensor", "4K Video", "Weather Sealed", "4-axis IBIS"], rating: 4.7 }, { id: 4, name: "Pro Camera X4", brand: "LensKing", price: "$1899", image: "https://images.unsplash.com/photo-1512790182412-b19e6d62bc39", specs: ["70MP Sensor", "12K Video", "Weather Sealed", "7-axis IBIS"], rating: 4.6 }, { id: 5, name: "Pro Camera X5", brand: "PixelPro", price: "$2199", image: "https://images.unsplash.com/photo-1510127034890-ba27508e9f1c", specs: ["80MP Sensor", "16K Video", "Weather Sealed", "8-axis IBIS"], rating: 4.5 }, { id: 6, name: "Pro Camera X6", brand: "CamKing", price: "$1699", image: "https://images.unsplash.com/photo-1516724562728-afc824a36e84", specs: ["65MP Sensor", "10K Video", "Weather Sealed", "6-axis IBIS"], rating: 4.4 } ]; const [leftProduct, setLeftProduct] = useState(data[0]); const [rightProduct, setRightProduct] = useState(data[1]); const [focusedSide, setFocusedSide] = useState(null); return ( <div className="h-screen w-screen relative overflow-hidden"> <div className="flex h-full"> {/* Left Side */} <div className="w-1/2 p-2 relative" onMouseEnter={() => setFocusedSide("left")} onMouseLeave={() => setFocusedSide(null)} > {/* Apply Sepia Only When Hovered */} <div className={`absolute inset-0 transition duration-300 ${ focusedSide === "left" ? "backdrop-sepia backdrop-blur-sm" : "" }`} ></div> <div className="relative z-10"> <select className="w-full mb-2 text-xs" onChange={(e) => setLeftProduct(data[e.target.value])} > {data.map((item, idx) => ( <option key={item.id} value={idx}>{item.name}</option> ))} </select> <div className="space-y-2"> <img src={leftProduct.image} alt={leftProduct.name} className="w-full h-32 object-cover rounded" /> <h3 className="text-sm font-semibold">{leftProduct.name}</h3> <p className="text-xs text-gray-600">{leftProduct.brand}</p> <p className="text-sm font-bold">{leftProduct.price}</p> <div className="text-xs space-y-1"> {leftProduct.specs.map((spec, idx) => ( <p key={idx}>{spec}</p> ))} </div> </div> </div> </div> {/* Divider */} <div className="w-px bg-gray-300"></div> {/* Right Side */} <div className="w-1/2 p-2 relative" onMouseEnter={() => setFocusedSide("right")} onMouseLeave={() => setFocusedSide(null)} > {/* Apply Sepia Only When Hovered */} <div className={`absolute inset-0 transition duration-300 ${ focusedSide === "right" ? "backdrop-sepia backdrop-blur-sm" : "" }`} ></div> <div className="relative z-10"> <select className="w-full mb-2 text-xs" onChange={(e) => setRightProduct(data[e.target.value])} > {data.map((item, idx) => ( <option key={item.id} value={idx}>{item.name}</option> ))} </select> <div className="space-y-2"> <img src={rightProduct.image} alt={rightProduct.name} className="w-full h-32 object-cover rounded" /> <h3 className="text-sm font-semibold">{rightProduct.name}</h3> <p className="text-xs text-gray-600">{rightProduct.brand}</p> <p className="text-sm font-bold">{rightProduct.price}</p> <div className="text-xs space-y-1"> {rightProduct.specs.map((spec, idx) => ( <p key={idx}>{spec}</p> ))} </div> </div> </div> </div> </div> </div> ); }; export default ProductComparison;
Before/After Image Slider
A unique implementation of an image slider where dragging reveals the before/after states with a sepia backdrop effect.
import { useState, useRef } from "react"; const BeforeAfterSlider = () => { const data = [ { id: 1, before: "https://images.unsplash.com/photo-1600596542815-ffad4c1539a9", after: "https://images.unsplash.com/photo-1600585154340-be6161a56a0c", title: "House Renovation", }, { id: 2, before: "https://images.unsplash.com/photo-1512917774080-9991f1c4c750", after: "https://images.unsplash.com/photo-1570129477492-45c003edd2be", title: "Exterior Makeover", }, { id: 3, before: "https://images.unsplash.com/photo-1523039031846-6b3f39302cb8", after: "https://images.unsplash.com/photo-1556911220-bff31c812dba", title: "Kitchen Remodel", }, { id: 4, before: "https://images.unsplash.com/photo-1560448204-603b3fc33ddc", after: "https://images.unsplash.com/photo-1560448075-bb485b067938", title: "Bathroom Update", }, { id: 5, before: "https://images.unsplash.com/photo-1565776316048-2501a698ba08", after: "https://images.unsplash.com/photo-1603024594199-4107b1e69b7d", title: "Living Room Transform", }, { id: 6, before: "https://images.unsplash.com/photo-1516253593875-bd7ba052fbc5", after: "https://images.unsplash.com/photo-1462759353907-b2ea5ebd72e7", title: "Garden Makeover", } ]; const [selectedImage, setSelectedImage] = useState(data[0]); const [sliderPosition, setSliderPosition] = useState(50); const sliderRef = useRef(null); const handleMouseMove = (e) => { if (!sliderRef.current) return; const rect = sliderRef.current.getBoundingClientRect(); const x = e.clientX - rect.left; const percent = (x / rect.width) * 100; setSliderPosition(Math.min(Math.max(percent, 0), 100)); }; return ( <div className="h-screen w-screen p-4 bg-gray-100"> <div className="space-y-4"> {/* Main Slider */} <div ref={sliderRef} className="relative h-48 cursor-ew-resize overflow-hidden rounded-lg" onMouseMove={handleMouseMove} > {/* Before Image */} <div className="absolute inset-0"> <img src={selectedImage.before} alt="Before" className="w-full h-full object-cover" /> {/* Applying backdrop-sepia */} <div className="absolute inset-0 bg-black/10 backdrop-sepia transition duration-300"></div> </div> {/* After Image */} <div className="absolute inset-0 overflow-hidden" style={{ width: `${sliderPosition}%` }} > <img src={selectedImage.after} alt="After" className="w-full h-full object-cover" /> </div> {/* Slider Handle */} <div className="absolute top-0 bottom-0 w-1 bg-white cursor-ew-resize" style={{ left: `${sliderPosition}%` }} > <div className="absolute top-1/2 -translate-y-1/2 -translate-x-1/2 w-6 h-6 bg-white rounded-full shadow-lg"></div> </div> </div> {/* Thumbnails */} <div className="grid grid-cols-3 gap-2"> {data.map((item) => ( <div key={item.id} onClick={() => setSelectedImage(item)} className={`cursor-pointer relative rounded-md overflow-hidden ${ selectedImage.id === item.id ? 'ring-2 ring-blue-500' : '' }`} > <img src={item.after} alt={item.title} className="w-full h-16 object-cover" /> <div className="absolute inset-0 bg-black bg-opacity-20"> <p className="text-white text-xs p-1">{item.title}</p> </div> </div> ))} </div> </div> </div> ); }; export default BeforeAfterSlider;
Vintage Cinema Listings
A movie showtime display with a sepia backdrop effect when viewing movie details.
import { useState } from 'react'; const CinemaListings = () => { const [selectedMovie, setSelectedMovie] = useState(null); const movieData = [ { id: 1, title: "The Grand Escape", poster: "https://images.unsplash.com/photo-1542204165-65bf26472b9b", director: "Edward Mitchell", year: "1935", runtime: "1h 45m", genre: "Mystery/Thriller", showtime: ["2:00 PM", "5:30 PM", "8:00 PM"], cast: "James Stewart, Grace Kelly", description: "A thrilling tale of mystery and intrigue in the golden age of cinema." }, { id: 2, title: "Midnight Waltz", poster: "https://images.unsplash.com/photo-1536440136628-849c177e76a1", director: "Maria Hernandez", year: "1942", runtime: "2h 10m", genre: "Romance/Drama", showtime: ["1:30 PM", "4:45 PM", "7:15 PM"], cast: "Katherine Hepburn, Cary Grant", description: "A romantic drama set in the glamorous world of ballroom dancing." }, { id: 3, title: "Desert Storm", poster: "https://images.unsplash.com/photo-1594909122845-11baa439b7bf", director: "Robert Wilson", year: "1939", runtime: "1h 55m", genre: "Adventure", showtime: ["3:15 PM", "6:00 PM", "8:45 PM"], cast: "Clark Gable, Vivien Leigh", description: "An epic adventure across the scorching desert landscapes." }, { id: 4, title: "City Lights", poster: "https://images.unsplash.com/photo-1478720568477-152d9b164e26", director: "Charles Chapman", year: "1938", runtime: "1h 30m", genre: "Comedy", showtime: ["2:30 PM", "5:00 PM", "7:30 PM"], cast: "Charlie Chaplin, Virginia Cherrill", description: "A heartwarming comedy about life in the big city." }, { id: 5, title: "The Last Train", poster: "https://images.unsplash.com/photo-1535443274868-756b0f070b6e", director: "John Ford", year: "1941", runtime: "2h 05m", genre: "Drama/War", showtime: ["1:00 PM", "4:00 PM", "7:00 PM"], cast: "Humphrey Bogart, Ingrid Bergman", description: "A gripping war drama about love and sacrifice." }, { id: 6, title: "Morning Glory", poster: "https://images.unsplash.com/photo-1533928298208-27ff66555d8d", director: "Alfred Hitchcock", year: "1937", runtime: "1h 50m", genre: "Mystery/Romance", showtime: ["3:30 PM", "6:30 PM", "9:00 PM"], cast: "Joan Crawford, Henry Fonda", description: "A mysterious romance that unfolds at sunrise." } ]; return ( <div className="w-screen h-screen bg-stone-100 p-4 overflow-y-auto"> <h1 className="text-2xl font-serif font-bold mb-4">Grand Palace Cinema</h1> <div className="space-y-4"> {movieData.map((movie) => ( <div key={movie.id} className="flex gap-3 cursor-pointer hover:bg-stone-200 p-2 rounded transition-colors" onClick={() => setSelectedMovie(movie)} > <img src={movie.poster} alt={movie.title} className="w-20 h-28 object-cover rounded" /> <div> <h3 className="font-medium">{movie.title}</h3> <p className="text-xs text-gray-600">{movie.year} • {movie.runtime}</p> <p className="text-xs text-gray-600 mt-1">{movie.genre}</p> <div className="flex gap-2 mt-2"> {movie.showtime.map((time, index) => ( <span key={index} className="text-xs bg-stone-200 px-2 py-1 rounded"> {time} </span> ))} </div> </div> </div> ))} </div> {selectedMovie && ( <div className="fixed inset-0 flex items-center justify-center"> <div className="absolute inset-0 backdrop-blur-sm backdrop-sepia bg-stone-900/30" onClick={() => setSelectedMovie(null)} /> <div className="relative z-10 bg-stone-100 p-6 rounded-lg max-w-md w-full mx-4 "> <img src={selectedMovie.poster} alt={selectedMovie.title} className="w-full h-24 object-cover rounded-lg mb-4" /> <h2 className="text-md font-serif font-bold">{selectedMovie.title}</h2> <p className="text-xs text-gray-600">{selectedMovie.year} • {selectedMovie.runtime}</p> <p className="text-xs font-medium mt-2">Director: {selectedMovie.director}</p> <p className="text-xs font-medium">Cast: {selectedMovie.cast}</p> <p className="text-xs mt-2">{selectedMovie.description}</p> <div className="mt-4 text-xs"> <h3 className="font-medium mb-2">Today's Showtimes</h3> <div className="flex gap-2"> {selectedMovie.showtime.map((time, index) => ( <span key={index} className="text-xs bg-stone-200 px-3 py-1 rounded"> {time} </span> ))} </div> </div> </div> </div> )} </div> ); }; export default CinemaListings;
Customization Examples
Custom Sepia Profile Card
A profile card component with a custom sepia backdrop effect that creates a vintage photography look for user profiles.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; // App.js export default function VintageProfileCard() { return ( <div className="flex items-center justify-center min-h-screen bg-gray-100"> <div className="relative w-80 h-96 overflow-hidden rounded-xl"> <img src="https://images.unsplash.com/photo-1544005313-94ddf0286df2" className="absolute w-full h-full object-cover" alt="Profile" /> <div className="absolute inset-0 backdrop-sepia-vintage bg-white/30" /> <div className="absolute bottom-0 w-full p-6 text-white"> <h3 className="text-2xl font-semibold">Sarah Anderson</h3> <p className="text-sm opacity-90">Vintage Photography Expert</p> </div> </div> </div> ) }
Sepia Gallery Showcase
A gallery showcase with varying sepia intensities for an artistic image display.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; // App.js export default function SepiaGallery() { const images = [ { url: "https://images.unsplash.com/photo-1501785888041-af3ef285b470", sepia: "backdrop-sepia-light" }, { url: "https://images.unsplash.com/photo-1449034446853-66c86144b0ad", sepia: "backdrop-sepia-medium" }, { url: "https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05", sepia: "backdrop-sepia-heavy" } ] return ( <div className="grid grid-cols-3 gap-4 p-8 bg-gray-900 h-screen"> {images.map((image, index) => ( <div key={index} className="relative group overflow-hidden rounded-lg"> <img src={image.url} className="w-full h-full object-cover" alt={`Gallery ${index + 1}`} /> <div className={`absolute inset-0 ${image.sepia} transition-all duration-300 group-hover:backdrop-blur-sm`} /> </div> ))} </div> ) }
Sepia Hero Banner
A hero banner with custom sepia effect and interactive hover states.
import tailwindConfig from "./tailwind.config.js"; tailwind.config = tailwindConfig; // App.js export default function SepiaHeroBanner() { return ( <div className="relative h-screen w-full overflow-hidden"> <img src="https://images.unsplash.com/photo-1501785888041-af3ef285b470" className="absolute w-full h-full object-cover" alt="Hero" /> <div className="absolute inset-0 backdrop-sepia-subtle transition-all duration-500 backdrop-blur-sm bg-black/20" /> <div className="relative z-10 flex flex-col items-center justify-center h-full text-white"> <h1 className="text-6xl font-bold mb-4 text-center">Timeless Memories</h1> <p className="text-xl max-w-2xl text-center"> Experience the beauty of vintage aesthetics through our carefully curated collection </p> <button className="mt-8 px-8 py-3 bg-white/10 backdrop-blur-md rounded-full hover:bg-white/20 transition-all duration-300"> Explore Collection </button> </div> </div> ) }
Best Practices
Maintain Design Consistency
When applying backdrop sepia in Tailwind CSS, maintaining a consistent design language across your project is essential. To achieve this consistency, define a limited set of global sepia intensity levels in your Tailwind configuration file, such as backdrop-sepia-25
or backdrop-sepia-75
. Then, apply these utilities consistently across all components where sepia effects are needed.
Consistency also involves adhering to a harmonious color palette that complements sepia tones. For example, pair warm hues like amber or beige with sepia filters for a vintage aesthetic.
Lastly, validate your design by conducting visual audits, particularly in scenarios with multiple layered elements or transparency overlaps. Ensure the underlying backdrop elements do not clash with the sepia filter, and verify that the filtered content aligns visually with your branding guidelines.
Leverage Utility Combinations
For more creative and visually appealing designs, you can combine backdrop-sepia
with other Tailwind CSS utilities like backdrop-blur
, backdrop-contrast
, backdrop-brightness
, etc. This allows you to refine how backdrop elements appear, making them softer, sharper, or more dramatic.
You can also use backdrop-sepia
in interactive elements like hoverable cards, buttons, or modals. By applying it with hover (hover:backdrop-sepia
) or focus (focus:backdrop-sepia
) states, you can make UI components dynamically change based on user interaction. This technique helps guide user attention while maintaining a visually appealing and engaging experience.
Accessibility Considerations
Enhance Readability and Navigability
The sepia effect introduces a warm, vintage tone that can soften contrasts and impact text clarity. To counteract this, use highly legible fonts along with an appropriate text size. Additionally, add proper line spacing for better readability and reduced eye strain.
Navigability also plays a key role in accessibility when applying sepia backgrounds. Users with color vision deficiencies or general visual impairments may struggle to differentiate elements if the sepia tone is too intense. To maintain clarity, use well-defined borders and shadows to provide clear separation between UI elements.
Focus on High Contrast
Low contrast between text and the background can be problematic for users with visual impairments, making it difficult to read content or distinguish between UI components. A good practice is to test contrast ratios using accessibility tools like the WebAIM Contrast Checker to ensure compliance with WCAG (Web Content Accessibility Guidelines) standards. If text on a sepia backdrop does not meet contrast requirements, adjust its color utilities.
Another approach to preserving contrast is to limit the intensity of the sepia effect (e.g., backdrop-sepia-[0.5]
) instead of applying a full sepia filter. Additionally, ensure the accompanying overlay (e.g., bg-black/40
, bg-white/30
) maintains sufficient contrast for text and interactive elements.