🎒Using Gradient Colors and Background Images
These are powerful tools to create visually appealing UI elements without external images, and offer great flexibility for modern designs.
✅ CSS Gradients
Gradients are smooth transitions between two or more colors and are treated as background images in CSS.
Master Code Block for further usage:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Gradient Box</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div class="box">
<h2>Gradient Box</h2>
<p>This box has a gradient background.</p>
</div>
</body>
</html>Creates a gradient along a straight line (default: top to bottom).
Syntax:
background: linear-gradient(direction, color-stop1, color-stop2, ...);.box {
background: linear-gradient(to right, #3498db, #9b59b6);
border-radius: 10px;
max-width: 400px;
margin: 50px auto;
}Direction options:
to right, to left, to top, to bottom
or use angles like 45deg
.box {
background: linear-gradient(
45deg,
#e74c3c,
#f1c40f
); /* red to yellow at 45 degrees */
padding: 2rem;
border-radius: 12px;
max-width: 400px;
}Radiates from a center point outward in a circular or elliptical shape.
Syntax:
background: radial-gradient(shape size at position, start-color, ..., last-color);
.box {
background: radial-gradient(circle, #1abc9c, #2ecc71); /* Teal to Green */
padding: 2rem;
border-radius: 12px;
max-width: 400px;
margin: 60px auto;
}Shapes:
circle(default),ellipse
Positioning:
.box {
background: radial-gradient(
at top left,
#e91e63,
#3f51b5
); /* Pink to Indigo */
padding: 2rem;
border-radius: 12px;
max-width: 420px;
margin: 60px auto;
}Rotates around a central point, like a pie chart.
Syntax:
background: conic-gradient([from angle] [at position,] color [degree], color [degree], ...);.box {
width: 300px;
height: 300px;
margin: 60px auto;
padding: 1.5rem;
border-radius: 50%;
background: conic-gradient(from 0deg, red, yellow, green, blue, red);
}
/* Another example */
background: conic-gradient(red 45deg, yellow 90deg, green 210deg);You can control where color changes occur:
.box {
background: linear-gradient(to bottom, #2980b9 0%, #6dd5fa 50%, #ffffff 100%);
padding: 2rem;
border-radius: 12px;
max-width: 420px;
margin: 60px auto;
}<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Gradients</title>
<style>
.infographic-gradients {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
box-sizing: border-box;
margin: 0 auto;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: var(--paper);
color: var(--ink);
border-radius: 14px;
overflow: hidden;
}
.infographic-gradients[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.gr-inner { padding: 0.5rem; }
.gr-layout { display: flex; flex-direction: column; gap: 1.2rem; }
.gr-typebar {
display: flex;
border: 1px solid var(--line);
border-radius: 999px;
overflow: hidden;
align-self: flex-start;
}
.gr-type-btn {
border: none;
background: var(--paper);
color: var(--ink-soft);
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.75rem;
font-weight: 700;
padding: 0.4rem 0.9rem;
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease;
}
.gr-type-btn + .gr-type-btn { border-left: 1px solid var(--line); }
.gr-type-btn.gr-type-on { background: var(--accent); color: #ffffff; }
.gr-code-wrap {
background: #0b0b0b;
border: 1px solid #2a2a2a;
border-radius: 10px;
overflow: hidden;
}
.gr-filetabs {
display: flex;
background: #161616;
border-bottom: 1px solid #2a2a2a;
}
.gr-filetab {
border: none;
background: transparent;
color: #8a8a8a;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.78rem;
font-weight: 700;
padding: 0.6rem 1rem;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.gr-filetab:hover { color: #e5e5e5; }
.gr-filetab.gr-tab-on {
color: #ffffff;
border-bottom-color: #5b8def;
background: #0b0b0b;
}
.gr-code {
padding: 1rem 1.8rem 1rem 0.9rem;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.8rem;
line-height: 1.85;
overflow-x: auto;
}
.gr-codepane { display: none; }
.gr-codepane.gr-pane-on { display: block; }
.gr-line { display: block; white-space: pre; color: #e5e5e5; padding: 0.05rem 0.4rem; border-radius: 5px; }
.gr-line.gr-hl { background: #1c2333; box-shadow: inset 3px 0 0 #5b8def; color: #ffffff; }
.gr-tag { color: #60a5fa; font-weight: 700; }
.gr-attr { color: #f2b96b; }
.gr-str { color: #9ece6a; }
.gr-sel { color: #f472b6; font-weight: 700; }
.gr-prop { color: #c586c0; }
.gr-val { color: #ce9178; }
.gr-browser {
border: 1px solid var(--line);
border-radius: 10px;
overflow: hidden;
background: var(--paper);
}
.gr-browser-bar {
background: var(--paper-alt);
padding: 0.5rem 0.7rem;
display: flex;
align-items: center;
gap: 0.5rem;
border-bottom: 1px solid var(--line);
}
.gr-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--line); }
.gr-tab {
background: var(--paper);
border: 1px solid var(--line);
border-bottom: none;
border-radius: 6px 6px 0 0;
font-size: 0.72rem;
color: var(--ink-soft);
padding: 0.25rem 0.6rem;
}
.gr-screen {
background: #f5f5f5;
padding: 1.4rem;
display: flex;
justify-content: center;
}
.gr-out-box {
width: 100%;
max-width: 340px;
padding: 1.6rem;
border-radius: 12px;
box-sizing: border-box;
font-family: sans-serif;
color: white;
text-shadow: 0 1px 3px rgba(0,0,0,0.35);
}
.gr-out-box h2 { margin: 0 0 0.4rem 0; font-size: 1.15rem; }
.gr-out-box p { margin: 0; font-size: 0.85rem; opacity: 0.95; }
.gr-controls {
background: var(--paper-alt);
padding: 0.7rem 0.9rem 0.9rem;
border-top: 1px solid var(--line);
}
.gr-control-group { display: none; flex-direction: column; gap: 0.6rem; }
.gr-control-group.gr-group-on { display: flex; }
.gr-control-row {
display: flex;
align-items: center;
gap: 0.6rem;
flex-wrap: wrap;
}
.gr-control-label {
font-size: 0.72rem;
color: var(--ink-soft);
font-family: "SFMono-Regular", Consolas, monospace;
min-width: 80px;
}
.gr-segmented {
display: flex;
border: 1px solid var(--line);
border-radius: 999px;
overflow: hidden;
flex-wrap: wrap;
}
.gr-seg-btn {
border: none;
background: var(--paper);
color: var(--ink-soft);
font-family: "SFMono-Regular", Consolas, monospace;
font-size: 0.68rem;
font-weight: 700;
padding: 0.32rem 0.6rem;
cursor: pointer;
white-space: nowrap;
transition: background 0.15s ease, color 0.15s ease;
}
.gr-seg-btn + .gr-seg-btn { border-left: 1px solid var(--line); }
.gr-seg-btn.gr-seg-on { background: var(--accent); color: #ffffff; }
.gr-range {
flex: 1;
min-width: 90px;
accent-color: var(--accent);
cursor: pointer;
}
.gr-readout {
font-size: 0.72rem;
color: var(--ink);
font-weight: 700;
font-family: "SFMono-Regular", Consolas, monospace;
min-width: 40px;
}
.gr-color-input {
width: 24px;
height: 24px;
border: 1px solid var(--line);
border-radius: 6px;
padding: 0;
cursor: pointer;
background: none;
}
.gr-note {
font-size: 0.82rem;
color: var(--ink-soft);
padding: 0 0.2rem;
}
.gr-note strong { color: var(--ink); }
.gr-note code {
font-family: "SFMono-Regular", Consolas, monospace;
background: var(--paper-alt);
padding: 0.05rem 0.3rem;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="infographic-gradients" id="gr-root">
<div class="gr-inner">
<div class="gr-layout">
<div class="gr-typebar" id="gr-typebar">
<button class="gr-type-btn gr-type-on" data-type="linear">Linear</button>
<button class="gr-type-btn" data-type="radial">Radial</button>
<button class="gr-type-btn" data-type="conic">Conic</button>
<button class="gr-type-btn" data-type="multistop">Multi-Stop</button>
</div>
<div class="gr-code-wrap">
<div class="gr-filetabs">
<button class="gr-filetab gr-tab-on" id="gr-tab-css">style.css</button>
<button class="gr-filetab" id="gr-tab-html">index.html</button>
</div>
<div class="gr-code">
<div class="gr-codepane gr-pane-on" id="gr-pane-css">
<span class="gr-line"><span class="gr-sel">.box</span> {</span>
<span class="gr-line gr-hl" id="gr-bg-line"> <span class="gr-prop">background</span>: <span class="gr-val" id="gr-bg-value">linear-gradient(to right, #3498db, #9b59b6)</span>;</span>
<span class="gr-line"> <span class="gr-prop">border-radius</span>: <span class="gr-val">12px</span>;</span>
<span class="gr-line"> <span class="gr-prop">max-width</span>: <span class="gr-val">400px</span>;</span>
<span class="gr-line"> <span class="gr-prop">padding</span>: <span class="gr-val">2rem</span>;</span>
<span class="gr-line"> <span class="gr-prop">margin</span>: <span class="gr-val">50px auto</span>;</span>
<span class="gr-line">}</span>
</div>
<div class="gr-codepane" id="gr-pane-html">
<span class="gr-line"><<span class="gr-tag">div</span> <span class="gr-attr">class</span>=<span class="gr-str">"box"</span>></span>
<span class="gr-line"> <<span class="gr-tag">h2</span>>Gradient Box</<span class="gr-tag">h2</span>></span>
<span class="gr-line"> <<span class="gr-tag">p</span>>This box has a gradient background.</<span class="gr-tag">p</span>></span>
<span class="gr-line"></<span class="gr-tag">div</span>></span>
</div>
</div>
</div>
<div class="gr-browser">
<div class="gr-browser-bar">
<span class="gr-dot"></span><span class="gr-dot"></span><span class="gr-dot"></span>
<div class="gr-tab">🌐 Gradient Box</div>
</div>
<div class="gr-screen">
<div class="gr-out-box" id="gr-out-box">
<h2>Gradient Box</h2>
<p>This box has a gradient background.</p>
</div>
</div>
<div class="gr-controls">
<div class="gr-control-group gr-group-on" id="gr-group-linear">
<div class="gr-control-row">
<span class="gr-control-label">direction</span>
<div class="gr-segmented" id="gr-linear-dir">
<button class="gr-seg-btn gr-seg-on" data-dir="to right">to right</button>
<button class="gr-seg-btn" data-dir="to left">to left</button>
<button class="gr-seg-btn" data-dir="to top">to top</button>
<button class="gr-seg-btn" data-dir="to bottom">to bottom</button>
</div>
</div>
<div class="gr-control-row">
<span class="gr-control-label">or angle</span>
<input type="range" class="gr-range" id="gr-linear-angle" min="0" max="360" step="5" value="90">
<span class="gr-readout" id="gr-linear-angle-readout">90deg</span>
</div>
<div class="gr-control-row">
<span class="gr-control-label">colors</span>
<input type="color" class="gr-color-input" id="gr-linear-c1" value="#3498db">
<input type="color" class="gr-color-input" id="gr-linear-c2" value="#9b59b6">
</div>
</div>
<div class="gr-control-group" id="gr-group-radial">
<div class="gr-control-row">
<span class="gr-control-label">shape</span>
<div class="gr-segmented" id="gr-radial-shape">
<button class="gr-seg-btn gr-seg-on" data-shape="circle">circle</button>
<button class="gr-seg-btn" data-shape="ellipse">ellipse</button>
</div>
</div>
<div class="gr-control-row">
<span class="gr-control-label">position</span>
<div class="gr-segmented" id="gr-radial-pos">
<button class="gr-seg-btn gr-seg-on" data-pos="center">center</button>
<button class="gr-seg-btn" data-pos="top left">top left</button>
<button class="gr-seg-btn" data-pos="top right">top right</button>
<button class="gr-seg-btn" data-pos="bottom left">bottom left</button>
</div>
</div>
<div class="gr-control-row">
<span class="gr-control-label">colors</span>
<input type="color" class="gr-color-input" id="gr-radial-c1" value="#1abc9c">
<input type="color" class="gr-color-input" id="gr-radial-c2" value="#2ecc71">
</div>
</div>
<div class="gr-control-group" id="gr-group-conic">
<div class="gr-control-row">
<span class="gr-control-label">from angle</span>
<input type="range" class="gr-range" id="gr-conic-angle" min="0" max="360" step="5" value="0">
<span class="gr-readout" id="gr-conic-angle-readout">0deg</span>
</div>
</div>
<div class="gr-control-group" id="gr-group-multistop">
<div class="gr-control-row">
<span class="gr-control-label">middle stop</span>
<input type="range" class="gr-range" id="gr-multi-pos" min="10" max="90" step="5" value="50">
<span class="gr-readout" id="gr-multi-pos-readout">50%</span>
</div>
<div class="gr-control-row">
<span class="gr-control-label">colors</span>
<input type="color" class="gr-color-input" id="gr-multi-c1" value="#2980b9">
<input type="color" class="gr-color-input" id="gr-multi-c2" value="#6dd5fa">
<input type="color" class="gr-color-input" id="gr-multi-c3" value="#ffffff">
</div>
</div>
</div>
</div>
<div class="gr-note" id="gr-note">
<strong>linear-gradient</strong> blends colors along a straight line — set a preset keyword direction like <code>to right</code>, or a precise angle in degrees. Both do the same job; angle just gives finer control.
</div>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.getElementById('gr-root');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
})();
(function () {
const tabCss = document.getElementById('gr-tab-css');
const tabHtml = document.getElementById('gr-tab-html');
const paneCss = document.getElementById('gr-pane-css');
const paneHtml = document.getElementById('gr-pane-html');
tabCss.addEventListener('click', () => {
tabCss.classList.add('gr-tab-on');
tabHtml.classList.remove('gr-tab-on');
paneCss.classList.add('gr-pane-on');
paneHtml.classList.remove('gr-pane-on');
});
tabHtml.addEventListener('click', () => {
tabHtml.classList.add('gr-tab-on');
tabCss.classList.remove('gr-tab-on');
paneHtml.classList.add('gr-pane-on');
paneCss.classList.remove('gr-pane-on');
});
const typeButtons = document.querySelectorAll('.gr-type-btn');
const groups = {
linear: document.getElementById('gr-group-linear'),
radial: document.getElementById('gr-group-radial'),
conic: document.getElementById('gr-group-conic'),
multistop: document.getElementById('gr-group-multistop')
};
const outBox = document.getElementById('gr-out-box');
const bgValue = document.getElementById('gr-bg-value');
const note = document.getElementById('gr-note');
// Linear controls
const linearDirBtns = document.querySelectorAll('#gr-linear-dir .gr-seg-btn');
const linearAngle = document.getElementById('gr-linear-angle');
const linearAngleReadout = document.getElementById('gr-linear-angle-readout');
const linearC1 = document.getElementById('gr-linear-c1');
const linearC2 = document.getElementById('gr-linear-c2');
let linearMode = 'dir';
let linearDir = 'to right';
// Radial controls
const radialShapeBtns = document.querySelectorAll('#gr-radial-shape .gr-seg-btn');
const radialPosBtns = document.querySelectorAll('#gr-radial-pos .gr-seg-btn');
const radialC1 = document.getElementById('gr-radial-c1');
const radialC2 = document.getElementById('gr-radial-c2');
let radialShape = 'circle';
let radialPos = 'center';
// Conic controls
const conicAngle = document.getElementById('gr-conic-angle');
const conicAngleReadout = document.getElementById('gr-conic-angle-readout');
// Multi-stop controls
const multiPos = document.getElementById('gr-multi-pos');
const multiPosReadout = document.getElementById('gr-multi-pos-readout');
const multiC1 = document.getElementById('gr-multi-c1');
const multiC2 = document.getElementById('gr-multi-c2');
const multiC3 = document.getElementById('gr-multi-c3');
let currentType = 'linear';
const notes = {
linear: '<strong>linear-gradient</strong> blends colors along a straight line — set a preset keyword direction like <code>to right</code>, or a precise angle in degrees. Both do the same job; angle just gives finer control.',
radial: '<strong>radial-gradient</strong> blends colors outward from a point — <code>circle</code> spreads evenly in all directions, <code>ellipse</code> stretches to match the box\'s aspect ratio, and position moves the center point.',
conic: '<strong>conic-gradient</strong> sweeps colors around a center point like a color wheel, rather than blending outward — <code>from</code> rotates the whole sweep\'s starting angle.',
multistop: 'Adding a <strong>third color</strong> with explicit <code>%</code> positions lets you control exactly where each color sits, not just where the gradient starts and ends — move the slider to shift where the middle color peaks.'
};
function render() {
let bg = '';
if (currentType === 'linear') {
const angleOrDir = linearMode === 'dir' ? linearDir : (linearAngle.value + 'deg');
bg = `linear-gradient(${angleOrDir}, ${linearC1.value}, ${linearC2.value})`;
} else if (currentType === 'radial') {
bg = `radial-gradient(${radialShape} at ${radialPos}, ${radialC1.value}, ${radialC2.value})`;
} else if (currentType === 'conic') {
bg = `conic-gradient(from ${conicAngle.value}deg, red, yellow, green, blue, red)`;
} else if (currentType === 'multistop') {
bg = `linear-gradient(to bottom, ${multiC1.value} 0%, ${multiC2.value} ${multiPos.value}%, ${multiC3.value} 100%)`;
}
outBox.style.background = bg;
if (currentType === 'conic') outBox.style.borderRadius = '50%';
else outBox.style.borderRadius = '';
bgValue.textContent = bg;
tabCss.click();
}
function switchType(type) {
currentType = type;
typeButtons.forEach(b => b.classList.toggle('gr-type-on', b.getAttribute('data-type') === type));
Object.entries(groups).forEach(([key, el]) => el.classList.toggle('gr-group-on', key === type));
note.innerHTML = notes[type];
render();
}
typeButtons.forEach(btn => {
btn.addEventListener('click', () => switchType(btn.getAttribute('data-type')));
});
linearDirBtns.forEach(btn => {
btn.addEventListener('click', () => {
linearMode = 'dir';
linearDir = btn.getAttribute('data-dir');
linearDirBtns.forEach(b => b.classList.toggle('gr-seg-on', b === btn));
render();
});
});
linearAngle.addEventListener('input', () => {
linearMode = 'angle';
linearDirBtns.forEach(b => b.classList.remove('gr-seg-on'));
linearAngleReadout.textContent = linearAngle.value + 'deg';
render();
});
linearC1.addEventListener('input', render);
linearC2.addEventListener('input', render);
radialShapeBtns.forEach(btn => {
btn.addEventListener('click', () => {
radialShape = btn.getAttribute('data-shape');
radialShapeBtns.forEach(b => b.classList.toggle('gr-seg-on', b === btn));
render();
});
});
radialPosBtns.forEach(btn => {
btn.addEventListener('click', () => {
radialPos = btn.getAttribute('data-pos');
radialPosBtns.forEach(b => b.classList.toggle('gr-seg-on', b === btn));
render();
});
});
radialC1.addEventListener('input', render);
radialC2.addEventListener('input', render);
conicAngle.addEventListener('input', () => {
conicAngleReadout.textContent = conicAngle.value + 'deg';
render();
});
multiPos.addEventListener('input', () => {
multiPosReadout.textContent = multiPos.value + '%';
render();
});
multiC1.addEventListener('input', render);
multiC2.addEventListener('input', render);
multiC3.addEventListener('input', render);
render();
})();
</script>
</body>
</html>✅ Background Images
You can set actual images as backgrounds for any element.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hero Section Backgrounds</title>
<style>
.infographic-hero {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
box-sizing: border-box;
margin: 0 auto;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: var(--paper);
color: var(--ink);
border-radius: 14px;
overflow: hidden;
}
.infographic-hero[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.hr-inner { padding: 0.5rem; }
.hr-layout { display: flex; flex-direction: column; gap: 1.2rem; }
.hr-typebar {
display: flex;
border: 1px solid var(--line);
border-radius: 999px;
overflow: hidden;
align-self: flex-start;
flex-wrap: wrap;
}
.hr-type-btn {
border: none;
background: var(--paper);
color: var(--ink-soft);
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.75rem;
font-weight: 700;
padding: 0.4rem 0.9rem;
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease;
}
.hr-type-btn + .hr-type-btn { border-left: 1px solid var(--line); }
.hr-type-btn.hr-type-on { background: var(--accent); color: #ffffff; }
.hr-code-wrap {
background: #0b0b0b;
border: 1px solid #2a2a2a;
border-radius: 10px;
overflow: hidden;
}
.hr-filetabs {
display: flex;
background: #161616;
border-bottom: 1px solid #2a2a2a;
}
.hr-filetab {
border: none;
background: transparent;
color: #8a8a8a;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.78rem;
font-weight: 700;
padding: 0.6rem 1rem;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.hr-filetab:hover { color: #e5e5e5; }
.hr-filetab.hr-tab-on {
color: #ffffff;
border-bottom-color: #5b8def;
background: #0b0b0b;
}
.hr-code {
padding: 1rem 1.8rem 1rem 0.9rem;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.78rem;
line-height: 1.85;
overflow-x: auto;
}
.hr-codepane { display: none; }
.hr-codepane.hr-pane-on { display: block; }
.hr-line { display: block; white-space: pre; color: #e5e5e5; padding: 0.05rem 0.4rem; border-radius: 5px; }
.hr-line.hr-hl { background: #1c2333; box-shadow: inset 3px 0 0 #5b8def; color: #ffffff; }
.hr-tag { color: #60a5fa; font-weight: 700; }
.hr-attr { color: #f2b96b; }
.hr-str { color: #9ece6a; }
.hr-sel { color: #f472b6; font-weight: 700; }
.hr-prop { color: #c586c0; }
.hr-val { color: #ce9178; }
.hr-browser {
border: 1px solid var(--line);
border-radius: 10px;
overflow: hidden;
background: var(--paper);
}
.hr-browser-bar {
background: var(--paper-alt);
padding: 0.5rem 0.7rem;
display: flex;
align-items: center;
gap: 0.5rem;
border-bottom: 1px solid var(--line);
}
.hr-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--line); }
.hr-tab {
background: var(--paper);
border: 1px solid var(--line);
border-bottom: none;
border-radius: 6px 6px 0 0;
font-size: 0.72rem;
color: var(--ink-soft);
padding: 0.25rem 0.6rem;
}
.hr-screen {
background: #1a1a1a;
padding: 0;
}
.hr-hero-box {
width: 100%;
height: 220px;
display: flex;
align-items: center;
padding: 0 1.6rem;
box-sizing: border-box;
font-family: sans-serif;
color: white;
background-color: #333;
transition: background-position 0.15s ease;
}
.hr-hero-box .hr-content h2 { margin: 0 0 0.35rem 0; font-size: 1.3rem; text-shadow: 0 1px 4px rgba(0,0,0,0.5); }
.hr-hero-box .hr-content p { margin: 0; font-size: 0.85rem; opacity: 0.95; text-shadow: 0 1px 4px rgba(0,0,0,0.5); max-width: 260px; }
.hr-controls {
background: var(--paper-alt);
padding: 0.7rem 0.9rem 0.9rem;
border-top: 1px solid var(--line);
}
.hr-control-group { display: none; flex-direction: column; gap: 0.6rem; }
.hr-control-group.hr-group-on { display: flex; }
.hr-control-row {
display: flex;
align-items: center;
gap: 0.6rem;
flex-wrap: wrap;
}
.hr-control-label {
font-size: 0.72rem;
color: var(--ink-soft);
font-family: "SFMono-Regular", Consolas, monospace;
min-width: 80px;
}
.hr-segmented {
display: flex;
border: 1px solid var(--line);
border-radius: 999px;
overflow: hidden;
flex-wrap: wrap;
}
.hr-seg-btn {
border: none;
background: var(--paper);
color: var(--ink-soft);
font-family: "SFMono-Regular", Consolas, monospace;
font-size: 0.68rem;
font-weight: 700;
padding: 0.32rem 0.6rem;
cursor: pointer;
white-space: nowrap;
transition: background 0.15s ease, color 0.15s ease;
}
.hr-seg-btn + .hr-seg-btn { border-left: 1px solid var(--line); }
.hr-seg-btn.hr-seg-on { background: var(--accent); color: #ffffff; }
.hr-posgrid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 3px;
width: 108px;
border: 1px solid var(--line);
border-radius: 8px;
overflow: hidden;
background: var(--line);
}
.hr-pos-btn {
border: none;
background: var(--paper);
height: 32px;
cursor: pointer;
position: relative;
}
.hr-pos-btn::after {
content: "";
position: absolute;
top: 50%; left: 50%;
width: 6px; height: 6px;
border-radius: 50%;
background: var(--ink-soft);
transform: translate(-50%, -50%);
opacity: 0.5;
}
.hr-pos-btn.hr-pos-on { background: var(--accent-soft); }
.hr-pos-btn.hr-pos-on::after { background: var(--accent); opacity: 1; }
.hr-range {
flex: 1;
min-width: 90px;
accent-color: var(--accent);
cursor: pointer;
}
.hr-readout {
font-size: 0.72rem;
color: var(--ink);
font-weight: 700;
font-family: "SFMono-Regular", Consolas, monospace;
min-width: 40px;
}
.hr-color-input {
width: 24px;
height: 24px;
border: 1px solid var(--line);
border-radius: 6px;
padding: 0;
cursor: pointer;
background: none;
}
.hr-note {
font-size: 0.82rem;
color: var(--ink-soft);
padding: 0 0.2rem;
}
.hr-note strong { color: var(--ink); }
.hr-note code {
font-family: "SFMono-Regular", Consolas, monospace;
background: var(--paper-alt);
padding: 0.05rem 0.3rem;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="infographic-hero" id="hr-root">
<div class="hr-inner">
<div class="hr-layout">
<div class="hr-typebar" id="hr-typebar">
<button class="hr-type-btn hr-type-on" data-tab="size">Size</button>
<button class="hr-type-btn" data-tab="position">Position</button>
<button class="hr-type-btn" data-tab="repeat">Repeat</button>
<button class="hr-type-btn" data-tab="overlay">Overlay</button>
</div>
<div class="hr-code-wrap">
<div class="hr-filetabs">
<button class="hr-filetab hr-tab-on" id="hr-tab-css">styles.css</button>
<button class="hr-filetab" id="hr-tab-html">index.html</button>
</div>
<div class="hr-code">
<div class="hr-codepane hr-pane-on" id="hr-pane-css">
<span class="hr-line"><span class="hr-sel">.hero</span> {</span>
<span class="hr-line" id="hr-line-image"> <span class="hr-prop">background-image</span>: <span class="hr-val" id="hr-val-image">url("mountain-pattern.svg")</span>;</span>
<span class="hr-line" id="hr-line-size"> <span class="hr-prop">background-size</span>: <span class="hr-val" id="hr-val-size">cover</span>;</span>
<span class="hr-line" id="hr-line-position"> <span class="hr-prop">background-position</span>: <span class="hr-val" id="hr-val-position">center</span>;</span>
<span class="hr-line" id="hr-line-repeat"> <span class="hr-prop">background-repeat</span>: <span class="hr-val" id="hr-val-repeat">no-repeat</span>;</span>
<span class="hr-line"> <span class="hr-prop">height</span>: <span class="hr-val">100vh</span>;</span>
<span class="hr-line"> <span class="hr-prop">display</span>: <span class="hr-val">flex</span>;</span>
<span class="hr-line"> <span class="hr-prop">align-items</span>: <span class="hr-val">center</span>;</span>
<span class="hr-line"> <span class="hr-prop">padding</span>: <span class="hr-val">2rem</span>;</span>
<span class="hr-line">}</span>
<span class="hr-line"></span>
<span class="hr-line"><span class="hr-sel">.content</span> {</span>
<span class="hr-line"> <span class="hr-prop">color</span>: <span class="hr-val">white</span>;</span>
<span class="hr-line"> <span class="hr-prop">max-width</span>: <span class="hr-val">32rem</span>;</span>
<span class="hr-line">}</span>
</div>
<div class="hr-codepane" id="hr-pane-html">
<span class="hr-line"><<span class="hr-tag">section</span> <span class="hr-attr">class</span>=<span class="hr-str">"hero"</span>></span>
<span class="hr-line"> <<span class="hr-tag">div</span> <span class="hr-attr">class</span>=<span class="hr-str">"content"</span>></span>
<span class="hr-line"> <<span class="hr-tag">h1</span>>Welcome</<span class="hr-tag">h1</span>></span>
<span class="hr-line"> <<span class="hr-tag">p</span>>Stunning hero section with a background image.</<span class="hr-tag">p</span>></span>
<span class="hr-line"> </<span class="hr-tag">div</span>></span>
<span class="hr-line"></<span class="hr-tag">section</span>></span>
</div>
</div>
</div>
<div class="hr-browser">
<div class="hr-browser-bar">
<span class="hr-dot"></span><span class="hr-dot"></span><span class="hr-dot"></span>
<div class="hr-tab">🌐 Hero Section</div>
</div>
<div class="hr-screen">
<div class="hr-hero-box" id="hr-hero-box">
<div class="hr-content">
<h2>Welcome</h2>
<p>Stunning hero section with a background image.</p>
</div>
</div>
</div>
<div class="hr-controls">
<div class="hr-control-group hr-group-on" id="hr-group-size">
<div class="hr-control-row">
<span class="hr-control-label">background-size</span>
<div class="hr-segmented" id="hr-size-seg">
<button class="hr-seg-btn" data-size="cover">cover</button>
<button class="hr-seg-btn" data-size="contain">contain</button>
<button class="hr-seg-btn hr-seg-on" data-size="auto">auto</button>
</div>
</div>
</div>
<div class="hr-control-group" id="hr-group-position">
<div class="hr-control-row">
<span class="hr-control-label">focal point</span>
<div class="hr-posgrid" id="hr-pos-grid">
<button class="hr-pos-btn" data-pos="left top" title="top left"></button>
<button class="hr-pos-btn" data-pos="center top" title="top center"></button>
<button class="hr-pos-btn" data-pos="right top" title="top right"></button>
<button class="hr-pos-btn" data-pos="left center" title="center left"></button>
<button class="hr-pos-btn hr-pos-on" data-pos="center center" title="center"></button>
<button class="hr-pos-btn" data-pos="right center" title="center right"></button>
<button class="hr-pos-btn" data-pos="left bottom" title="bottom left"></button>
<button class="hr-pos-btn" data-pos="center bottom" title="bottom center"></button>
<button class="hr-pos-btn" data-pos="right bottom" title="bottom right"></button>
</div>
</div>
</div>
<div class="hr-control-group" id="hr-group-repeat">
<div class="hr-control-row">
<span class="hr-control-label">background-repeat</span>
<div class="hr-segmented" id="hr-repeat-seg">
<button class="hr-seg-btn" data-repeat="no-repeat">no-repeat</button>
<button class="hr-seg-btn hr-seg-on" data-repeat="repeat">repeat</button>
<button class="hr-seg-btn" data-repeat="repeat-x">repeat-x</button>
<button class="hr-seg-btn" data-repeat="repeat-y">repeat-y</button>
</div>
</div>
</div>
<div class="hr-control-group" id="hr-group-overlay">
<div class="hr-control-row">
<span class="hr-control-label">overlay opacity</span>
<input type="range" class="hr-range" id="hr-overlay-opacity" min="0" max="85" step="5" value="35">
<span class="hr-readout" id="hr-overlay-readout">0.35</span>
</div>
<div class="hr-control-row">
<span class="hr-control-label">overlay color</span>
<input type="color" class="hr-color-input" id="hr-overlay-color" value="#000000">
</div>
</div>
</div>
</div>
<div class="hr-note" id="hr-note">
<strong>background-size: cover</strong> scales the image to fill the box completely, cropping any overflow — the most common choice for hero sections since it never leaves gaps, unlike <code>contain</code> which shrinks to fit and can show empty space.
</div>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-hero')
|| document.querySelector('.infographic-hero');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
})();
(function () {
const MOUNTAIN_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="240" height="160">
<rect width="240" height="160" fill="#dbe9f7"/>
<circle cx="200" cy="35" r="18" fill="#fdf3d8"/>
<polygon points="0,100 40,60 80,100 120,60 160,100 200,60 240,100 240,160 0,160" fill="#9fc3e0"/>
<polygon points="0,90 40,130 80,90 120,130 160,90 200,130 240,90 240,160 0,160" fill="#4f7fb0"/>
</svg>`;
const IMG_URL = 'data:image/svg+xml,' + encodeURIComponent(MOUNTAIN_SVG);
const tabCss = document.getElementById('hr-tab-css');
const tabHtml = document.getElementById('hr-tab-html');
const paneCss = document.getElementById('hr-pane-css');
const paneHtml = document.getElementById('hr-pane-html');
tabCss.addEventListener('click', () => {
tabCss.classList.add('hr-tab-on');
tabHtml.classList.remove('hr-tab-on');
paneCss.classList.add('hr-pane-on');
paneHtml.classList.remove('hr-pane-on');
});
tabHtml.addEventListener('click', () => {
tabHtml.classList.add('hr-tab-on');
tabCss.classList.remove('hr-tab-on');
paneHtml.classList.add('hr-pane-on');
paneCss.classList.remove('hr-pane-on');
});
const typeButtons = document.querySelectorAll('.hr-type-btn');
const groups = {
size: document.getElementById('hr-group-size'),
position: document.getElementById('hr-group-position'),
repeat: document.getElementById('hr-group-repeat'),
overlay: document.getElementById('hr-group-overlay')
};
const lines = {
size: document.getElementById('hr-line-size'),
position: document.getElementById('hr-line-position'),
repeat: document.getElementById('hr-line-repeat'),
overlay: document.getElementById('hr-line-image')
};
const heroBox = document.getElementById('hr-hero-box');
const note = document.getElementById('hr-note');
const valSize = document.getElementById('hr-val-size');
const valPosition = document.getElementById('hr-val-position');
const valRepeat = document.getElementById('hr-val-repeat');
const valImage = document.getElementById('hr-val-image');
const sizeSeg = document.querySelectorAll('#hr-size-seg .hr-seg-btn');
const posBtns = document.querySelectorAll('#hr-pos-grid .hr-pos-btn');
const repeatSeg = document.querySelectorAll('#hr-repeat-seg .hr-seg-btn');
const overlayOpacity = document.getElementById('hr-overlay-opacity');
const overlayReadout = document.getElementById('hr-overlay-readout');
const overlayColor = document.getElementById('hr-overlay-color');
let state = {
size: 'auto',
position: 'center center',
repeat: 'repeat',
opacity: 35,
color: '#000000'
};
let currentTab = 'size';
const notes = {
size: '<strong>background-size</strong> controls the scale before <code>repeat</code> tiles it — <code>auto</code> keeps a small pattern at its native size so it tiles crisply, while <code>cover</code>/<code>contain</code> stretch it to fill or fit the box, which usually kills the repeating effect.',
position: '<strong>background-position</strong> picks which part of the image stays anchored as the box resizes — pick the focal point (a face, a headline area) so cropping never cuts off what matters.',
repeat: '<strong>background-repeat</strong> only matters when the image is smaller than the box or sized with <code>auto</code> — with <code>cover</code> or <code>contain</code> it rarely tiles, since the image is already scaled to fill or fit.',
overlay: 'A semi-transparent color layered <em>under</em> the image (not over the text) keeps white headline text readable on busy photos — stack it as a second <code>background-image</code> gradient rather than a separate element.'
};
function hexToRgb(hex) {
const n = parseInt(hex.slice(1), 16);
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
}
function render() {
const [r, g, b] = hexToRgb(state.color);
const alpha = (state.opacity / 100).toFixed(2);
const overlayCss = `linear-gradient(rgba(${r}, ${g}, ${b}, ${alpha}), rgba(${r}, ${g}, ${b}, ${alpha}))`;
heroBox.style.backgroundImage = `${overlayCss}, url("${IMG_URL}")`;
heroBox.style.backgroundSize = `${state.size}, ${state.size}`;
heroBox.style.backgroundPosition = `${state.position}, ${state.position}`;
heroBox.style.backgroundRepeat = `${state.repeat}, ${state.repeat}`;
valSize.textContent = state.size;
valPosition.textContent = state.position;
valRepeat.textContent = state.repeat;
valImage.textContent = alpha > 0
? `linear-gradient(rgba(0,0,0,${alpha})...), url("mountain-pattern.svg")`
: 'url("mountain-pattern.svg")';
overlayReadout.textContent = alpha;
tabCss.click();
}
function switchTab(tab) {
currentTab = tab;
typeButtons.forEach(b => b.classList.toggle('hr-type-on', b.getAttribute('data-tab') === tab));
Object.entries(groups).forEach(([key, el]) => el.classList.toggle('hr-group-on', key === tab));
Object.entries(lines).forEach(([key, el]) => el.classList.toggle('hr-hl', key === tab));
note.innerHTML = notes[tab];
}
typeButtons.forEach(btn => {
btn.addEventListener('click', () => switchTab(btn.getAttribute('data-tab')));
});
sizeSeg.forEach(btn => {
btn.addEventListener('click', () => {
state.size = btn.getAttribute('data-size');
sizeSeg.forEach(b => b.classList.toggle('hr-seg-on', b === btn));
render();
});
});
posBtns.forEach(btn => {
btn.addEventListener('click', () => {
state.position = btn.getAttribute('data-pos').replace('left', 'left').replace('right', 'right')
.replace('center center', 'center')
.replace('center top', 'center top')
.replace('center bottom', 'center bottom');
state.position = btn.getAttribute('data-pos') === 'center center' ? 'center' : btn.getAttribute('data-pos');
posBtns.forEach(b => b.classList.toggle('hr-pos-on', b === btn));
render();
});
});
repeatSeg.forEach(btn => {
btn.addEventListener('click', () => {
state.repeat = btn.getAttribute('data-repeat');
repeatSeg.forEach(b => b.classList.toggle('hr-seg-on', b === btn));
render();
});
});
overlayOpacity.addEventListener('input', () => {
state.opacity = Number(overlayOpacity.value);
render();
});
overlayColor.addEventListener('input', () => {
state.color = overlayColor.value;
render();
});
switchTab('size');
render();
})();
</script>
</body>
</html>🔹 Key Properties
Property | Description |
|---|---|
| Sets the image or gradient |
|
|
|
|
|
|
|
|
✅ Combining Gradients with Background Images
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Card Gradient Overlay</title>
<style>
.infographic-cardoverlay {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
box-sizing: border-box;
margin: 0 auto;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: var(--paper);
color: var(--ink);
border-radius: 14px;
overflow: hidden;
}
.infographic-cardoverlay[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.co-inner { padding: 0.5rem; }
.co-layout { display: flex; flex-direction: column; gap: 1.2rem; }
.co-typebar {
display: flex;
border: 1px solid var(--line);
border-radius: 999px;
overflow: hidden;
align-self: flex-start;
flex-wrap: wrap;
}
.co-type-btn {
border: none;
background: var(--paper);
color: var(--ink-soft);
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.75rem;
font-weight: 700;
padding: 0.4rem 0.9rem;
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease;
}
.co-type-btn + .co-type-btn { border-left: 1px solid var(--line); }
.co-type-btn.co-type-on { background: var(--accent); color: #ffffff; }
.co-code-wrap {
background: #0b0b0b;
border: 1px solid #2a2a2a;
border-radius: 10px;
overflow: hidden;
}
.co-filetabs {
display: flex;
background: #161616;
border-bottom: 1px solid #2a2a2a;
}
.co-filetab {
border: none;
background: transparent;
color: #8a8a8a;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.78rem;
font-weight: 700;
padding: 0.6rem 1rem;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.co-filetab:hover { color: #e5e5e5; }
.co-filetab.co-tab-on {
color: #ffffff;
border-bottom-color: #5b8def;
background: #0b0b0b;
}
.co-code {
padding: 1rem 1.8rem 1rem 0.9rem;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
font-size: 0.78rem;
line-height: 1.85;
overflow-x: auto;
}
.co-codepane { display: none; }
.co-codepane.co-pane-on { display: block; }
.co-line { display: block; white-space: pre; color: #e5e5e5; padding: 0.05rem 0.4rem; border-radius: 5px; }
.co-line.co-hl { background: #1c2333; box-shadow: inset 3px 0 0 #5b8def; color: #ffffff; }
.co-tag { color: #60a5fa; font-weight: 700; }
.co-attr { color: #f2b96b; }
.co-str { color: #9ece6a; }
.co-sel { color: #f472b6; font-weight: 700; }
.co-prop { color: #c586c0; }
.co-val { color: #ce9178; }
.co-browser {
border: 1px solid var(--line);
border-radius: 10px;
overflow: hidden;
background: var(--paper);
}
.co-browser-bar {
background: var(--paper-alt);
padding: 0.5rem 0.7rem;
display: flex;
align-items: center;
gap: 0.5rem;
border-bottom: 1px solid var(--line);
}
.co-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--line); }
.co-tab {
background: var(--paper);
border: 1px solid var(--line);
border-bottom: none;
border-radius: 6px 6px 0 0;
font-size: 0.72rem;
color: var(--ink-soft);
padding: 0.25rem 0.6rem;
}
.co-screen {
background: #f5f5f5;
padding: 1.6rem;
display: flex;
justify-content: center;
}
.co-card {
width: 100%;
max-width: 320px;
height: 200px;
border-radius: 12px;
overflow: hidden;
color: white;
display: flex;
box-sizing: border-box;
padding: 1.3rem;
font-family: sans-serif;
}
.co-card .co-content { max-width: 220px; }
.co-card .co-content h2 { margin: 0 0 0.3rem 0; font-size: 1rem; text-shadow: 0 1px 3px rgba(0,0,0,0.4); }
.co-card .co-content p { margin: 0; font-size: 0.78rem; opacity: 0.95; text-shadow: 0 1px 3px rgba(0,0,0,0.4); }
.co-controls {
background: var(--paper-alt);
padding: 0.7rem 0.9rem 0.9rem;
border-top: 1px solid var(--line);
}
.co-control-group { display: none; flex-direction: column; gap: 0.6rem; }
.co-control-group.co-group-on { display: flex; }
.co-control-row {
display: flex;
align-items: center;
gap: 0.6rem;
flex-wrap: wrap;
}
.co-control-label {
font-size: 0.72rem;
color: var(--ink-soft);
font-family: "SFMono-Regular", Consolas, monospace;
min-width: 80px;
}
.co-segmented {
display: flex;
border: 1px solid var(--line);
border-radius: 999px;
overflow: hidden;
flex-wrap: wrap;
}
.co-seg-btn {
border: none;
background: var(--paper);
color: var(--ink-soft);
font-family: "SFMono-Regular", Consolas, monospace;
font-size: 0.68rem;
font-weight: 700;
padding: 0.32rem 0.6rem;
cursor: pointer;
white-space: nowrap;
transition: background 0.15s ease, color 0.15s ease;
}
.co-seg-btn + .co-seg-btn { border-left: 1px solid var(--line); }
.co-seg-btn.co-seg-on { background: var(--accent); color: #ffffff; }
.co-range {
flex: 1;
min-width: 90px;
accent-color: var(--accent);
cursor: pointer;
}
.co-readout {
font-size: 0.72rem;
color: var(--ink);
font-weight: 700;
font-family: "SFMono-Regular", Consolas, monospace;
min-width: 40px;
}
.co-color-input {
width: 24px;
height: 24px;
border: 1px solid var(--line);
border-radius: 6px;
padding: 0;
cursor: pointer;
background: none;
}
.co-note {
font-size: 0.82rem;
color: var(--ink-soft);
padding: 0 0.2rem;
}
.co-note strong { color: var(--ink); }
.co-note code {
font-family: "SFMono-Regular", Consolas, monospace;
background: var(--paper-alt);
padding: 0.05rem 0.3rem;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="infographic-cardoverlay" id="co-root">
<div class="co-inner">
<div class="co-layout">
<div class="co-typebar" id="co-typebar">
<button class="co-type-btn co-type-on" data-tab="direction">Direction</button>
<button class="co-type-btn" data-tab="overlay">Overlay</button>
<button class="co-type-btn" data-tab="text">Text position</button>
</div>
<div class="co-code-wrap">
<div class="co-filetabs">
<button class="co-filetab co-tab-on" id="co-tab-css">styles.css</button>
<button class="co-filetab" id="co-tab-html">index.html</button>
</div>
<div class="co-code">
<div class="co-codepane co-pane-on" id="co-pane-css">
<span class="co-line"><span class="co-sel">.card</span> {</span>
<span class="co-line"> <span class="co-prop">width</span>: <span class="co-val">90%</span>;</span>
<span class="co-line"> <span class="co-prop">max-width</span>: <span class="co-val">500px</span>;</span>
<span class="co-line"> <span class="co-prop">height</span>: <span class="co-val">300px</span>;</span>
<span class="co-line"> <span class="co-prop">border-radius</span>: <span class="co-val">12px</span>;</span>
<span class="co-line"> <span class="co-prop">overflow</span>: <span class="co-val">hidden</span>;</span>
<span class="co-line"> <span class="co-prop">color</span>: <span class="co-val">white</span>;</span>
<span class="co-line"> <span class="co-prop">display</span>: <span class="co-val">flex</span>;</span>
<span class="co-line" id="co-line-align"> <span class="co-prop">align-items</span>: <span class="co-val" id="co-val-align">flex-start</span>;</span>
<span class="co-line" id="co-line-justify"> <span class="co-prop">justify-content</span>: <span class="co-val" id="co-val-justify">flex-start</span>;</span>
<span class="co-line"> <span class="co-prop">padding</span>: <span class="co-val">2rem</span>;</span>
<span class="co-line"></span>
<span class="co-line" id="co-line-bg"> <span class="co-prop">background</span>: <span class="co-val" id="co-val-bg">linear-gradient(to bottom, rgba(0,0,0,0.6), transparent), url("photo.jpg")</span>;</span>
<span class="co-line"> <span class="co-prop">background-size</span>: <span class="co-val">cover</span>;</span>
<span class="co-line"> <span class="co-prop">background-position</span>: <span class="co-val">center</span>;</span>
<span class="co-line">}</span>
<span class="co-line"></span>
<span class="co-line"><span class="co-sel">.content</span> { <span class="co-prop">z-index</span>: <span class="co-val">1</span>; }</span>
</div>
<div class="co-codepane" id="co-pane-html">
<span class="co-line"><<span class="co-tag">div</span> <span class="co-attr">class</span>=<span class="co-str">"card"</span>></span>
<span class="co-line"> <<span class="co-tag">div</span> <span class="co-attr">class</span>=<span class="co-str">"content"</span>></span>
<span class="co-line"> <<span class="co-tag">h2</span>>Gradient Overlay Card</<span class="co-tag">h2</span>></span>
<span class="co-line"> <<span class="co-tag">p</span>>Text stays readable with a gradient overlay.</<span class="co-tag">p</span>></span>
<span class="co-line"> </<span class="co-tag">div</span>></span>
<span class="co-line"></<span class="co-tag">div</span>></span>
</div>
</div>
</div>
<div class="co-browser">
<div class="co-browser-bar">
<span class="co-dot"></span><span class="co-dot"></span><span class="co-dot"></span>
<div class="co-tab">🌐 Card Gradient Overlay</div>
</div>
<div class="co-screen">
<div class="co-card" id="co-card">
<div class="co-content">
<h2>Gradient Overlay Card</h2>
<p>Text stays readable with a gradient overlay.</p>
</div>
</div>
</div>
<div class="co-controls">
<div class="co-control-group co-group-on" id="co-group-direction">
<div class="co-control-row">
<span class="co-control-label">gradient</span>
<div class="co-segmented" id="co-dir-seg">
<button class="co-seg-btn co-seg-on" data-dir="to bottom">to bottom</button>
<button class="co-seg-btn" data-dir="to top">to top</button>
<button class="co-seg-btn" data-dir="to right">to right</button>
<button class="co-seg-btn" data-dir="radial">radial</button>
</div>
</div>
</div>
<div class="co-control-group" id="co-group-overlay">
<div class="co-control-row">
<span class="co-control-label">strength</span>
<input type="range" class="co-range" id="co-overlay-opacity" min="0" max="90" step="5" value="60">
<span class="co-readout" id="co-overlay-readout">0.6</span>
</div>
<div class="co-control-row">
<span class="co-control-label">tint color</span>
<input type="color" class="co-color-input" id="co-overlay-color" value="#000000">
</div>
</div>
<div class="co-control-group" id="co-group-text">
<div class="co-control-row">
<span class="co-control-label">text sits</span>
<div class="co-segmented" id="co-text-seg">
<button class="co-seg-btn co-seg-on" data-pos="top-left">top</button>
<button class="co-seg-btn" data-pos="bottom-left">bottom</button>
<button class="co-seg-btn" data-pos="center">center</button>
</div>
</div>
</div>
</div>
</div>
<div class="co-note" id="co-note">
<strong>Two backgrounds, one property</strong> — a <code>linear-gradient</code> layered in front of the photo in the same <code>background</code> shorthand, comma-separated. The gradient fades from solid at the text edge to transparent, so only the part behind the text gets darker.
</div>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-cardoverlay')
|| document.querySelector('.infographic-cardoverlay');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
})();
(function () {
const PHOTO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="320" height="200">
<rect width="320" height="200" fill="#e8c78a"/>
<circle cx="250" cy="55" r="26" fill="#fff3d6"/>
<polygon points="0,200 0,140 60,80 130,150 190,70 260,150 320,110 320,200" fill="#c98f4f"/>
<polygon points="0,200 0,170 90,120 170,190 320,150 320,200" fill="#8a5a35"/>
</svg>`;
const IMG_URL = 'data:image/svg+xml,' + encodeURIComponent(PHOTO_SVG);
const tabCss = document.getElementById('co-tab-css');
const tabHtml = document.getElementById('co-tab-html');
const paneCss = document.getElementById('co-pane-css');
const paneHtml = document.getElementById('co-pane-html');
tabCss.addEventListener('click', () => {
tabCss.classList.add('co-tab-on');
tabHtml.classList.remove('co-tab-on');
paneCss.classList.add('co-pane-on');
paneHtml.classList.remove('co-pane-on');
});
tabHtml.addEventListener('click', () => {
tabHtml.classList.add('co-tab-on');
tabCss.classList.remove('co-tab-on');
paneHtml.classList.add('co-pane-on');
paneCss.classList.remove('co-pane-on');
});
const typeButtons = document.querySelectorAll('.co-type-btn');
const groups = {
direction: document.getElementById('co-group-direction'),
overlay: document.getElementById('co-group-overlay'),
text: document.getElementById('co-group-text')
};
const lines = {
direction: document.getElementById('co-line-bg'),
overlay: document.getElementById('co-line-bg'),
text: document.getElementById('co-line-align')
};
const card = document.getElementById('co-card');
const note = document.getElementById('co-note');
const valBg = document.getElementById('co-val-bg');
const valAlign = document.getElementById('co-val-align');
const valJustify = document.getElementById('co-val-justify');
const lineJustify = document.getElementById('co-line-justify');
const dirSeg = document.querySelectorAll('#co-dir-seg .co-seg-btn');
const overlayOpacity = document.getElementById('co-overlay-opacity');
const overlayReadout = document.getElementById('co-overlay-readout');
const overlayColor = document.getElementById('co-overlay-color');
const textSeg = document.querySelectorAll('#co-text-seg .co-seg-btn');
let state = {
direction: 'to bottom',
opacity: 60,
color: '#000000',
textPos: 'top-left'
};
const textPosMap = {
'top-left': { align: 'flex-start', justify: 'flex-start' },
'bottom-left': { align: 'flex-end', justify: 'flex-start' },
'center': { align: 'center', justify: 'center' }
};
const notes = {
direction: '<strong>Gradient direction should follow the text.</strong> Text pinned to the top needs <code>to bottom</code> (dark at top, fading down); text at the bottom needs the opposite. A mismatched direction darkens the wrong half of the photo.',
overlay: '<strong>Strength</strong> is just the gradient\'s starting alpha — high enough to pass contrast checks against the busiest part of the photo, low enough that the image still reads as a photo and not a black box.',
text: 'Moving the text changes what <code>align-items</code> / <code>justify-content</code> need to be on <code>.card</code> — the overlay direction (previous tab) should always point toward wherever the text ends up.'
};
function hexToRgb(hex) {
const n = parseInt(hex.slice(1), 16);
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
}
function render() {
const [r, g, b] = hexToRgb(state.color);
const alpha = (state.opacity / 100).toFixed(2);
const gradientCss = state.direction === 'radial'
? `radial-gradient(circle at ${state.textPos === 'center' ? 'center' : (state.textPos === 'bottom-left' ? 'bottom left' : 'top left')}, rgba(${r},${g},${b},${alpha}), transparent)`
: `linear-gradient(${state.direction}, rgba(${r},${g},${b},${alpha}), transparent)`;
card.style.background = `${gradientCss}, ${IMG_URL ? `url("${IMG_URL}")` : 'none'}`;
card.style.backgroundSize = 'cover, cover';
card.style.backgroundPosition = 'center, center';
const pos = textPosMap[state.textPos];
card.style.alignItems = pos.align;
card.style.justifyContent = pos.justify;
valBg.textContent = state.direction === 'radial'
? `radial-gradient(circle, rgba(0,0,0,${alpha}), transparent), url("photo.jpg")`
: `linear-gradient(${state.direction}, rgba(0,0,0,${alpha}), transparent), url("photo.jpg")`;
valAlign.textContent = pos.align;
valJustify.textContent = pos.justify;
overlayReadout.textContent = alpha;
tabCss.click();
}
function switchTab(tab) {
typeButtons.forEach(b => b.classList.toggle('co-type-on', b.getAttribute('data-tab') === tab));
Object.entries(groups).forEach(([key, el]) => el.classList.toggle('co-group-on', key === tab));
document.getElementById('co-line-bg').classList.toggle('co-hl', tab === 'direction' || tab === 'overlay');
document.getElementById('co-line-align').classList.toggle('co-hl', tab === 'text');
lineJustify.classList.toggle('co-hl', tab === 'text');
note.innerHTML = notes[tab];
}
typeButtons.forEach(btn => {
btn.addEventListener('click', () => switchTab(btn.getAttribute('data-tab')));
});
dirSeg.forEach(btn => {
btn.addEventListener('click', () => {
state.direction = btn.getAttribute('data-dir');
dirSeg.forEach(b => b.classList.toggle('co-seg-on', b === btn));
render();
});
});
overlayOpacity.addEventListener('input', () => {
state.opacity = Number(overlayOpacity.value);
render();
});
overlayColor.addEventListener('input', () => {
state.color = overlayColor.value;
render();
});
textSeg.forEach(btn => {
btn.addEventListener('click', () => {
state.textPos = btn.getAttribute('data-pos');
textSeg.forEach(b => b.classList.toggle('co-seg-on', b === btn));
render();
});
});
switchTab('direction');
render();
})();
</script>
</body>
</html>✅ Summary
Feature | Use Case |
|---|---|
linear-gradient | Horizontal, vertical, angled color fades |
radial-gradient | Circular or spotlight-like effects |
conic-gradient | Circular color transitions (e.g., charts) |
background-image | Set image backgrounds |
Layering | Combine gradients + images for advanced design |