惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
Lohrmann on Cybersecurity
Martin Fowler
Martin Fowler
Engineering at Meta
Engineering at Meta
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Azure Blog
Microsoft Azure Blog
G
Google Developers Blog
TaoSecurity Blog
TaoSecurity Blog
博客园_首页
Vercel News
Vercel News
Hugging Face - Blog
Hugging Face - Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Last Week in AI
Last Week in AI
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
The Exploit Database - CXSecurity.com
量子位
Project Zero
Project Zero
A
Arctic Wolf
小众软件
小众软件
NISL@THU
NISL@THU
C
CERT Recently Published Vulnerability Notes
有赞技术团队
有赞技术团队
MongoDB | Blog
MongoDB | Blog
博客园 - 聂微东
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
News and Events Feed by Topic
宝玉的分享
宝玉的分享
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Troy Hunt's Blog
P
Privacy & Cybersecurity Law Blog
Security Latest
Security Latest
B
Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
D
DataBreaches.Net
Schneier on Security
Schneier on Security
The Hacker News
The Hacker News
K
Kaspersky official blog
C
Check Point Blog
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Webroot Blog
Webroot Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
人人都是产品经理
人人都是产品经理
AI
AI
Cisco Talos Blog
Cisco Talos Blog
MyScale Blog
MyScale Blog
Cloudbric
Cloudbric
B
Blog RSS Feed
S
Schneier on Security
P
Palo Alto Networks Blog

Chip Cullen

