イニシャル自動生成アバター

画像がなくても成立するアバター一覧。氏名からイニシャルを抜き出し、名前自体をハッシュ化して背景色を決めるため、同じ名前は常に同じ色になります。

#css#js#avatar

ライブデモ

コード

HTML
<!-- イニシャル自動生成: 氏名からイニシャルを抜き出し、名前のハッシュ値で背景色を決める(画像なしでも成立) -->
<div class="stage">
  <ul class="initials-grid" id="initialsGrid" aria-label="メンバーのイニシャルアバター一覧"></ul>
</div>
CSS
* { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 28px;
  font-family: "Hiragino Sans", "Segoe UI", system-ui, -apple-system, sans-serif;
  background:
    radial-gradient(circle at 85% 10%, rgba(129, 140, 248, .12) 0%, transparent 42%),
    radial-gradient(circle at 8% 92%, rgba(52, 211, 153, .1) 0%, transparent 45%),
    #0d0e14;
  color: #e2e8f0;
}

.initials-grid {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 22px 16px;
  width: 100%;
  max-width: 420px;
  margin: 0;
  padding: 28px 24px;
  border-radius: 22px;
  background: rgba(255, 255, 255, .045);
  border: 1px solid rgba(255, 255, 255, .09);
  box-shadow: 0 26px 60px -28px rgba(0, 0, 0, .7);
}

/* JSが生成する各アイテムのスタイル */
.initial-item {
  display: grid;
  justify-items: center;
  gap: 9px;
}

.initial-avatar {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: #fff;
  font-weight: 700;
  font-size: 15.5px;
  letter-spacing: .01em;
  box-shadow: 0 10px 20px -9px rgba(0, 0, 0, .6);
  transition: transform .3s cubic-bezier(.22, 1, .36, 1);
}
.initial-item:hover .initial-avatar {
  transform: translateY(-3px) scale(1.06);
}

.initial-name {
  margin: 0;
  font-size: 11.5px;
  text-align: center;
  line-height: 1.3;
  color: rgba(226, 232, 240, .6);
}

@media (prefers-reduced-motion: reduce) {
  .initial-avatar { transition: none; }
  .initial-item:hover .initial-avatar { transform: none; }
}

@media (max-width: 420px) {
  .initials-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 22px 16px; }
}
JavaScript
// イニシャル自動生成: 氏名からイニシャルを抜き出し、名前文字列のハッシュ値から背景色(色相)を決めて描画する
(() => {
  const grid = document.getElementById('initialsGrid');
  if (!grid) return; // null安全

  const NAMES = ['田中 太郎', '佐藤 花子', '鈴木 一郎', 'Emma Wilson', '山本 美咲', 'David Chen'];

  // 「姓 名」または「First Last」の先頭文字を組み合わせる。1語のみなら先頭2文字を使う
  const getInitials = (name) => {
    const parts = name.trim().split(/\s+/).filter(Boolean);
    if (parts.length === 0) return '?';
    if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
    return (parts[0].charAt(0) + parts[1].charAt(0)).toUpperCase();
  };

  // 名前の文字列から安定した数値ハッシュを作り、色相(0-359)に変換する。同じ名前は常に同じ色になる
  const hashHue = (str) => {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      hash = str.charCodeAt(i) + ((hash << 5) - hash);
      hash |= 0; // 32bit整数に丸める
    }
    return Math.abs(hash) % 360;
  };

  const frag = document.createDocumentFragment();
  NAMES.forEach((name) => {
    const hue = hashHue(name);

    const li = document.createElement('li');
    li.className = 'initial-item';

    const avatar = document.createElement('span');
    avatar.className = 'initial-avatar';
    avatar.setAttribute('aria-hidden', 'true');
    avatar.style.background = `linear-gradient(155deg, hsl(${hue} 70% 55%), hsl(${(hue + 40) % 360} 62% 38%))`;
    avatar.textContent = getInitials(name);

    const label = document.createElement('p');
    label.className = 'initial-name';
    label.textContent = name;

    li.appendChild(avatar);
    li.appendChild(label);
    frag.appendChild(li);
  });

  grid.appendChild(frag);
})();

🤖 AIエージェント用プロンプト

このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「イニシャル自動生成アバター」の効果を追加してください。

