Montag, 25 August 2025

Top 5 diese Woche

Ähnliche Tutorials

Favicon Generator

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>
Vorheriges Tutorial
Nächstes Tutorial

Hier etwas für dich dabei?