The need for importance, and AI: Chip Cullen An updated Colorosetta: Chip Cullen The Return of the Font Combinator!: Chip Cullen Changing the number of an item in an ordered list: Chip Cullen My pizza dough recipe as of May 2025: Chip Cullen Gonna try to be a bit more personal: Chip Cullen How I built dynamic social media images in Eleventy using Cloudinary: Chip Cullen My current approach to AI : Chip Cullen Lessons Learned Surviving a Major Product Launch: Chip Cullen How to Build a Drop Down Menu with Modern CSS: Chip Cullen How to stop page scrolling when you have an open dialog element: Chip Cullen Distraction Driven Development: Chip Cullen How I learned to code: the art of letting go: Chip Cullen In praise of the switch statement: Chip Cullen Project stuck? Think about how you’re breaking it down & question everything: Chip Cullen So how did the onboarding experiment go?: Chip Cullen Ideas for an Onboarding Checklist: Chip Cullen I really like Post Mortems: Chip Cullen Raise Red Flags Early: Chip Cullen How to mock fetch requests in React Testing Librarty tests: Chip Cullen Running a Structured Meeting: Chip Cullen Adding the View Transitions API to my personal site: Chip Cullen A Lightweight Way to Read GraphQL Data: Chip Cullen Using a Pros/Cons list to help navigate technical discussions: Chip Cullen How to use variable fonts from Google Fonts: Chip Cullen A new website: now on Eleventy!: Chip Cullen How to Truncate Type at More Than One Line with Just CSS: Chip Cullen Colorosetta: the VS Code Extension!: Chip Cullen Using CSS Custom Properties and Logical Properties Together: Chip Cullen Browser Dev Tools: Element Inspector Popover: Chip Cullen The Link with rel=preload is a Seperate Thing: Chip Cullen How to have Dark & Light Mode Images that also works with User Choice: Chip Cullen Don’t use Viewport Units for Font Size on their own: Chip Cullen A little known Media Query: Aspect Ratio: Chip Cullen Meta thinking: Managing Decisions: Chip Cullen Give Your To-Do's Context: Chip Cullen Say What the Impact is when Reporting Issues: Chip Cullen Firefighting 101: How to Manage Breakages: Chip Cullen How to Deal With Large Pieces of Technical Debt: Chip Cullen Make Your Request Clear: Chip Cullen Analytics events, HTML classes, and protecting against refactoring: Chip Cullen How We Removed jQuery from a large app: Chip Cullen New tool: ColoRosetta: Chip Cullen What width and height attributes should you use with responsive images?: Chip Cullen Django 3.1 gotcha: Referrer Policy has a new default, and it might break iframes and links: Chip Cullen A Javascript Component Pattern: Chip Cullen CSS min(), max() and clamp() Functions: Chip Cullen Pointer Events and Inline Elements in Chrome: Chip Cullen Resolving a github repo and a new Create React App: Chip Cullen How to POST *Data* with the Fetch API: Chip Cullen The Contrast Triangle: Chip Cullen Advice on interviewing for Junior Developers: Chip Cullen Life Lessons Learned From Running a Marathon: How to do something really hard: Chip Cullen A (Brief) intro to Search Engine Structured Data: Chip Cullen Javascript Fallback Values on Variables and Booleans - a hard lesson: Chip Cullen Alfred Tip: Quickly Access Common URLs: Chip Cullen Responsive Images in Hugo - by Laura Kalbag: Chip Cullen Making a Gatsby Site with Multiple Content Types: Chip Cullen How to Create and Use Fixtures in Cypress Tests: Chip Cullen Fixing the 'Bad Interpreter' Error from AWS and Python 3.7: Chip Cullen Creating a Canonical Tag in a Django Template: Chip Cullen Responsive spacing with viewport and ch units: Chip Cullen Welcome to my New Design - 2019: Chip Cullen Django Templates: Block and If statements don’t work like you might expect: Chip Cullen Books I Read in 2018: Chip Cullen Lifehack: 4 ways to help tame common email noise: Chip Cullen How to make better Pull Requests: Adding Steps to Test: Chip Cullen The unsung develpment tool: Spreadsheets: Chip Cullen Troubleshooting Adding and Removing EventListeners: with Arguments, Debounced, and in a React Class: Chip Cullen How to Fake the Window Object in Jest and Enzyme: Chip Cullen Migrating From Wordpress to Hugo: Chip Cullen Background Repeat and its Possibilities: Chip Cullen Getting Started With Front End Tests: a Mindset: Chip Cullen Migrating a Blog - An Opportunity for a Content Inventory: Chip Cullen Moving to Hugo: Chip Cullen JavaScript events: .target vs .currentTarget: Chip Cullen Things I wish I knew when starting with Python: Chip Cullen Leading Ampersands for modifiers in Sass: An anti-pattern: Chip Cullen How to get rid of the "You have mail" message in your terminal: Chip Cullen Why three typefaces rule the web, and what you can do about it: Chip Cullen You shouldn't worry about Section 508 - it's Section 504: Chip Cullen Looping Video Backgrounds: pointers and pitfalls: Chip Cullen How to “preview” a click event tag in the Google Tag Manager console: Chip Cullen Moving on from a technology, or: life after Drupal: Chip Cullen Don’t be a dumb developer: Chip Cullen Two level breadcrumbs with CSS :only-child: Chip Cullen Simplicity comes with experience: Chip Cullen Do the least amount possible: Chip Cullen SVGs vs. Icon Fonts: Two points in favor of Icon Fonts: Chip Cullen Accessible links without underlines: Chip Cullen The Strategic Job Hunt: Chip Cullen Surviving Getting Laid Off: Chip Cullen How to structure your typography in Sass: Chip Cullen Layer Cake: A Responsive Design Layout Pattern: Chip Cullen Creativity is yet to come in Web Design: Chip Cullen Front End Testing with Wraith: A Step by Step Recipe: Chip Cullen Where to begin? How I start a visual design for the web: Chip Cullen If you could only have five Google Fonts: Chip Cullen Why SVG is so cool (or: what happens when you're late to the party on something): Chip Cullen How to apply classes to elements with CKEditor 4, in Drupal 7: Chip Cullen
How to make a color changing favicon: Chip Cullen
2023-06-06 · via Chip Cullen

One of my favorite details of the ColoRosetta tool that I have built is the color changing favicon. It updates as you adjust the color in real time!

The favicon changing color as the user updates the color of ColoRosetta

And if you are using the tool in Safari, the overall color scheme of the browser will also update in real time, via the theme-color meta tag.

The browser chrome updated to green in Safari with ColoRosetta

In this blog post I want to share the function that does this and explain how it works.

First, some context - ColoRosetta is a small React app. When a user changes a color input, first that change is validated, then the color is passed to the root App component. Within that component we determine what kind of color it is, and pass both pieces of information to the colorFavicon function. That lives in it's own file:

import { translatedColor } from '../utils/translatedColor';

