Dieses interaktive Tool erlaubt es, individuelle Favicons für Webseiten in Echtzeit zu erstellen. Nutzer können Farben, Formen, Symbole und Text anpassen und sehen direkt eine Live-Vorschau des Favicons. Die Vorschau ist dynamisch und reagiert sofort auf Änderungen, sodass das Design optimal abgestimmt werden kann. Das Skript ist im modernen Agentur-Stil gestaltet, übersichtlich und benutzerfreundlich, ideal für Webdesigner, Entwickler oder Agenturen.
Funktionen:
- Anpassbare Farben, Formen und Symbole
- Live-Vorschau des Favicons in verschiedenen Größen
- Direkter Download als ICO oder PNG
- Einfache Bedienung durch interaktive Regler
- Stilvolles, responsives Design wie von einer professionellen Agentur
Hinweis: Das Tool ist lokal oder online nutzbar und dient der schnellen und professionellen Erstellung von Favicons ohne zusätzliche Software.
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Dreamcodes Favicon Generator — Blue Edition</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
<style>
:root{
--bg:#0b1020;
--panel:#0f1530;
--muted:#94a6c4;
--accent:#6c8cff;
--accent2:#1ee0a1;
--card:#0f153a;
--stroke:rgba(255,255,255,.06);
--text:#e8eefc;
}
*{box-sizing:border-box}
body{margin:0;font-family:Inter,system-ui,Arial,sans-serif;background:
radial-gradient(900px 600px at 10% -10%, rgba(108,140,255,.12), transparent 50%),
var(--bg);color:var(--text);-webkit-font-smoothing:antialiased}
.container{max-width:1200px;margin:28px auto;padding:20px}
.header{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:18px}
.brand{display:flex;align-items:center;gap:12px}
.logo{width:46px;height:46px;border-radius:10px;background:linear-gradient(135deg,var(--accent),#9aaeff);box-shadow:0 8px 30px rgba(108,140,255,.25)}
.brand h1{margin:0;font-size:20px}
.layout{
display:grid;
grid-template-columns: 520px 1fr;
gap:18px;
align-items:start;
}
/* ensure preview never overlaps controls */
.controls{
background:linear-gradient(180deg, rgba(255,255,255,.02), rgba(255,255,255,.01));
border:1px solid var(--stroke);border-radius:14px;padding:16px;
}
.preview{
background:linear-gradient(180deg, rgba(255,255,255,.02), rgba(255,255,255,.01));
border:1px solid var(--stroke);border-radius:14px;padding:20px;display:flex;flex-direction:column;align-items:center;
min-height:360px; position:relative; overflow:hidden;
}
.form-row{display:flex;gap:10px;align-items:center;margin-bottom:10px}
.input, select, textarea{width:100%;padding:10px;border-radius:10px;border:1px solid var(--stroke);background:transparent;color:var(--text)}
.input[type="color"]{padding:6px;height:44px}
.btn{background:linear-gradient(180deg,var(--accent),#4f6bff);color:white;padding:10px 12px;border-radius:10px;border:0;cursor:pointer;font-weight:700}
.btn.ghost{background:transparent;border:1px solid var(--stroke)}
.small{font-size:13px;color:var(--muted)}
.card-title{font-weight:700;margin:0 0 8px 0}
.options{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-bottom:10px}
.preview-stage{display:flex;flex-direction:column;align-items:center;gap:12px}
.preview-box{background:linear-gradient(180deg, rgba(255,255,255,.02), rgba(255,255,255,.01));border-radius:20px;padding:18px;display:flex;flex-direction:column;align-items:center;gap:10px;min-width:200px}
.preview-img{width:96px;height:96px;border-radius:18px;display:flex;align-items:center;justify-content:center;overflow:hidden;border:1px solid rgba(255,255,255,.04);background:white}
.preview-sm{display:flex;gap:10px;align-items:center}
.badge{font-size:12px;padding:6px 10px;border-radius:999px;background:rgba(255,255,255,.03);border:1px solid var(--stroke)}
.snippet{width:100%;background:rgba(0,0,0,.18);padding:12px;border-radius:10px;color:var(--muted);font-family:monospace;font-size:13px}
.download-grid{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
.link-small{font-size:13px;color:var(--accent);text-decoration:none}
.footer{margin-top:18px;padding:12px;border-top:1px solid var(--stroke);display:flex;justify-content:space-between;color:var(--muted);font-size:13px}
@media(max-width:980px){.layout{grid-template-columns:1fr}.preview{order:2}.controls{order:1}}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="brand">
<div class="logo" aria-hidden="true"></div>
<h1>Favicon Generator — Agentur Edition</h1>
</div>
<div class="small">Erstelle hochwertige Favicons · PNG Größen · Apple Touch · HTML Snippets</div>
</div>
<div class="layout">
<aside class="controls" aria-label="Einstellungen">
<div class="card-title">Uploads & Basis</div>
<div class="form-row">
<input id="file" class="input" type="file" accept="image/*">
</div>
<div class="card-title">Text/Emoji Alternative</div>
<div class="form-row">
<input id="iconText" class="input" placeholder="z. B. 'D' oder '🔥'">
</div>
<div class="card-title">Design</div>
<div class="options">
<label class="small">Hintergrundfarbe
<input id="bgColor" type="color" value="#ffffff" class="input">
</label>
<label class="small">Iconfarbe
<input id="fgColor" type="color" value="#111827" class="input">
</label>
</div>
<div class="options">
<label class="small">Form
<select id="shape" class="input">
<option value="square">Quadratisch</option>
<option value="rounded">Abgerundet</option>
<option value="circle">Kreis</option>
</select>
</label>
<label class="small">Padding (px)
<input id="padding" type="number" class="input" value="14" min="0" max="80">
</label>
</div>
<div class="card-title">Typografie</div>
<div class="options">
<label class="small">Schriftart
<select id="fontFamily" class="input">
<option value="Inter">Inter</option>
<option value="Arial">Arial</option>
<option value="Segoe UI">Segoe UI</option>
<option value="Verdana">Verdana</option>
</select>
</label>
<label class="small">Font-Weight
<select id="fontWeight" class="input">
<option value="700">Bold</option>
<option value="600">Semibold</option>
<option value="500">Medium</option>
</select>
</label>
</div>
<div style="margin-top:12px">
<div class="card-title">Output Optionen</div>
<label class="small">Erzeuge Größen</label>
<div style="display:flex;gap:8px;margin-top:6px">
<label class="badge"><input id="s16" type="checkbox" checked> 16</label>
<label class="badge"><input id="s32" type="checkbox" checked> 32</label>
<label class="badge"><input id="s48" type="checkbox" checked> 48</label>
<label class="badge"><input id="s64" type="checkbox" checked> 64</label>
<label class="badge"><input id="s128" type="checkbox" checked>128</label>
<label class="badge"><input id="s256" type="checkbox" checked>256</label>
</div>
<div style="margin-top:12px;display:flex;gap:8px">
<button class="btn" id="regen">Aktualisieren</button>
<button class="btn ghost" id="downloadAll">Alle herunterladen</button>
</div>
</div>
<div style="margin-top:14px">
<div class="card-title">Snippets</div>
<div class="snippet" id="htmlSnippet" aria-live="polite"></div>
</div>
</aside>
<main class="preview" aria-label="Vorschau">
<div class="preview-stage">
<div class="preview-box" role="region" aria-label="Live Vorschau">
<div class="small">Live Vorschau</div>
<div id="previewWrap" class="preview-img" style="background:#fff">
<canvas id="previewCanvas" width="512" height="512" style="width:96px;height:96px;"></canvas>
</div>
<div class="preview-sm">
<div class="small">Tab Icon</div>
<div class="badge" id="favName">favicon.png</div>
</div>
</div>
<div style="width:100%;display:flex;flex-direction:column;gap:10px;align-items:stretch">
<div class="small">Generierte Dateien</div>
<div id="files" class="download-grid" aria-live="polite"></div>
</div>
</div>
<div style="width:100%;margin-top:18px">
<div class="small">Tipps</div>
<ul class="small" style="color:var(--muted);margin:8px 0 0 18px">
<li>Für maximale Erkennbarkeit einfache Formen und starke Kontraste verwenden</li>
<li>Nutze 32x32 und 16x16 für klassische Favicons, 180x180 für Apple Touch</li>
<li>Wenn du ein komplexes Bild hochlädst, skaliere oder vereinfache es vorher</li>
</ul>
</div>
</main>
</div>
<div class="footer">
<div>© <p>© <span id="year"></span> <a href="https://dreamcodes.net" target="_blank">Dreamcodes.net</a></p></div>
<div class="small">Favicon Generator — Blue Style · PNG Export · HTML Snippets</div>
</div>
</div>
<script>
document.getElementById('year').textContent = new Date().getFullYear()
// Utils
const el = id => document.getElementById(id)
const pick = arr => arr[Math.floor(Math.random()*arr.length)]
// state
let uploadedImage = null
// load uploaded image
el('file').addEventListener('change', (ev)=>{
const f = ev.target.files[0]
if(!f) { uploadedImage = null; renderAll(); return }
const url = URL.createObjectURL(f)
const img = new Image()
img.onload = ()=>{ uploadedImage = img; renderAll() }
img.onerror = ()=>{ uploadedImage = null; alert('Bild konnte nicht geladen werden') }
img.src = url
})
// render to canvas with current settings
function renderToCanvas(size){
const canvas = document.createElement('canvas')
canvas.width = canvas.height = size
const ctx = canvas.getContext('2d')
const bg = el('bgColor').value
const fg = el('fgColor').value
const shape = el('shape').value
const padding = Math.max(0, Math.min(80, +el('padding').value || 14))
const inner = size - padding*2
// background
ctx.clearRect(0,0,size,size)
ctx.fillStyle = bg
if(shape === 'circle'){
const r = size/2
ctx.beginPath(); ctx.arc(r,r,r); ctx.fill()
} else if(shape === 'rounded'){
const r = Math.min(48, Math.floor(size*0.12))
roundRect(ctx, 0,0,size,size, r); ctx.fill()
} else {
ctx.fillRect(0,0,size,size)
}
// draw image or text/icon
const hasImage = uploadedImage !== null
if(hasImage){
// draw image centered and fit inside inner
const img = uploadedImage
// compute fit
const ratio = Math.min(inner / img.width, inner / img.height)
const w = img.width * ratio, h = img.height * ratio
const x = (size - w)/2, y = (size - h)/2
// optional: drop shadow for legibility
ctx.save()
ctx.globalCompositeOperation = 'source-over'
ctx.drawImage(img, x, y, w, h)
ctx.restore()
} else {
const text = el('iconText').value.trim() || ''
if(text){
// draw text centered
ctx.fillStyle = fg
const fontWeight = el('fontWeight').value
const fontFamily = el('fontFamily').value
// choose font size based on inner
let fs = Math.floor(inner * 0.7)
if(text.length > 2) fs = Math.floor(inner * 0.45)
ctx.font = `${fontWeight} ${fs}px "${fontFamily}", sans-serif`
ctx.textAlign = 'center'; ctx.textBaseline = 'middle'
// stroke for contrast
ctx.lineWidth = Math.max(2, Math.floor(fs/12))
ctx.strokeStyle = 'rgba(0,0,0,0.25)'
ctx.strokeText(text, size/2, size/2 + 1)
ctx.fillText(text, size/2, size/2)
} else {
// fallback: simple icon (circle)
ctx.fillStyle = fg
const r = inner/2
ctx.beginPath(); ctx.arc(size/2, size/2, r, 0, Math.PI*2); ctx.fill()
}
}
return canvas
}
// helper round rect
function roundRect(ctx,x,y,w,h,r){
ctx.beginPath()
ctx.moveTo(x+r,y)
ctx.arcTo(x+w,y,x+w,y+h,r)
ctx.arcTo(x+w,y+h,x,y+h,r)
ctx.arcTo(x,y+h,x,y,r)
ctx.arcTo(x,y,x+w,y,r)
ctx.closePath()
}
// create preview for the UI
function renderPreview(){
const previewCanvas = el('previewCanvas')
const big = renderToCanvas(512)
// scale draw to preview canvas
const ctx = previewCanvas.getContext('2d')
ctx.clearRect(0,0,previewCanvas.width,previewCanvas.height)
ctx.drawImage(big, 0, 0, previewCanvas.width, previewCanvas.height)
// update file list
updateFiles()
}
// updates downloadable files list
function updateFiles(){
const sizes = [16,32,48,64,128,180,256]
const chosen = sizes.filter(sz=>{
if(sz===16) return el('s16').checked
if(sz===32) return el('s32').checked
if(sz===48) return el('s48').checked
if(sz===64) return el('s64').checked
if(sz===128) return el('s128').checked
if(sz===256) return el('s256').checked
if(sz===180) return true // apple touch always available
return false
})
const container = el('files')
container.innerHTML = ''
chosen.forEach(sz=>{
const c = renderToCanvas(sz)
const url = c.toDataURL('image/png')
const a = document.createElement('a')
a.className = 'link-small badge'
a.href = url
a.download = `favicon-${sz}x${sz}.png`
a.textContent = `PNG ${sz}×${sz}`
container.appendChild(a)
// attach click to increment KPI
a.addEventListener('click', ()=> incKpiFile())
})
// update html snippet
const snippet = generateHtmlSnippet()
el('htmlSnippet').textContent = snippet
}
// increment KPI for downloads
function incKpiFile(){ const elc = document.getElementById('kpi-count'); elc.textContent = (+elc.textContent)+1; el('kpi-last').textContent = 'Datei heruntergeladen' }
// main render
function renderAll(){
renderPreview()
}
// regenerate button
el('regen').addEventListener('click', (e)=>{
e.preventDefault()
renderAll()
el('kpi-last').textContent = 'vorgeschlagen aktualisiert'
})
// download all (zip not used) -> trigger downloads for each selected size sequentially
el('downloadAll').addEventListener('click', async (e)=>{
e.preventDefault()
const sizes = [16,32,48,64,128,180,256]
const chosen = sizes.filter(sz=>{
if(sz===16) return el('s16').checked
if(sz===32) return el('s32').checked
if(sz===48) return el('s48').checked
if(sz===64) return el('s64').checked
if(sz===128) return el('s128').checked
if(sz===256) return el('s256').checked
if(sz===180) return true
})
for(const sz of chosen){
const c = renderToCanvas(sz)
const a = document.createElement('a')
a.href = c.toDataURL('image/png')
a.download = `favicon-${sz}x${sz}.png`
document.body.appendChild(a)
a.click()
a.remove()
await new Promise(r=>setTimeout(r,120))
}
el('kpi-last').textContent = 'Alles heruntergeladen'
})
// generate HTML snippet
function generateHtmlSnippet(){
// use the 32x32 and 180x180 as default names
const baseName32 = 'favicon-32x32.png'
const baseName180 = 'favicon-180x180.png'
const snippet = `<link rel="icon" type="image/png" sizes="32x32" href="${baseName32}">
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
<link rel="apple-touch-icon" sizes="180x180" href="${baseName180}">
<!-- optional: larger PNG for modern browsers -->
<link rel="icon" type="image/png" sizes="256x256" href="favicon-256x256.png">`
return snippet
}
// init
renderAll()
// keyboard quick generate: Ctrl+Enter
document.addEventListener('keydown', (e)=>{ if((e.ctrlKey||e.metaKey) && e.key==='Enter'){ renderAll(); el('kpi-last').textContent='Schnell generiert' } })
</script>
</body>
</html>