We are still cooking the magic in the way!
Backgrounds: Color, Image, Size, Position
Introduction to CSS Backgrounds
CSS backgrounds are one of the most powerful visual tools available to web developers. They allow you to add colors, images, gradients, and patterns behind any HTML element. Backgrounds are essential for creating visually engaging web designs -- from simple colored sections to complex hero images, textured patterns, and layered visual effects. In this lesson, we will explore every background property in detail, understand how they work together, and learn when to use background images versus <img> elements.
Every HTML element has a background layer that sits behind its content, padding, and (by default) extends to the edge of its border. Understanding how backgrounds interact with the box model is critical for controlling their appearance. By default, an element's background is transparent, meaning you can see through to whatever is behind it -- whether that is the parent element's background, the body background, or the browser's default white canvas.
The background-color Property
The background-color property sets a solid color behind an element's content and padding areas. This is the simplest and most commonly used background property. It accepts any valid CSS color value.
Basic background-color Usage
/* Named colors */
.header {
background-color: navy;
}
/* Hexadecimal */
.card {
background-color: #f5f5f5;
}
/* RGB */
.sidebar {
background-color: rgb(240, 240, 240);
}
/* RGBA (with transparency) */
.overlay {
background-color: rgba(0, 0, 0, 0.5);
}
/* HSL */
.banner {
background-color: hsl(210, 100%, 50%);
}
/* HSLA */
.modal-backdrop {
background-color: hsla(0, 0%, 0%, 0.7);
}
/* Transparent (default value) */
.glass-effect {
background-color: transparent;
}
/* currentColor keyword -- uses the element's text color */
.highlight {
color: #e74c3c;
background-color: currentColor; /* Same red as text */
}
The background-color is always rendered behind any background-image. This means you should always set a background-color as a fallback when using background images -- if the image fails to load, the user will still see a reasonable color instead of nothing. This is especially important for accessibility, as text over a background image without a fallback color can become unreadable if the image does not load.
Fallback Color with Background Image
.hero {
background-color: #2c3e50; /* Fallback: dark blue */
background-image: url('hero-bg.jpg');
}
/* If hero-bg.jpg fails to load, the dark blue
still provides contrast for white text */
.hero h1 {
color: white;
}
rgba() or hsla() are incredibly useful for creating overlay effects. A common pattern is placing a semi-transparent dark background over an image to improve text readability: background-color: rgba(0, 0, 0, 0.6);The background-image Property
The background-image property places one or more images behind an element. Unlike <img> elements in HTML, background images are purely decorative -- they are not part of the document's content, cannot have alt text, and are not announced by screen readers. This makes them ideal for visual decoration but unsuitable for content images.
Basic background-image Usage
/* URL to an image file */
.hero {
background-image: url('images/hero-bg.jpg');
}
/* Absolute URL */
.banner {
background-image: url('https://example.com/images/banner.png');
}
/* Without quotes (valid but quotes recommended) */
.section {
background-image: url(pattern.svg);
}
/* Gradient as background image */
.gradient-section {
background-image: linear-gradient(to right, #667eea, #764ba2);
}
/* Remove a background image */
.plain {
background-image: none;
}
The url() function can accept relative or absolute paths. Relative paths are resolved relative to the CSS file's location, not the HTML file. This is an important distinction -- if your CSS file is in /css/styles.css and you write url('images/bg.jpg'), the browser looks for /css/images/bg.jpg, not /images/bg.jpg. To reference files relative to the site root, use url('/images/bg.jpg') with a leading slash.
Multiple Background Images
CSS allows you to layer multiple background images on a single element. Images are listed in comma-separated order, with the first image on top (closest to the viewer) and the last image on the bottom. This is a powerful technique for creating complex visual effects without additional HTML elements.
Layering Multiple Backgrounds
.complex-bg {
background-image:
url('overlay-pattern.png'), /* Top layer */
url('decorative-shape.svg'), /* Middle layer */
url('main-background.jpg'); /* Bottom layer */
background-repeat:
repeat, /* Pattern repeats */
no-repeat, /* Shape shows once */
no-repeat; /* Main bg shows once */
background-position:
0 0, /* Pattern starts top-left */
right bottom, /* Shape in bottom-right */
center center; /* Main bg centered */
background-size:
auto, /* Pattern at natural size */
200px 200px, /* Shape fixed dimensions */
cover; /* Main bg covers element */
}
background-repeat values, the third image uses the first value again.The background-repeat Property
By default, background images tile (repeat) both horizontally and vertically to fill the entire element. The background-repeat property controls this behavior. Understanding repeat options is essential for working with patterns, textures, and single images.
All background-repeat Values
/* Default: repeats in both directions */
.pattern {
background-image: url('tile.png');
background-repeat: repeat;
}
/* Repeat only horizontally */
.horizontal-stripe {
background-image: url('stripe.png');
background-repeat: repeat-x;
}
/* Repeat only vertically */
.vertical-stripe {
background-image: url('stripe.png');
background-repeat: repeat-y;
}
/* No repeating -- show image once */
.logo-bg {
background-image: url('logo.png');
background-repeat: no-repeat;
}
/* Space: repeat without clipping, add gaps between tiles */
.spaced-pattern {
background-image: url('icon.png');
background-repeat: space;
}
/* Round: repeat without clipping, resize tiles to fit */
.rounded-pattern {
background-image: url('icon.png');
background-repeat: round;
}
/* Two-value syntax: horizontal vertical */
.mixed {
background-image: url('tile.png');
background-repeat: repeat no-repeat; /* Repeat X only */
}
.fancy {
background-image: url('tile.png');
background-repeat: space round; /* Space horizontally, round vertically */
}
The space and round values are particularly useful and often overlooked. The space value distributes copies of the image evenly across the element, adding whitespace between them so that no tile is ever partially cut off at the edges. The round value similarly prevents clipping, but instead of adding space, it stretches or shrinks the tiles so that a whole number of them fit exactly within the element. Both values eliminate the jarring visual effect of a background tile being cut off at the edge of its container.
background-repeat lets you control horizontal and vertical repetition independently. For example, background-repeat: repeat-x is equivalent to background-repeat: repeat no-repeat. The two-value syntax gives you combinations that the single keywords cannot express, like space round.The background-position Property
The background-position property controls where a background image is placed within its container. By default, a background image is positioned at the top-left corner of the element (0% 0%). This property is especially important when using background-repeat: no-repeat, as it determines exactly where the single image appears.
Keyword Positioning
/* Single keyword (other axis defaults to center) */
.top {
background-position: top; /* top center */
}
.bottom {
background-position: bottom; /* bottom center */
}
.left {
background-position: left; /* center left */
}
.right {
background-position: right; /* center right */
}
.centered {
background-position: center; /* center center */
}
/* Two keywords */
.top-left {
background-position: top left;
}
.bottom-right {
background-position: bottom right;
}
.center-top {
background-position: center top;
}
Percentage and Pixel Positioning
/* Percentage values: position of image relative to container */
.example1 {
background-position: 50% 50%; /* Centered (same as center center) */
}
.example2 {
background-position: 0% 0%; /* Top-left (same as top left) */
}
.example3 {
background-position: 100% 100%; /* Bottom-right */
}
.example4 {
background-position: 25% 75%; /* 25% from left, 75% from top */
}
/* Pixel offsets from top-left corner */
.pixel-offset {
background-position: 20px 30px; /* 20px from left, 30px from top */
}
/* Mix units */
.mixed {
background-position: 50% 20px; /* Centered horizontally, 20px from top */
}
Percentage positioning works differently than you might expect. When you write background-position: 25% 75%, the browser aligns the point that is 25% across the image with the point that is 25% across the container, and similarly for the vertical axis. This means 50% 50% perfectly centers the image regardless of the image or container dimensions. Pixel values, by contrast, simply offset the top-left corner of the image from the top-left corner of the container.
Edge Offset Syntax (4-Value)
/* Offset from specific edges */
.edge-offset {
/* 20px from the right edge, 30px from the bottom edge */
background-position: right 20px bottom 30px;
}
.another {
/* 10px from the left edge, 50px from the top edge */
background-position: left 10px top 50px;
}
/* Useful for placing icons or decorative elements */
.card-icon {
background-image: url('icon.svg');
background-repeat: no-repeat;
background-position: right 15px top 15px;
padding-right: 50px; /* Make room for the icon */
}
background-position: right 20px bottom 30px means "place the image 20px from the right edge and 30px from the bottom edge" -- this stays consistent regardless of the element's size.The background-size Property
The background-size property controls the dimensions of a background image. Without this property, images display at their natural (intrinsic) size, which may not match the container's dimensions. This property is critical for responsive design and for making background images adapt to different screen sizes.
All background-size Values
/* auto: natural size (default) */
.natural {
background-size: auto;
}
/* Specific dimensions: width height */
.fixed-size {
background-size: 300px 200px;
}
/* One value: width only, height becomes auto (maintains aspect ratio) */
.width-only {
background-size: 300px;
/* Equivalent to: background-size: 300px auto; */
}
/* Percentage of the container */
.percentage {
background-size: 50% 100%; /* Half width, full height */
}
/* cover: scale to fill entire container (may crop) */
.hero-cover {
background-size: cover;
}
/* contain: scale to fit inside container (may leave empty space) */
.logo-contain {
background-size: contain;
}
cover vs contain
The two most important keyword values for background-size are cover and contain. Understanding the difference is essential for responsive background images.
cover scales the image to be as small as possible while still completely covering the container area. The image will fill the entire element with no empty space, but parts of the image may be cropped (hidden) if the image's aspect ratio does not match the container's aspect ratio. This is the most common choice for full-screen hero backgrounds and card images.
contain scales the image to be as large as possible while still fitting entirely inside the container. The entire image is always visible, but there may be empty space (letterboxing) on the sides or top and bottom if the aspect ratios do not match. This is ideal for logos or images where you need to guarantee the entire image is visible.
cover vs contain in Practice
/* Hero section: image fills entire area, cropping is acceptable */
.hero {
width: 100%;
height: 80vh;
background-image: url('landscape.jpg');
background-size: cover;
background-position: center center; /* Control which part is visible */
background-repeat: no-repeat;
}
/* Logo display: entire logo must be visible */
.company-logo {
width: 200px;
height: 100px;
background-image: url('logo.png');
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
/* Pattern: specific tile size that repeats */
.tile-pattern {
background-image: url('tile.svg');
background-size: 40px 40px;
background-repeat: repeat;
}
background-size: cover on very large images can cause performance problems, especially on mobile devices. Always optimize your images for the web -- compress them, use modern formats like WebP or AVIF, and consider serving different image sizes for different screen sizes using media queries.The background-attachment Property
The background-attachment property determines whether a background image scrolls with the element's content or stays fixed in place relative to the viewport. This property is key to creating parallax-like scrolling effects.
background-attachment Values
/* scroll (default): background scrolls with the element */
.normal {
background-attachment: scroll;
}
/* fixed: background stays fixed relative to the viewport */
.parallax {
background-image: url('mountains.jpg');
background-attachment: fixed;
background-size: cover;
background-position: center;
}
/* local: background scrolls with the element's content */
.scrollable-box {
width: 300px;
height: 200px;
overflow: auto;
background-image: url('watermark.png');
background-attachment: local;
background-repeat: no-repeat;
background-position: center;
}
The difference between scroll and local is subtle but important. With scroll (the default), the background is fixed relative to the element itself -- it does not move when you scroll the element's content (in an overflow-scrollable container). With local, the background scrolls along with the element's content. The fixed value makes the background fixed relative to the viewport, creating a parallax effect where the background appears stationary while content scrolls over it.
background-attachment: fixed property has known performance issues on mobile devices. Many mobile browsers either ignore it or render it poorly because fixed backgrounds interfere with smooth scrolling optimizations. Consider using JavaScript-based parallax solutions or simply avoiding fixed backgrounds on mobile. You can use a media query to disable it: @media (max-width: 768px) { .parallax { background-attachment: scroll; } }The background-origin Property
The background-origin property defines the positioning area for background images -- in other words, where the background image's coordinate system begins. It determines the reference point for background-position and affects where background tiling starts.
background-origin Values
/* padding-box (default): background starts from the padding edge */
.default-origin {
background-origin: padding-box;
}
/* border-box: background starts from the border edge */
.border-origin {
border: 20px dashed rgba(0, 0, 0, 0.3);
padding: 30px;
background-image: url('pattern.png');
background-origin: border-box;
/* Image starts from behind the border */
}
/* content-box: background starts from the content edge */
.content-origin {
padding: 30px;
background-image: url('logo.svg');
background-origin: content-box;
background-repeat: no-repeat;
background-position: top left;
/* Image starts from top-left of the content area, not padding */
}
background-origin property only affects background positioning and tiling -- it does not change the area where the background is actually painted. That is controlled by background-clip. These two properties are often confused, but they serve different purposes.The background-clip Property
While background-origin controls where the background image starts, background-clip controls where the background is actually visible -- it clips the background to a specific area of the box model. This property affects both background-color and background-image.
background-clip Values
/* border-box (default): background extends behind the border */
.default-clip {
background-clip: border-box;
}
/* padding-box: background stops at the padding edge (not behind border) */
.padding-clip {
border: 10px dashed #333;
background-color: #3498db;
background-clip: padding-box;
/* The dashed border shows the parent's background through the gaps */
}
/* content-box: background only in the content area */
.content-clip {
padding: 30px;
background-color: #e74c3c;
background-clip: content-box;
/* Padding area is transparent, creating a visual inset effect */
}
/* text: background only visible through text (clip to text shape) */
.gradient-text {
background-image: linear-gradient(45deg, #f093fb, #f5576c, #4facfe);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
font-size: 4rem;
font-weight: bold;
}
The text value for background-clip is one of the most visually striking CSS effects available. It clips the background to the shape of the text, allowing you to fill text with gradients, images, or patterns. Note that you must also set the text color to transparent (using either color: transparent or -webkit-text-fill-color: transparent) for the background to show through. The -webkit- prefix is still required for broad browser support of the text value.
Creative background-clip: text Examples
/* Image-filled text */
.image-text {
background-image: url('forest.jpg');
background-size: cover;
background-position: center;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
font-size: 6rem;
font-weight: 900;
}
/* Animated gradient text */
.animated-text {
background-image: linear-gradient(90deg, #ff6b6b, #feca57, #48dbfb, #ff6b6b);
background-size: 300% 100%;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
animation: gradient-shift 3s ease infinite;
}
@keyframes gradient-shift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
The background Shorthand Property
CSS provides a background shorthand property that lets you set all background properties in a single declaration. While convenient, this shorthand has specific rules about order and syntax that you need to understand to use it correctly.
Background Shorthand Syntax
/* Full syntax */
.element {
background: [color] [image] [position] / [size] [repeat] [attachment] [origin] [clip];
}
/* Simple examples */
.simple {
background: #f5f5f5;
}
.with-image {
background: url('bg.jpg') center / cover no-repeat;
}
.complete {
background: #2c3e50 url('pattern.png') top left / 100px 100px repeat fixed;
}
/* Equivalent longhand */
.complete-longhand {
background-color: #2c3e50;
background-image: url('pattern.png');
background-position: top left;
background-size: 100px 100px;
background-repeat: repeat;
background-attachment: fixed;
}
background shorthand resets all omitted background properties to their default values. If you write background: red;, it also resets background-image to none, background-position to 0% 0%, background-size to auto, and so on. This can accidentally remove a previously set background image. To avoid this, either specify all values in the shorthand or use individual properties.The / (slash) syntax is critical when using background-size in the shorthand. The background-size must come immediately after background-position, separated by a forward slash. Without the slash, the browser cannot distinguish position values from size values. For example, center / cover means "position: center, size: cover" while center cover would be interpreted incorrectly.
Multiple Backgrounds in Shorthand
/* Multiple backgrounds separated by commas */
.layered {
background:
url('top-pattern.svg') top left / 50px 50px repeat,
url('decoration.png') right 20px bottom 20px / 100px no-repeat,
linear-gradient(to bottom, #667eea, #764ba2);
/* Note: background-color can only be on the LAST layer */
}
/* Equivalent longhand for the above */
.layered-longhand {
background-image:
url('top-pattern.svg'),
url('decoration.png'),
linear-gradient(to bottom, #667eea, #764ba2);
background-position:
top left,
right 20px bottom 20px,
0 0;
background-size:
50px 50px,
100px,
auto;
background-repeat:
repeat,
no-repeat,
no-repeat;
}
background-color can only be specified on the last (bottom-most) layer. If you try to include a color in an earlier layer, the browser will ignore it. This makes sense conceptually -- the background color sits behind all image layers.Background Images vs <img> Elements
Knowing when to use a CSS background image versus an HTML <img> element is an important design decision that affects accessibility, SEO, and performance.
Use a CSS background image when:
- The image is purely decorative (patterns, textures, visual flair)
- The image is part of the design, not the content
- You need the image behind text or other content
- You want the image to fill a container regardless of aspect ratio
- The image should not appear when the page is printed
- You need multiple layered images on one element
Use an HTML <img> element when:
- The image is content (product photos, article images, charts)
- The image needs alt text for accessibility and screen readers
- The image should be indexed by search engines for SEO
- You need lazy loading with the
loading="lazy"attribute - You need responsive images with
srcsetandsizes - The image should be visible when the page is printed
- The image is part of the document flow and affects layout
background-size: cover is convenient. While it works visually, you sacrifice accessibility (no alt text), SEO (search engines may not index the image), and responsive image capabilities. For content images that need to fill a container, use an <img> with object-fit: cover instead -- it provides the same visual effect with proper semantics.Performance Considerations for Background Images
Background images can significantly impact page performance if not managed carefully. Here are key strategies for optimizing background image performance:
- Optimize file size: Compress images using tools like TinyPNG, Squoosh, or ImageOptim. Use modern formats like WebP (30-50% smaller than JPEG) or AVIF (even smaller) with fallbacks.
- Use appropriate dimensions: Do not use a 4000px wide image for a 400px wide element. Resize images to match their display size (accounting for high-DPI screens -- typically 2x the display size).
- Consider lazy loading: Background images load immediately. For below-the-fold sections, use Intersection Observer API to add background images only when sections scroll into view.
- Avoid large images on mobile: Use media queries to serve smaller background images on mobile devices.
- Use CSS gradients instead of images: Simple patterns like stripes, dots, and color transitions can often be replicated with CSS gradients, which are resolution-independent and load instantly.
Responsive Background Images with Media Queries
/* Mobile-first: small image by default */
.hero {
background-image: url('hero-small.jpg');
background-size: cover;
background-position: center;
}
/* Tablet: medium image */
@media (min-width: 768px) {
.hero {
background-image: url('hero-medium.jpg');
}
}
/* Desktop: large image */
@media (min-width: 1200px) {
.hero {
background-image: url('hero-large.jpg');
}
}
/* High-DPI (Retina) displays */
@media (-webkit-min-device-pixel-ratio: 2),
(min-resolution: 192dpi) {
.hero {
background-image: url('hero-large-2x.jpg');
}
}
Practical Examples
Example 1: Full-Screen Hero Section
Hero Section with Dark Overlay
<!-- HTML -->
<section class="hero">
<div class="hero-content">
<h1>Welcome to Our Site</h1>
<p>Building amazing web experiences</p>
</div>
</section>
/* CSS */
.hero {
position: relative;
width: 100%;
height: 100vh;
background:
linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.7)),
url('hero-landscape.jpg') center / cover no-repeat;
display: flex;
align-items: center;
justify-content: center;
}
.hero-content {
text-align: center;
color: white;
}
.hero-content h1 {
font-size: 3.5rem;
margin-bottom: 1rem;
}
.hero-content p {
font-size: 1.5rem;
opacity: 0.9;
}
Example 2: Card with Background Pattern
Decorative Card Background
.card {
background-color: #ffffff;
background-image:
radial-gradient(circle at 100% 0%, rgba(52, 152, 219, 0.1) 0%, transparent 50%),
radial-gradient(circle at 0% 100%, rgba(231, 76, 60, 0.1) 0%, transparent 50%);
border-radius: 12px;
padding: 2rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
/* Card with subtle dot pattern */
.card-dotted {
background-color: #fafafa;
background-image: radial-gradient(circle, #ddd 1px, transparent 1px);
background-size: 20px 20px;
border-radius: 12px;
padding: 2rem;
}
Example 3: Parallax Sections
Alternating Parallax and Content Sections
.parallax-section {
height: 60vh;
background-attachment: fixed;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
display: flex;
align-items: center;
justify-content: center;
color: white;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
.parallax-1 {
background-image: url('mountain.jpg');
}
.parallax-2 {
background-image: url('ocean.jpg');
}
.content-section {
padding: 4rem 2rem;
background-color: #fff;
}
/* Disable parallax on mobile for performance */
@media (max-width: 768px) {
.parallax-section {
background-attachment: scroll;
height: 40vh;
}
}
Example 4: CSS-Only Pattern Backgrounds
Pure CSS Patterns (No Image Files Needed)
/* Diagonal stripes */
.diagonal-stripes {
background-color: #3498db;
background-image: repeating-linear-gradient(
45deg,
transparent,
transparent 10px,
rgba(255, 255, 255, 0.1) 10px,
rgba(255, 255, 255, 0.1) 20px
);
}
/* Polka dots */
.polka-dots {
background-color: #2c3e50;
background-image:
radial-gradient(circle, rgba(255, 255, 255, 0.15) 10%, transparent 11%),
radial-gradient(circle, rgba(255, 255, 255, 0.15) 10%, transparent 11%);
background-size: 30px 30px;
background-position: 0 0, 15px 15px;
}
/* Grid lines */
.grid-bg {
background-color: #ffffff;
background-image:
linear-gradient(rgba(0, 0, 0, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 0, 0, 0.05) 1px, transparent 1px);
background-size: 20px 20px;
}
background-clip: padding-box with a dashed border so the parent background shows through the border gaps.
background-clip: text to fill the text with a gradient. Make the gradient animate smoothly from left to right using CSS keyframe animations. Ensure you include the -webkit- vendor prefixes for maximum browser compatibility.