
# 将公司徽标放入你的应用——复制粘贴食谱

> 实用片段用于徽标最终出现的常见形状：一个`<img>`标签、一个React组件、一个Next.js Image、一个Tailwind头像插槽、一个深色模式感知`<picture>`元素、一个OG图像后备和一个服务器签名URL。每个片段都针对公开`https://api.clearlogo.dev`端点工作。
>
> 所有示例都假设你有一个浏览器密钥（用于客户端代码）或一个服务器密钥（用于后端代码）。[从仪表板创建密钥](https://clearlogo.dev/login?lang=zh)。

## 1. 普通HTML

最快的集成——将URL粘贴到`<img>`标签中。

```html
<img
  src="https://api.clearlogo.dev/logo/github.com?size=64&content=80&token=YOUR_BROWSER_KEY"
  alt="GitHub"
  width="64"
  height="64"
/>
```

将`size`设置为匹配渲染的尺寸，这样浏览器就不会浪费带宽缩放更大的资产。

## 2. React组件

一个小的可重用组件涵盖大多数产品UI需求。

```tsx
type CompanyLogoProps = {
  domain: string;
  size?: 32 | 48 | 64 | 96 | 128;
  alt?: string;
};

const BROWSER_KEY = process.env.NEXT_PUBLIC_CLEARLOGO_KEY!;

export function CompanyLogo({ domain, size = 64, alt }: CompanyLogoProps) {
  return (
    <img
      src={`https://api.clearlogo.dev/logo/${domain}?size=${size}&content=80&token=${BROWSER_KEY}`}
      alt={alt ?? `${domain} logo`}
      width={size}
      height={size}
      loading="lazy"
      decoding="async"
    />
  );
}
```

`loading="lazy"`和`decoding="async"`使长列表（CRM、目录、帐户表）不会阻止绘制。

## 3. Next.js `<Image>`

将API主机添加到`next.config.js`一次，然后在任何地方使用优化的`<Image>`组件。

```js
// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      { protocol: "https", hostname: "api.clearlogo.dev" },
    ],
  },
};
```

```tsx
import Image from "next/image";

export function CompanyLogo({ domain, size = 64 }: { domain: string; size?: number }) {
  return (
    <Image
      src={`https://api.clearlogo.dev/logo/${domain}?size=${size * 2}&content=80&token=${process.env.NEXT_PUBLIC_CLEARLOGO_KEY}`}
      alt={`${domain} logo`}
      width={size}
      height={size}
      unoptimized
    />
  );
}
```

请求`size * 2`用于HiDPI显示器上的Retina清晰度。如果你想要API中的WebP协商流向客户端，使用`unoptimized`；如果你想要Next.js自己处理格式协商，删除它。

## 4. Tailwind头像插槽

将徽标放入一个固定的UI插槽中，在品牌之间保持视觉一致。

```tsx
<div className="flex items-center gap-3">
  <div className="h-10 w-10 overflow-hidden rounded-md bg-neutral-100 ring-1 ring-neutral-200">
    <img
      src={`https://api.clearlogo.dev/logo/${domain}?size=64&content=80&token=${BROWSER_KEY}`}
      alt=""
      className="h-full w-full object-contain"
    />
  </div>
  <div>
    <div className="font-medium">{name}</div>
    <div className="text-sm text-neutral-500">{domain}</div>
  </div>
</div>
```

`object-contain`加上一个固定的插槽大小是表和列表最可靠的形状。与`content=80`参数配对，使徽标永远不会抵靠插槽边缘。

## 5. 深色模式感知徽标

使用`<picture>`与`prefers-color-scheme`来源，使浏览器在绘制时交换深色变体——没有JavaScript或每个徽标的重新渲染。

```html
<picture>
  <source
    srcset="https://api.clearlogo.dev/logo/github.com?size=64&theme=dark&token=YOUR_BROWSER_KEY"
    media="(prefers-color-scheme: dark)"
  />
  <img
    src="https://api.clearlogo.dev/logo/github.com?size=64&theme=light&token=YOUR_BROWSER_KEY"
    alt="GitHub"
    width="64"
    height="64"
  />
