Menu

Tailwind CSS Background Attachment

Background attachment is a CSS property that specifies whether a background image scrolls with the rest of the content or remains fixed. Using this property can add depth and a seamless scrolling effect to your interface.

Tailwind offers three main utilities for background attachment: bg-fixed, bg-local, and bg-scroll. These correspond to the CSS values background-attachment: fixed;, background-attachment: local;, and background-attachment: scroll;

In this guide, we'll learn how to implement the background attachment utilities of Tailwind. We'll explore its utilities, followed by techniques to conditionally apply styles using states and responsive breakpoints.

ClassPropertiesExample
bg-fixedbackground-attachment: fixed;<div className="bg-fixed"></div>
bg-localbackground-attachment: local;<div className="bg-local"></div>
bg-scrollbackground-attachment: scroll;<div className="bg-scroll"></div>

Overview of Background Attachment

Fixed Attachment

When you use the bg-fixed utility, the background will remain fixed as the rest of the page content scrolls.

This is a live editor. Play around with it!
export default function FixedBackground() {  
 return (  
   <>
     <p className="px-16 text-center text-xl py-10">Scroll this preview to see <code>bg-fixed</code> utility in action.</p>
     <div className="bg-fixed bg-contain bg-no-repeat h-[400px] w-screen bg-cover opacity-80 bg-center" style={{ backgroundImage: 'url("https://images.unsplash.com/photo-1517059224940-d4af9eec41b7")' }} />   
       <p className="px-10 py-4">  
         The <code>bg-fixed</code> utility creates a effect where the background image remains completely fixed relative to the viewport. As you scroll through this content, notice how the text moves independently while the background stays anchored in place. This creates an illusion of depth and can add a sophisticated, layered feel to your web design. The fixed background technique is particularly effective for creating immersive hero sections, story-telling interfaces, or any design where you want to create a sense of visual hierarchy through scrolling interactions.
       </p>
   </>  
  );  
}

Local Attachment

The bg-local utility makes the background scroll only inside its container, moving with the element’s content instead of the entire page.

This is a live editor. Play around with it!
export default function LocalBackground() {  
  return (  
    <>
      <p className="px-16 text-center text-xl py-10">Scroll this preview to see <code>bg-local</code> utility in action.</p>
      <div className="bg-local bg-contain bg-no-repeat h-[200px] bg-center overflow-auto" 
           style={{ backgroundImage: 'url("https://images.unsplash.com/photo-1517059224940-d4af9eec41b7")'}} >   
        <p className="px-12 bg-white/50">  
          The <code>bg-local</code> utility creates a unique scrolling experience where the background image is truly attached to the container's content. As you scroll within this container, watch how the background image moves along with the text, creating a synchronized scrolling effect. This behavior makes <code>bg-local</code> particularly useful when you want the background to be an integral part of the scrollable content, rather than just a decorative backdrop.
        </p>
      </div>
    </>
  );  
}

Scroll Attachment

The bg-scroll utility makes the background move with the viewport instead of the container. When scrolled inside the container, the background remains fixed, but when scrolling the entire page, the background moves with it.

This is a live editor. Play around with it!
export default function ScrollBackground() {  
  return (  
    <>
      <p className="px-12 text-center text-xl py-10">Scroll this preview to see <code>bg-scroll</code> utility in action.</p>
      <div className="bg-scroll bg-contain bg-no-repeat h-[200px] bg-center overflow-auto" 
           style={{ backgroundImage: 'url("https://images.unsplash.com/photo-1517059224940-d4af9eec41b7")'}} >   
        <p className="px-12 bg-white/50">  
          The <code>bg-scroll</code> utility demonstrates an interesting behavior with nested scrolling contexts. When you scroll within this container, notice how the background image stays fixed relative to the container itself. This is because the scrolling is happening within a contained context, and the background is attached to the container's viewport.
        </p>
      </div>
      
      <p className="px-12 py-8">
        Now, as you scroll the entire page (outside the container above), you'll notice a different behavior. The background image moves along with the page scroll. This demonstrates how <code>bg-scroll</code> responds differently to the main viewport scroll versus container scroll. This dual behavior makes <code>bg-scroll</code> particularly versatile for creating layered scrolling experiences.
      </p>
    </>
  );  
}