// the arguments incomingColor and incomingColor type are specific to ColoRosetta
// you don't necessarily need to have them
const colorFavicon = (incomingColor, incomingColorType) => {
    const img = new Image();
    const canvas = document.createElement('canvas');
    canvas.width = 32;
    canvas.height = 32;
    const ctx = canvas.getContext('2d');
    const link = document.querySelector("link[rel*='icon']") || document.createElement('link');
    link.type = 'image/x-icon';
    link.rel = 'shortcut icon';
    document.getElementsByTagName('head')[0].appendChild(link);
    // translatedColor is partiuclar to ColoRosetta - this can be whatever you want
    const color = translatedColor(incomingColor, incomingColorType, 'hex6');
    img.src = '';
    ctx.drawImage(img, 0, 0);
    ctx.fillStyle = color;
    ctx.fillRect(0, 0, 32, 32);
    link.href = canvas.toDataURL("image/x-icon");

    const meta = document.querySelector("meta[name='theme-color']") || document.createElement('meta');
    meta.name = "theme-color";
    document.getElementsByTagName('head')[0].appendChild(meta);
    meta.content = color;
}

The Favicon

The approach here is that we're going to make a new image & canvas on every color change, encode it as a string, and update the icon link element.

Full disclosure - I got a lot of this functionality from this Stack Overflow answer. What I've added here is the fact that it's updated dynamically by react.

Particularities of ColoRosetta

The arguments incomingColor and incomingColorType are particular to ColoRosetta. I need to know what the user's input actually is, and what kind of color that input is, which is determined by the point that they change a color elsewhere. I need those two pieces of information later to pass to my translatedColor function which transforms the color to a hex6 value.

These three pieces can be whatever you want - this was just how my app works.

Making an Image and Canvas

    const img = new Image();
    const canvas = document.createElement('canvas');
    canvas.width = 32;
    canvas.height = 32;
    const ctx = canvas.getContext('2d');

Here we make a new image, with, well, new Image(). We also make a 32 x 32 pixel canvas, and address it's 2d context (ctx). More on that in a minute.

Making the Link element

    const link = document.querySelector("link[rel*='icon']") || document.createElement('link');
    link.type = 'image/x-icon';
    link.rel = 'shortcut icon';
    document.getElementsByTagName('head')[0].appendChild(link);

Here we look for a link element with a rel attribute that includes icon - or we fall back to creating one. It's a bit belt-and-suspenders to have the fallback in my case, as I have control over the source HTML, but it's a good idea.

Once we have that link, we make sure it's type is image/x-icon and it's rel is shortcut icon. This is what tells the browser that this is a favicon.

We then append this link element to the head. Note - if we found a link element to begin with, this does not add more and more link elements - it replaces it.

Making sure the color is hex6

    const color = translatedColor(incomingColor, incomingColorType, 'hex6');

This is particular to ColoRosetta - incomingColor is the color coming from state in my application. The color that is set by the user can be one of many types. This function takes their input and ensures that it's translated to hex6 (e.g. #121212). We need a hex6 color in order for the color to work with the fillStyle attribute below.

Drawing the icon in Canvas

    img.src = '';
    ctx.drawImage(img, 0, 0);
    ctx.fillStyle = color;
    ctx.fillRect(0, 0, 32, 32);

Remember img? that was the new Image() that we made earlier. We'll need that for our canvas context.

We then get that context, ctx and drawImage using the empty img that we made.

Here is where we actually draw the favicon - we set fillStyle to our hex6 color, and make it a rectangle 32, 32 in size (which is also our canvas height and width).

Encoding the resulting Canvas

We now have a canvas with a 32 x 32 pixel image that's filled with the color that we want.

    link.href = canvas.toDataURL("image/x-icon");

We now encode it as a string with the toDataURL method, and set that string as the href for the link element that we're replacing/appending to the head.

The toDataURL method takes a image type argument - it defaults to image/png. We don't want that in the case of a favicon (though that is changing). We can set it to image/x-icon and we'll get an encoded image that a browser can handle as an icon.

Because this string gets updated every time that the application state changes, the browser will update the icon as it's getting displayed.

Meta Theme Color

I was pretty happy with the above function, but shortly after I added it, Safari added a new meta tag - theme-color which will cause the browser chrome to update it's color.

    const meta = document.querySelector("meta[name='theme-color']") || document.createElement('meta');
    meta.name = "theme-color";
    document.getElementsByTagName('head')[0].appendChild(meta);
    meta.content = color;

Here I'm largely following the same pattern as I did for the favicon. I look for a meta tag, make sure it's named theme-color. We simply replace the tag's content with color which we translated to hex6 earlier.

Conclusion

I hope this line-by-line explanation of how to make a dynamic favicon is helpful. Frankly, having to write out each piece of this made me understand it at a much deeper level. At the very least I hope it gives you ideas on how you can make elements of your applications more dynamic.