</picture>
```

包装为React组件：

```tsx
export function CompanyLogo({ domain, size = 64 }: { domain: string; size?: number }) {
  const base = `https://api.clearlogo.dev/logo/${domain}?size=${size}&content=80&token=${BROWSER_KEY}`;
  return (
    <picture>
      <source srcSet={`${base}&theme=dark`} media="(prefers-color-scheme: dark)" />
      <img src={`${base}&theme=light`} alt={`${domain} logo`} width={size} height={size} />
    </picture>
  );
}
```

API在不存在深色版本时回退到浅色变体，所以请求`theme=dark`总是安全的。对于应用级主题开关（不是OS级），从你的主题状态而不是`prefers-color-scheme`驱动来源URL。

## 6. 列表渲染与占位符

对于长列表，立即渲染占位符，使空插槽不会闪烁。

```tsx
function LogoCell({ domain }: { domain: string }) {
  const [loaded, setLoaded] = useState(false);
  return (
    <div className="relative h-10 w-10 rounded-md bg-neutral-100">
      <img
        src={`https://api.clearlogo.dev/logo/${domain}?size=64&content=80&token=${BROWSER_KEY}`}
        alt=""
        loading="lazy"
        onLoad={() => setLoaded(true)}
        className={`h-full w-full object-contain transition-opacity ${
          loaded ? "opacity-100" : "opacity-0"
        }`}
      />
    </div>
  );
}
```


## 7. 错误后备与第一个字母

如果API找不到域的徽标，渲染一个确定性字母头像代替。

```tsx
function LogoOrFallback({ domain, name }: { domain: string; name: string }) {
  const [errored, setErrored] = useState(false);

  if (errored) {
    return (
      <div className="flex h-10 w-10 items-center justify-center rounded-md bg-neutral-200 font-medium text-neutral-600">
        {name[0]?.toUpperCase() ?? "?"}
      </div>
    );
  }

  return (
    <img
      src={`https://api.clearlogo.dev/logo/${domain}?size=64&content=80&token=${BROWSER_KEY}`}
      alt={`${name} logo`}
      width={40}
      height={40}
      className="rounded-md"
      onError={() => setErrored(true)}
    />
  );
}
```

后备从不网络请求，所以即使冷行也保持敏捷。

## 8. Open Graph图像后备

使用服务器端获取将徽标嵌入到你自己的动态生成的OG卡中。

```ts
// app/og/route.ts (Next.js, Edge runtime)
import { ImageResponse } from "next/og";

export const runtime = "edge";

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const domain = searchParams.get("domain") ?? "example.com";

  const logoUrl = `https://api.clearlogo.dev/logo/${domain}?size=256&content=80&token=YOUR_SERVER_KEY`;

  return new ImageResponse(
    (
      <div style={{ display: "flex", alignItems: "center", padding: 64 }}>
        <img src={logoUrl} width={128} height={128} alt="" />
        <span style={{ marginLeft: 32, fontSize: 64 }}>{domain}</span>
      </div>
    ),
    { width: 1200, height: 630 },
  );
}
```

在这里使用**服务器**密钥，而不是浏览器密钥——Edge函数是服务器端的，服务器密钥在不受限制的源标头中存活。

## 9. 后端签名用于敏感UI

当你不想要URL公开时（例如内部管理工具），通过你的后端代理。

```ts
// app/api/logo/[domain]/route.ts (Next.js)
export async function GET(
  request: Request,
  { params }: { params: { domain: string } },
) {
  const upstream = await fetch(
    `https://api.clearlogo.dev/logo/${params.domain}?size=128&content=80`,
    { headers: { Authorization: `Bearer ${process.env.CLEARLOGO_SERVER_KEY}` } },
  );
  return new Response(upstream.body, {
    headers: {
      "Content-Type": upstream.headers.get("Content-Type") ?? "image/png",
      "Cache-Control": "public, max-age=86400, s-maxage=86400",
    },
  });
}
```

现在你的前端使用`/api/logo/{domain}`——页面源中没有API密钥，你在自己的CDN处控制缓存。

## 10. TypeScript助手

一个单个助手在代码库中保持URL构造一致。

```ts
type LogoOptions = {
  size?: 16 | 32 | 48 | 64 | 96 | 128 | 192 | 256 | 512 | 1024;
  content?: number; // 50–100, step 5
  theme?: "light" | "dark";
  format?: "png" | "webp" | "jpeg";
};

