Menu

Tailwind CSS Sepia

Sepia in CSS is a filter effect that adds a warm, brownish tone to an image, resembling old photographs or giving elements a vintage appearance. This filter finds usage in creative designs and is a key component in image manipulation for web layouts. Tailwind CSS, being a utility-first CSS framework, provides several utilities to easily implement and customize sepia effects in your projects, ensuring flexibility and responsiveness.

In this guide, we delve into the seamless integration of sepia filters in Tailwind CSS, covering fundamental usage, conditional applications, and customization techniques.

ClassPropertiesExample
sepia-0filter: sepia(0);<div className="sepia-0"></div>
sepiafilter: sepia(100%);<div className="sepia"></div>

Overview of Sepia

Adding the Sepia

To apply a sepia effect to an element, use sepia class. The sepia class applies a sepia filter with a default intensity of 100%.

This is a live editor. Play around with it!
// JSX Code for adding sepia
export default function SepiaImage() {
  return (
    <div className="h-screen w-screen flex items-center justify-center bg-gray-200">
      {/* Applying Sepia */}
      <img
        src="https://images.unsplash.com/photo-1488998427799-e3362cec87c3"
        alt="Sepia Filter"
        className="sepia rounded-md shadow-lg"
      />
    </div>
  );
}

Removing the Sepia

If you wish to remove the applied sepia effect, use the filter-none, or sepia-0 class, to reset all filter utilities, or only sepia.

This is a live editor. Play around with it!
// JSX Code for no filters
export default function ResetSepia() {
  return (
    <div className="h-screen w-screen flex items-center justify-center bg-gray-200">
      {/* Removing filters */}
      <img
        src="https://images.unsplash.com/photo-1488998427799-e3362cec87c3"
        alt="Original Image"
        className="filter-none rounded-md shadow-lg"
      />
    </div>
  );
}

States and Responsiveness

Tailwind CSS allows the application of sepia filters conditionally, based on interactive states (such as hover or focus) or within defined screen breakpoints. This section elaborates on these dynamic use cases.

Hover and Focus States

With Tailwind CSS, you can add sepia effects interactively, such as on hover or focus states. This is particularly useful in enhancing user experience for clickable or interactive elements.

This is a live editor. Play around with it!
// JSX Code for hover and focus effects
export default function InteractiveSepia() {
  return (
    <div className="h-screen w-screen flex items-center justify-center bg-gray-200">
      {/* Hover State */}
      <img
        src="https://images.unsplash.com/photo-1488998427799-e3362cec87c3"
        alt="Interactive Image"
        className="hover:sepia cursor-pointer rounded-md shadow-lg transition-all duration-300"
      />
    </div>
  );
}

Breakpoint Modifiers

Tailwind CSS makes it easy to apply sepia filters based on screen sizes using breakpoint modifiers. This enables developers to define responsive sepia styles seamlessly.

This is a live editor. Play around with it!
// JSX Code for responsive sepia
export default function ResponsiveSepia() {
  return (
    <div className="h-screen w-screen flex flex-col items-center justify-center bg-gray-200 space-y-6">
      {/* Responsive Filters */}
      <img
        src="https://images.unsplash.com/photo-1488998427799-e3362cec87c3"
        alt="Sepia on Large Screens"
        className="md:sepia lg:filter-none rounded-md shadow-lg"
      />
      <span className="text-sm px-10 text-center">
        Sepia effect on medium screens, none for large screens.
      </span>
    </div>
  );
}

Custom Sepia

Default utilities work in most scenarios, but Tailwind CSS lets you extend and customize the sepia intensity or define arbitrary values for creative requirements.

Extending the Theme

Tailwind allows customization of its sepia filter via the configuration file. By extending the default theme, you can introduce different levels of sepia effects.

Now you can use the extended classes, such as:

This is a live editor. Play around with it!
import tailwindConfig from "./tailwind.config.js";
tailwind.config = tailwindConfig;

// JSX Code for extended sepia
export default function CustomSepiaImage() {
  return (
    <div className="h-screen w-screen flex items-center justify-center bg-gray-200">
      <img
        src="https://images.unsplash.com/photo-1488998427799-e3362cec87c3"
        alt="Interactive Image"
        className="sepia-75 cursor-pointer rounded-md shadow-lg transition-all duration-300"
      />
    </div>
  );
}

Using Arbitrary Values