# 追加してほしい効果
イニシャル自動生成アバター(バッジ & アバター)
画像がなくても成立するアバター一覧。氏名からイニシャルを抜き出し、名前自体をハッシュ化して背景色を決めるため、同じ名前は常に同じ色になります。

# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- イニシャル自動生成: 氏名からイニシャルを抜き出し、名前のハッシュ値で背景色を決める(画像なしでも成立) -->
<div class="stage">
  <ul class="initials-grid" id="initialsGrid" aria-label="メンバーのイニシャルアバター一覧"></ul>
</div>

【CSS】
* { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 28px;
  font-family: "Hiragino Sans", "Segoe UI", system-ui, -apple-system, sans-serif;
  background:
    radial-gradient(circle at 85% 10%, rgba(129, 140, 248, .12) 0%, transparent 42%),
    radial-gradient(circle at 8% 92%, rgba(52, 211, 153, .1) 0%, transparent 45%),
    #0d0e14;
  color: #e2e8f0;
}

.initials-grid {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 22px 16px;
  width: 100%;
  max-width: 420px;
  margin: 0;
  padding: 28px 24px;
  border-radius: 22px;
  background: rgba(255, 255, 255, .045);
  border: 1px solid rgba(255, 255, 255, .09);
  box-shadow: 0 26px 60px -28px rgba(0, 0, 0, .7);
}

/* JSが生成する各アイテムのスタイル */
.initial-item {
  display: grid;
  justify-items: center;
  gap: 9px;
}

.initial-avatar {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: #fff;
  font-weight: 700;
  font-size: 15.5px;
  letter-spacing: .01em;
  box-shadow: 0 10px 20px -9px rgba(0, 0, 0, .6);
  transition: transform .3s cubic-bezier(.22, 1, .36, 1);
}
.initial-item:hover .initial-avatar {
  transform: translateY(-3px) scale(1.06);
}

.initial-name {
  margin: 0;
  font-size: 11.5px;
  text-align: center;
  line-height: 1.3;
  color: rgba(226, 232, 240, .6);
}

@media (prefers-reduced-motion: reduce) {
  .initial-avatar { transition: none; }
  .initial-item:hover .initial-avatar { transform: none; }
}

@media (max-width: 420px) {
  .initials-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 22px 16px; }
}

【JavaScript】
// イニシャル自動生成: 氏名からイニシャルを抜き出し、名前文字列のハッシュ値から背景色(色相)を決めて描画する
(() => {
  const grid = document.getElementById('initialsGrid');
  if (!grid) return; // null安全

  const NAMES = ['田中 太郎', '佐藤 花子', '鈴木 一郎', 'Emma Wilson', '山本 美咲', 'David Chen'];

  // 「姓 名」または「First Last」の先頭文字を組み合わせる。1語のみなら先頭2文字を使う
  const getInitials = (name) => {
    const parts = name.trim().split(/\s+/).filter(Boolean);
    if (parts.length === 0) return '?';
    if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
    return (parts[0].charAt(0) + parts[1].charAt(0)).toUpperCase();
  };

  // 名前の文字列から安定した数値ハッシュを作り、色相(0-359)に変換する。同じ名前は常に同じ色になる
  const hashHue = (str) => {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      hash = str.charCodeAt(i) + ((hash << 5) - hash);
      hash |= 0; // 32bit整数に丸める
    }
    return Math.abs(hash) % 360;
  };

  const frag = document.createDocumentFragment();
  NAMES.forEach((name) => {
    const hue = hashHue(name);

    const li = document.createElement('li');
    li.className = 'initial-item';

    const avatar = document.createElement('span');
    avatar.className = 'initial-avatar';
    avatar.setAttribute('aria-hidden', 'true');
    avatar.style.background = `linear-gradient(155deg, hsl(${hue} 70% 55%), hsl(${(hue + 40) % 360} 62% 38%))`;
    avatar.textContent = getInitials(name);

    const label = document.createElement('p');
    label.className = 'initial-name';
    label.textContent = name;

    li.appendChild(avatar);
    li.appendChild(label);
    frag.appendChild(li);
  });

  grid.appendChild(frag);
})();

# 外部ライブラリ
なし(追加ライブラリ不要)

# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。