export function logoUrl(domain: string, opts: LogoOptions = {}): string {
  const params = new URLSearchParams({
    size: String(opts.size ?? 64),
    content: String(opts.content ?? 80),
    token: process.env.NEXT_PUBLIC_CLEARLOGO_KEY!,
  });
  if (opts.theme) params.set("theme", opts.theme);
  if (opts.format) params.set("format", opts.format);
  return `https://api.clearlogo.dev/logo/${encodeURIComponent(domain)}?${params}`;
}
```

`encodeURIComponent`保护不寻常字符在域名中，使助手安全地使用不受信任的输入调用。

## 11. 预连接以提前准备连接

对于渲染几十个徽标在折叠上方的仪表板，第一个请求支付DNS、TCP和TLS。将单个`<link rel="preconnect">`添加到你的文档标题，以便在第一个`<img>`命中前连接准备就绪——每个后续徽标都获得一个抢先而没有每URL预加载膨胀。

```html
<link rel="preconnect" href="https://api.clearlogo.dev" crossorigin />
<link rel="dns-prefetch" href="https://api.clearlogo.dev" />
```

```tsx
// Next.js
import Head from "next/head";

export function ClearLogoPreconnect() {
  return (
    <Head>
      <link rel="preconnect" href="https://api.clearlogo.dev" crossOrigin="" />
      <link rel="dns-prefetch" href="https://api.clearlogo.dev" />
    </Head>
  );
}
```

`preconnect`立即解决DNS并打开TCP/TLS握手；`dns-prefetch`是忽略预连接的浏览器的廉价后备。总共两个提示，无论页面渲染多少徽标。相比每个徽标的`<link rel="preload" as="image">`更倾向于这个——预加载很重，计入带宽预算，如果渲染的URL最终与预加载的略有不同（大小、主题、令牌）也无助益。

## 常见问题

### 我应该从哪个食谱开始？

对于单个徽标，普通`<img>`食谱就足够了。对于列表和表，跳到Tailwind头像插槽和延迟加载模式。

### 我需要一个密钥用于测试吗？

否。端点对低体积浏览匿名工作。在你发布到生产前添加浏览器密钥，以便请求被正确归因并计入你的计划。

### 我应该请求什么大小？

匹配CSS中的渲染大小，然后请求`2x`用于Retina清晰度。不要为32像素插槽请求`1024`——它浪费带宽并看起来不会更好。

### 我如何在没有JavaScript的情况下处理深色模式？

使用由`media="(prefers-color-scheme: dark)"`门控的`<picture>`元素与`<source>`。浏览器在绘制时选择正确的URL——没有React钩子、没有每个徽标的重新渲染、长列表中没有每行开销。

### 我如何使徽标列表加载更快？

在你的文档标题中添加单个`<link rel="preconnect" href="https://api.clearlogo.dev">`。这为页面上的每个徽标打开一次DNS/TCP/TLS，这比每URL的`<link rel="preload">`便宜。

### 当API返回没有徽标时，我如何显示后备？

在`<img>`上监听`onError`并交换字母头像或通用图标。上面的错误后备食谱是生产形状。

### 我可以从服务器端渲染使用浏览器密钥吗？

你可以——但服务器密钥是更好的拟合，因为它通过`Authorization: Bearer …`而不是依靠源检查发送请求。对于Next.js服务器组件、OG路由或后端代理，使用服务器密钥。

### 我如何在我自己的CDN处缓存徽标？

使用上面的后端签名食谱。上游响应包括长期`Cache-Control`，所以你可以在你的代理上设置相同的标题并让你的CDN做其余部分。