Sometimes, you might need to apply unique sepia levels beyond predefined utilities. Tailwind CSS supports arbitrary values, offering unparalleled design flexibility.

This is a live editor. Play around with it!
// JSX Code for arbitrary values
export default function ArbitrarySepia() {
  return (
    <div className="h-screen w-screen flex flex-col items-center justify-center bg-gray-200 space-y-6">
      {/* Specific sepia value */}
      <img
        src="https://images.unsplash.com/photo-1488998427799-e3362cec87c3"
        alt="Arbitrary Sepia"
        className="sepia-[0.4] rounded-md shadow-lg"
      />
    </div>
  );
}

Real World Examples

This component displays a collection of classic cameras with a sepia effect to create a nostalgic feel.

This is a live editor. Play around with it!
export default function VintageProductGallery() {
  const cameras = [
    {
      id: 1,
      name: "Rolleiflex TLR",
      year: "1962",
      src: "https://images.unsplash.com/photo-1551232865-e0a56728e881",
      alt: "Classic Rolleiflex twin lens camera",
      price: "$1,899"
    },
    {
      id: 2,
      name: "Canon AE-1",
      year: "1976",
      src: "https://images.unsplash.com/photo-1589492477829-5e65395b66cc",
      alt: "Vintage Canon AE-1 camera",
      price: "$899"
    },
    {
      id: 3,
      name: "Pentax Spotmatic",
      year: "1964",
      src: "https://images.unsplash.com/photo-1552168324-d612d77725e3",
      alt: "Classic Pentax Spotmatic camera",
      price: "$799"
    }
  ];

  return (
    <div className="container mx-auto p-8">
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
        {cameras.map((camera) => (
          <div key={camera.id} className="group relative">
            <img
              src={camera.src}
              alt={camera.alt}
              className="w-full h-64 object-cover rounded-lg transition-all duration-300 filter sepia hover:sepia-0"
            />
            <div className="absolute bottom-0 left-0 right-0 bg-black bg-opacity-60 p-4 rounded-b-lg">
              <h3 className="text-white text-xl font-semibold">{camera.name}</h3>
              <p className="text-gray-300">Year: {camera.year}</p>
              <p className="text-white font-bold">{camera.price}</p>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Historical Timeline Component

A timeline component showcasing historical events with sepia-toned images.

This is a live editor. Play around with it!
export default function HistoricalTimeline() {
  const events = [
    {
      id: 1,
      year: "1903",
      title: "First Flight",
      description: "Wright brothers make the first powered aircraft flight",
      src: "https://images.unsplash.com/photo-1464037866556-6812c9d1c72e",
      alt: "Vintage airplane"
    },
    {
      id: 2,
      year: "1929",
      title: "Stock Market Crash",
      description: "The Great Depression begins",
      src: "https://images.unsplash.com/photo-1611974789855-9c2a0a7236a3",
      alt: "Historic stock market scene"
    },
    {
      id: 3,
      year: "1945",
      title: "World War II Ends",
      description: "Victory celebrations worldwide",
      src: "https://images.unsplash.com/photo-1580130281320-0ef0754f2bf7",
      alt: "Victory celebration"
    },
    {
      id: 4,
      year: "1969",
      title: "Moon Landing",
      description: "First humans walk on the moon",
      src: "https://images.unsplash.com/photo-1541873676-a18131494184",
      alt: "Moon landing photograph"
    },
  ];

  return (
    <div className="max-w-4xl mx-auto p-8">
      <div className="space-y-12">
        {events.map((event, index) => (
          <div key={event.id} className={`flex ${index % 2 === 0 ? 'flex-row' : 'flex-row-reverse'}`}>
            <div className="w-1/2 p-4">
              <img
                src={event.src}
                alt={event.alt}
                className="w-full h-48 object-cover rounded-lg filter sepia"
              />
            </div>
            <div className="w-1/2 p-4 flex flex-col justify-center">
              <div className="text-4xl font-bold text-amber-800">{event.year}</div>
              <h3 className="text-2xl font-semibold mt-2">{event.title}</h3>
              <p className="text-gray-600 mt-2">{event.description}</p>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Memory Album Component

An interactive photo album with sepia effects that reveal original colors on hover.

This is a live editor. Play around with it!
export default function MemoryAlbum() {
  const memories = [
    {
      id: 1,
      title: "Summer Picnic",
      date: "June 1955",
      src: "https://images.unsplash.com/photo-1528605105345-5344ea20e269",
      alt: "Family picnic in the park"
    },
    {
      id: 2,
      title: "First Car",
      date: "March 1960",
      src: "https://images.unsplash.com/photo-1591293835940-934a7c4f2d9b",
      alt: "Classic car photograph"
    },
    {
      id: 3,
      title: "Wedding Day",
      date: "May 1958",
      src: "https://images.unsplash.com/photo-1583939003579-730e3918a45a",
      alt: "Vintage wedding photograph"
    },
    {
      id: 4,
      title: "Beach Holiday",
      date: "July 1962",
      src: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e",
      alt: "Beach vacation memory"
    },
    {
      id: 5,
      title: "High School Graduation",
      date: "June 1957",
      src: "https://images.unsplash.com/photo-1523050854058-8df90110c9f1",
      alt: "Graduation ceremony"
    },
    {
      id: 6,
      title: "First House",
      date: "April 1963",
      src: "https://images.unsplash.com/photo-1518780664697-55e3ad937233",
      alt: "Old house photograph"
    }
  ];

  return (
    <div className="bg-amber-50 min-h-screen p-8">
      <div className="max-w-6xl mx-auto">
        <div className="grid grid-cols-2 md:grid-cols-3 gap-8">
          {memories.map((memory) => (
            <div key={memory.id} className="group relative">
              <div className="relative overflow-hidden rounded-lg shadow-lg">
                <img
                  src={memory.src}
                  alt={memory.alt}
                  className="w-full h-64 object-cover transition-all duration-500 filter sepia group-hover:sepia-0"
                />
                <div className="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black to-transparent">
                  <h3 className="text-white text-lg font-semibold">{memory.title}</h3>
                  <p className="text-gray-300 text-sm">{memory.date}</p>
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

Vintage Recipe Card Component

A collection of recipe cards with a nostalgic sepia effect.

This is a live editor. Play around with it!
export default function VintageRecipeCards() {
  const recipes = [
    {
      id: 1,
      title: "Traditional Beef Stew",
      year: "1932",
      src: "https://images.unsplash.com/photo-1534939561126-855b8675edd7",
      alt: "Homemade beef stew",
      author: "Elizabeth Brown",
      difficulty: "Easy"
    },
    {
      id: 2,
      title: "Classic Pound Cake",
      year: "1918",
      src: "https://images.unsplash.com/photo-1588195538326-c5b1e9f80a1b",
      alt: "Traditional pound cake",
      author: "Sarah Davis",
      difficulty: "Easy"
    },
    {
      id: 3,
      title: "Southern Fried Chicken",
      year: "1940",
      src: "https://images.unsplash.com/photo-1626082927389-6cd097cdc6ec",
      alt: "Fried chicken recipe",
      author: "Mary Johnson",
      difficulty: "Medium"
    },
    {
      id: 4,
      title: "Heritage Bread Rolls",
      year: "1915",
      src: "https://images.unsplash.com/photo-1586444248902-2f64eddc13df",
      alt: "Homemade bread rolls",
      author: "Ruth Miller",
      difficulty: "Hard"
    },
    {
      id: 5,
      title: "Classic Meatloaf",
      year: "1935",
      src: "https://images.unsplash.com/photo-1544025162-d76694265947",
      alt: "Traditional meatloaf",
      author: "Helen Thompson",
      difficulty: "Medium"
    }
  ];

  return (
    <div className="bg-amber-100 p-8">
      <div className="max-w-7xl mx-auto">
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
          {recipes.map((recipe) => (
            <div key={recipe.id} className="bg-white rounded-lg overflow-hidden shadow-lg">
              <div className="relative h-48">
                <img
                  src={recipe.src}
                  alt={recipe.alt}
                  className="w-full h-full object-cover filter sepia"
                />
                <div className="absolute top-4 right-4 bg-amber-800 text-white px-3 py-1 rounded-full text-sm">
                  {recipe.year}
                </div>
              </div>
              <div className="p-6">
                <h3 className="text-xl font-semibold text-amber-900">{recipe.title}</h3>
                <p className="text-gray-600 mt-2">By {recipe.author}</p>
                <div className="mt-4 flex justify-between items-center">
                  <span className="text-sm text-gray-500">Difficulty: {recipe.difficulty}</span>
                  <button className="bg-amber-600 text-white px-4 py-2 rounded-lg hover:bg-amber-700">
                    View Recipe
                  </button>
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

A museum gallery component featuring historical artifacts with sepia effects.

This is a live editor. Play around with it!
export default function HeritageMuseumGallery() {
  const artifacts = [
    {
      id: 1,
      name: "Ancient Egyptian Vase",
      period: "2500 BC",
      src: "https://images.unsplash.com/photo-1597423498219-04418210827d",
      alt: "Egyptian artifact vase",
      description: "Ceremonial vase from the Old Kingdom period"
    },
    {
      id: 2,
      name: "Medieval Manuscript",
      period: "1200 AD",
      src: "https://images.unsplash.com/photo-1544982503-9f984c14501a",
      alt: "Ancient manuscript",
      description: "Illuminated manuscript from medieval monastery"
    },
    {
      id: 3,
      name: "Ming Dynasty Porcelain",
      period: "1500 AD",
      src: "https://images.unsplash.com/photo-1590794056226-79ef3a8147e1",
      alt: "Chinese porcelain",
      description: "Blue and white porcelain from Ming Dynasty"
    },
    {
      id: 4,
      name: "Aztec Stone Mask",
      period: "1400 AD",
      src: "https://images.unsplash.com/photo-1594760467013-64ac2b80b7d3",
      alt: "Aztec artifact",
      description: "Ceremonial mask from Aztec temple"
    }
  ];

  return (
    <div className="bg-stone-900 min-h-screen p-8">
      <div className="max-w-7xl mx-auto">
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
          {artifacts.map((artifact) => (
            <div key={artifact.id} className="group">
              <div className="relative overflow-hidden rounded-xl">
                <img
                  src={artifact.src}
                  alt={artifact.alt}
                  className="w-full h-80 object-cover filter sepia transition-transform duration-500 group-hover:scale-110"
                />
                <div className="absolute inset-0 bg-black bg-opacity-60 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-col justify-end p-6">
                  <h3 className="text-white text-xl font-semibold">{artifact.name}</h3>
                  <p className="text-amber-400 mt-2">{artifact.period}</p>
                  <p className="text-gray-300 mt-2 text-sm">{artifact.description}</p>
                </div>
              </div>
              <div className="mt-4 text-center">
                <h4 className="text-amber-500 text-lg font-medium">{artifact.name}</h4>
                <p className="text-gray-400 text-sm">{artifact.period}</p>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

Customization Examples

This example creates a photo gallery with different sepia intensities for a vintage photography portfolio.

This is a live editor. Play around with it!
import tailwindConfig from "./tailwind.config.js";
tailwind.config = tailwindConfig;

// App.js
export default function VintageGallery() {
  const photos = [
    { id: 1, url: 'https://images.unsplash.com/photo-1516483638261-f4dbaf036963', title: 'Venice' },
    { id: 2, url: 'https://images.unsplash.com/photo-1523906834658-6e24ef2386f9', title: 'Paris' },
    { id: 3, url: 'https://images.unsplash.com/photo-1533105079780-92b9be482077', title: 'Rome' },
  ];

  return (
    <div className="container mx-auto p-8 bg-stone-100">
      <h1 className="text-3xl font-serif mb-8 text-center">Vintage Europe</h1>
      <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
        {photos.map((photo) => (
          <div key={photo.id} className="group relative overflow-hidden rounded-lg">
            <img
              src={photo.url}
              alt={photo.title}
              className="w-full h-72 object-cover transition-all duration-300 sepia-medium hover:sepia-light"
            />
            <div className="absolute bottom-0 left-0 right-0 bg-black/50 text-white p-4 transform translate-y-full group-hover:translate-y-0 transition-transform">
              <h3 className="text-xl font-serif">{photo.title}</h3>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Interactive Timeline with Sepia Transitions

A historical timeline that uses sepia effects to distinguish between past and present events.

This is a live editor. Play around with it!
import tailwindConfig from "./tailwind.config.js";
tailwind.config = tailwindConfig;

// App.js
export default function HistoricalTimeline() {
  const events = [
    { year: '1920', title: 'The Golden Age', image: 'https://images.unsplash.com/photo-1552084117-56a987666449' },
    { year: '1980', title: 'Modern Times', image: 'https://images.unsplash.com/photo-1568992687947-868a62a9f521' },
  ];

  return (
    <div className="max-w-4xl mx-auto p-6 bg-zinc-50">
      <div className="space-y-12">
        {events.map((event, index) => (
          <div key={event.year} className={`flex ${index % 2 === 0 ? 'flex-row' : 'flex-row-reverse'} items-center gap-8`}>
            <div className="w-1/2">
              <img
                src={event.image}
                alt={event.title}
                className="rounded-lg shadow-xl transition-all duration-500 sepia-90 hover:sepia-0"
              />
            </div>
            <div className="w-1/2 space-y-4">
              <span className="text-6xl font-bold text-sepia-800">{event.year}</span>
              <h3 className="text-2xl font-serif">{event.title}</h3>
              <div className="h-1 w-24 bg-sepia-700"></div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Memory Card Game with Sepia Reveal Effect

A card-matching game that uses sepia effects to create an aged photograph reveal animation.

This is a live editor. Play around with it!
import tailwindConfig from "./tailwind.config.js";
tailwind.config = tailwindConfig;

// App.js
export default function MemoryGame() {
  const cards = [
    { id: 1, image: 'https://images.unsplash.com/photo-1509048191080-d2984bad6ae5' },
    { id: 2, image: 'https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e' },
    { id: 3, image: 'https://images.unsplash.com/photo-1514282401047-d79a71a590e8' },
    { id: 4, image: 'https://images.unsplash.com/photo-1516962126636-27ad087061cc' },
  ];

  return (
    <div className="min-h-screen bg-amber-50 p-8">
      <div className="max-w-3xl mx-auto">
        <h1 className="text-4xl font-serif text-center mb-8">Vintage Memories</h1>
        <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
          {cards.concat(cards).map((card, index) => (
            <div
              key={`${card.id}-${index}`}
              className="group perspective-1000 relative h-48 cursor-pointer"
            >
              <div className="absolute inset-0 transition-transform duration-700 transform-style-3d group-hover:rotate-y-180">
                <div className="absolute inset-0 bg-sepia-200 rounded-lg shadow-xl backface-hidden">
                  <div className="w-full h-full bg-[url('https://images.unsplash.com/photo-1572375992501-4b0892d50c69')] bg-cover rounded-lg"></div>
                </div>
                <div className="absolute inset-0 rounded-lg shadow-xl backface-hidden rotate-y-180 overflow-hidden">
                  <img
                    src={card.image}
                    alt="Memory Card"
                    className="w-full h-full object-cover transition-all duration-500 sepia-full hover:sepia-75"
                  />
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

Best Practices

Maintain Design Consistency

When applying the sepia utility in Tailwind CSS, it is essential to ensure a consistent design language throughout your project. Visual continuity can enhance the user experience and create a unified aesthetic, particularly with vintage-inspired themes.

The sepia class should be incorporated in harmony with other design elements, such as color palettes, typography, and layout properties.

Leverage Utility Combinations

Combining sepia with complementary utilities can enhance your layouts significantly. Pair sepia with utilities like border, shadow, and rounded, etc. to enrich visual appeal and build sophisticated interfaces. Additionally, leverage Tailwind's typography classes to ensure coherent text alignment and consistency alongside sepia-treated images.

When combining utilities, always account for clarity and simplicity. Avoid applying too many effects, which can result in visual clutter. Use flex, grid, or utility combos like space-x-* and gap-* to maintain balance.

Accessibility Considerations

Enhance Readability and Navigability

Sepia effects can impact the readability of text and the clarity of important elements. Ensure sufficient text contrast against sepia-toned backgrounds by pairing strong text utilities like text-white, text-black, or text-gray-800. This is crucial for accessibility, especially for visually impaired users.

For navigable content like cards, headings, and focus states, use interactive utilities (hover: and focus:) to highlight elements dynamically without sacrificing usability.

Focus on High Contrast

High contrast is essential when integrating sepia into your designs to ensure accessibility for users with visual impairments. Sepia tones can reduce the contrast between foreground and background elements, making it challenging for some users to discern content. To address this, combine sepia effects with Tailwind's color utilities like bg-white or text-gray-800 to maintain legibility.

When designing interactive elements like buttons, avoid applying sepia directly to the text. Instead, use sepia for decorative backgrounds while keeping the text color distinct.

Test your designs using accessibility tools to verify that contrast ratios meet WCAG standards. Prioritize high contrast in critical areas like navigation menus, call-to-action buttons, and form fields to ensure an inclusive user experience.