States and Responsiveness

Hover and Focus States

Tailwind allows you to conditionally apply the utility class on certain states like hover and focus. Use state modifiers like- hover, focus, etc. to apply the utility only when these states are active, e.g., hover:bg-fixed.

This is a live editor. Play around with it!
export default function HoverBackgroundChange() {  
 return (  
   <div className="h-[20rem]">
     <p className="px-20 text-center text-lg py-10">Hover to fix the background image.</p>
   <div className="hover:bg-fixed h-[400px] w-screen bg-cover opacity-80 bg-center" style={{ backgroundImage: 'url("https://images.unsplash.com/photo-1517059224940-d4af9eec41b7")' }}>   
   </div>
     <p className="px-10">  
       This example demonstrates the dynamic switching between background behaviors using hover state. Initially, the background image scrolls normally with the page. However, when you hover over the image section, the <code>hover:bg-fixed</code> utility kicks in, instantly switching the background to a fixed position relative to the viewport. This creates an interactive effect where users can temporarily "freeze" the background in place while scrolling, adding an engaging layer of interactivity to the scrolling experience. Try scrolling the page while hovering and not hovering to see the difference in background behavior.
     </p>
   </div>
 );
}

Breakpoint Modifiers

Tailwind CSS provides breakpoint modifiers to conditionally apply the utility only when the screen hits the defined breakpoint. This is especially helpful for applying effects only on specific screens. Use Tailwind's breakpoint modifiers like- sm, md, etc., to apply the utility only on these breakpoints and above.

This is a live editor. Play around with it!
export default function ResponsiveBackground() {  
 return (  
   <>
     <p className="px-16 text-center text-lg py-10">The background attachment changes based on the screen</p>
   <div className="sm:bg-fixed md:bg-local lg:bg-scroll h-[400px] w-screen bg-cover opacity-80 bg-center" style={{ backgroundImage: 'url("https://images.unsplash.com/photo-1517059224940-d4af9eec41b7")' }}>   
   </div>
     <p className="px-10">  
       This example showcases responsive background attachment behavior using Tailwind's breakpoint prefixes. On small screens (<code>sm</code>), the background becomes fixed to create a more immersive mobile experience. At medium breakpoints (<code>md</code>), it switches to <code>bg-local</code> where the background scrolls with its container's content. On larger screens (<code>lg</code>), it adopts <code>bg-scroll</code> behavior for a traditional scrolling experience. Try resizing your browser window to observe how the background attachment smoothly adapts to different screen sizes, providing an optimized viewing experience across all devices.
     </p>
   </>
 );  
}

Real World Examples

Product Categories Showcase

This component displays product categories with a fixed background effect, creating a parallax-like scrolling experience.

This is a live editor. Play around with it!
export default function ProductCategories() {
  const categories = [
    {
      id: 1,
      name: "Electronics",
      description: "Latest gadgets and devices",
      src: "https://images.unsplash.com/photo-1498049794561-7780e7231661",
      alt: "Electronics category background"
    },
    {
      id: 2,
      name: "Fashion",
      description: "Trending clothing and accessories",
      src: "https://images.unsplash.com/photo-1445205170230-053b83016050",
      alt: "Fashion category background"
    },
    {
      id: 3,
      name: "Home Decor",
      description: "Interior design essentials",
      src: "https://images.unsplash.com/photo-1513161455079-7dc1de15ef3e",
      alt: "Home decor category background"
    },
    {
      id: 4,
      name: "Sports",
      description: "Athletic gear and equipment",
      src: "https://images.unsplash.com/photo-1461896836934-ffe607ba8211",
      alt: "Sports category background"
    },
    {
      id: 5,
      name: "Books",
      description: "Literature and educational materials",
      src: "https://images.unsplash.com/photo-1495446815901-a7297e633e8d",
      alt: "Books category background"
    },
    {
      id: 6,
      name: "Beauty",
      description: "Cosmetics and personal care",
      src: "https://images.unsplash.com/photo-1522335789203-aabd1fc54bc9",
      alt: "Beauty category background"
    }
  ];

  return (
    <div className="min-h-screen">
      {categories.map((category) => (
        <div
          key={category.id}
          className="h-[50vh] bg-fixed bg-center bg-no-repeat bg-cover relative"
          style={{ backgroundImage: `url(${category.src})` }}
        >
          <div className="absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center">
            <div className="text-center text-white">
              <h2 className="text-4xl font-bold mb-2">{category.name}</h2>
              <p className="text-xl">{category.description}</p>
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

Travel Destination Cards

This component shows travel destinations with a scrollable background that remains fixed while content moves.

This is a live editor. Play around with it!
export default function TravelDestinations() {
  const destinations = [
    {
      id: 1,
      name: "Paris",
      country: "France",
      rating: 4.8,
      src: "https://images.unsplash.com/photo-1502602898657-3e91760cbb34",
      alt: "Paris cityscape"
    },
    {
      id: 2,
      name: "Tokyo",
      country: "Japan",
      rating: 4.9,
      src: "https://images.unsplash.com/photo-1503899036084-c55cdd92da26",
      alt: "Tokyo street view"
    },
    {
      id: 3,
      name: "New York",
      country: "USA",
      rating: 4.7,
      src: "https://images.unsplash.com/photo-1496442226666-8d4d0e62e6e9",
      alt: "New York skyline"
    },
    {
      id: 4,
      name: "Sydney",
      country: "Australia",
      rating: 4.6,
      src: "https://images.unsplash.com/photo-1506973035872-a4ec16b8e8d9",
      alt: "Sydney opera house"
    },
    {
      id: 5,
      name: "Dubai",
      country: "UAE",
      rating: 4.8,
      src: "https://images.unsplash.com/photo-1512453979798-5ea266f8880c",
      alt: "Dubai skyline"
    },
    {
      id: 6,
      name: "Rome",
      country: "Italy",
      rating: 4.7,
      src: "https://images.unsplash.com/photo-1525874684015-58379d421a52",
      alt: "Rome colosseum"
    }
  ];

  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-6">
      {destinations.map((destination) => (
        <div key={destination.id} className="rounded-xl overflow-hidden shadow-lg h-96">
          <div
            className="h-full bg-fixed bg-center bg-cover relative"
            style={{ backgroundImage: `url(${destination.src})` }}
          >
            <div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black to-transparent p-6">
              <h3 className="text-2xl font-bold text-white">{destination.name}</h3>
              <p className="text-white mb-2">{destination.country}</p>
              <div className="flex items-center">
                <span className="text-yellow-400"></span>
                <span className="text-white ml-1">{destination.rating}</span>
              </div>
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

Team Member Profiles

This component displays team member profiles with a fixed background header section.

This is a live editor. Play around with it!
export default function TeamProfiles() {
  const team = [
    {
      id: 1,
      name: "Sarah Johnson",
      role: "CEO",
      bio: "10+ years of leadership experience",
      src: "https://images.unsplash.com/photo-1573496359142-b8d87734a5a2",
      alt: "Sarah Johnson profile"
    },
    {
      id: 2,
      name: "Michael Chen",
      role: "CTO",
      bio: "Expert in cloud architecture",
      src: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e",
      alt: "Michael Chen profile"
    },
    {
      id: 3,
      name: "Emma Williams",
      role: "Design Director",
      bio: "Award-winning designer",
      src: "https://images.unsplash.com/photo-1580489944761-15a19d654956",
      alt: "Emma Williams profile"
    },
    {
      id: 4,
      name: "James Martinez",
      role: "Product Manager",
      bio: "Specialized in agile methodologies",
      src: "https://images.unsplash.com/photo-1519085360753-af0119f7cbe7",
      alt: "James Martinez profile"
    },
    {
      id: 5,
      name: "Lisa Thompson",
      role: "Marketing Lead",
      bio: "Digital marketing expert",
      src: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80",
      alt: "Lisa Thompson profile"
    },
    {
      id: 6,
      name: "David Wilson",
      role: "Sales Director",
      bio: "15+ years in enterprise sales",
      src: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e",
      alt: "David Wilson profile"
    }
  ];

  return (
    <div className="space-y-12">
      {team.map((member) => (
        <div key={member.id} className="relative">
          <div
            className="h-48 bg-fixed bg-center bg-cover"
            style={{ backgroundImage: `url(${member.src})` }}
          />
          <div className="bg-white shadow-lg mx-4 -mt-24 relative rounded-lg p-6">
            <div className="flex items-center space-x-4">
              <img
                src={member.src}
                alt={member.alt}
                className="w-24 h-24 rounded-full border-4 border-white"
              />
              <div>
                <h3 className="text-2xl font-bold">{member.name}</h3>
                <p className="text-gray-600">{member.role}</p>
                <p className="text-gray-500 mt-2">{member.bio}</p>
              </div>
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

Feature Section

This component presents features with a fixed background that creates depth while scrolling.

This is a live editor. Play around with it!
export default function FeatureShowcase() {
  const features = [
    {
      id: 1,
      title: "Advanced Security",
      description: "Enterprise-grade protection",
      icon: "https://images.unsplash.com/photo-1563986768609-322da13575f3",
      alt: "Security feature icon"
    },
    {
      id: 2,
      title: "Analytics Dashboard",
      description: "Real-time data insights",
      icon: "https://images.unsplash.com/photo-1551288049-bebda4e38f71",
      alt: "Analytics feature icon"
    },
    {
      id: 3,
      title: "Mobile Support",
      description: "Cross-platform compatibility",
      icon: "https://images.unsplash.com/photo-1512941937669-90a1b58e7e9c",
      alt: "Mobile feature icon"
    },
    {
      id: 4,
      title: "24/7 Support",
      description: "Round-the-clock assistance",
      icon: "https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d",
      alt: "Support feature icon"
    },
    {
      id: 5,
      title: "API Access",
      description: "Developer-friendly integration",
      icon: "https://images.unsplash.com/photo-1461749280684-dccba630e2f6",
      alt: "API feature icon"
    }
  ];

  return (
    <div className="min-h-screen">
      <div
        className="bg-fixed bg-cover bg-center h-[73rem] relative"
        style={{
          backgroundImage:
            "url('https://images.unsplash.com/photo-1451187580459-43490279c0fa')"
        }}
      >
        <div className="absolute inset-0 bg-black bg-opacity-70">
          <div className="container mx-auto px-4 py-12">
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
              {features.map((feature) => (
                <div
                  key={feature.id}
                  className="bg-white bg-opacity-10 backdrop-blur-sm rounded-xl p-6 text-white"
                >
                  <img
                    src={feature.icon}
                    alt={feature.alt}
                    className="w-16 h-16 rounded-full mb-4"
                  />
                  <h3 className="text-xl font-bold mb-2">{feature.title}</h3>
                  <p className="text-gray-200">{feature.description}</p>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

This component creates a portfolio gallery with fixed background sections for each project.

This is a live editor. Play around with it!
export default function PortfolioGallery() {
  const projects = [
    {
      id: 1,
      title: "E-commerce Platform",
      category: "Web Development",
      src: "https://images.unsplash.com/photo-1517245386807-bb43f82c33c4",
      alt: "E-commerce project"
    },
    {
      id: 2,
      title: "Mobile Banking App",
      category: "Mobile Development",
      src: "https://images.unsplash.com/photo-1563986768494-4dee2763ff3f",
      alt: "Banking app project"
    },
    {
      id: 3,
      title: "Social Media Dashboard",
      category: "UI/UX Design",
      src: "https://images.unsplash.com/photo-1460925895917-afdab827c52f",
      alt: "Dashboard project"
    },
    {
      id: 4,
      title: "Healthcare Platform",
      category: "Web Development",
      src: "https://images.unsplash.com/photo-1576091160399-112ba8d25d1d",
      alt: "Healthcare project"
    },
    {
      id: 5,
      title: "Travel Booking System",
      category: "Full Stack",
      src: "https://images.unsplash.com/photo-1488646953014-85cb44e25828",
      alt: "Travel project"
    },
    {
      id: 6,
      title: "Educational Platform",
      category: "Web Development",
      src: "https://images.unsplash.com/photo-1509062522246-3755977927d7",
      alt: "Education project"
    }
  ];

  return (
    <div className="min-h-screen">
      {projects.map((project) => (
        <div key={project.id} className="relative h-screen">
          <div
            className="h-full bg-fixed bg-cover bg-center"
            style={{ backgroundImage: `url(${project.src})` }}
          >
            <div className="absolute inset-0 bg-gradient-to-r from-black to-transparent">
              <div className="h-full flex items-center px-12">
                <div className="max-w-xl">
                  <span className="inline-block bg-white text-black px-4 py-1 rounded-full text-sm mb-4">
                    {project.category}
                  </span>
                  <h2 className="text-5xl font-bold text-white mb-6">
                    {project.title}
                  </h2>
                  <button className="bg-white text-black px-8 py-3 rounded-lg hover:bg-gray-100 transition-colors">
                    View Project
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

Best Practices

Maintain Design Consistency

Ensure that background attachment settings remain uniform across similar sections of your UI. For example, if a fixed background is applied to one section, avoid abrupt transitions to scrolling backgrounds in adjacent sections unless it serves a specific design purpose.

To maintain a consistent style, define background attachment utilities within reusable component or classes rather than assigning them directly to individual elements. Use Tailwind’s @apply directive or create React components that encapsulate the styles for repeated use. For example, grouping bg-fixed bg-cover bg-center under a fixed-background class ensures uniform background behavior across multiple sections while reducing code duplication.

Leverage Utility Combinations

When applying bg-fixed, bg-local, or bg-scroll, consider pairing them with other bg-* utilities like bg-cover,bg-center, bg-no-repeat, etc. These combinations ensure that backgrounds remain aesthetically pleasing and well-fitted to different screen sizes without unnecessary repetition or misalignment.

For example, combining bg-fixed with bg-cover ensures that the background image remains full-width while staying fixed in place, preventing awkward gaps or scaling issues. Similarly, pairing bg-scroll with bg-contain can be useful for patterns or smaller textures that should not be stretched to fill an area.

Accessibility Considerations

Enhance Readability and Navigability

Background attachment settings should never compromise text readability. When using bg-fixed or bg-scroll, ensure that foreground text remains clearly distinguishable from the background. Overlay techniques, such as applying a semi-transparent backdrop, can enhance legibility without reducing aesthetic appeal.

For content-heavy sections, maintaining adequate spacing and contrast helps prevent background images from interfering with readability. Ensuring sufficient padding around text elements also prevents background distractions from affecting readability, particularly for users with cognitive impairments.

Support Accessible Interactive Elements

Interactive elements, such as buttons and links, should remain distinguishable even when placed over background-attached sections. Applying bg-fixed on sections with clickable elements can sometimes create visibility challenges, especially if the background shifts unexpectedly. To enhance visibility, apply background colors to buttons to ensure that they stand out against the background.

Ensuring clear hover states and focus outlines is also important. Using Tailwind’s focus:ring-* or hover:bg-opacity-* enhances visual feedback, improving accessibility for users navigating through interactive sections. Additionally, maintain sufficient padding around clickable elements to prevent unintended interactions caused by background behavior.