寫網頁介面時,有時我會想用多種顏色表示不同類別資料,此時如何挑選一組彼此差異明顯的顏色,差異大到即使同框出現也不致混淆,這批顏色該如何搭配組合是個學問。

面對這個常見的小需求,我 Google 到不錯的建議 - List of 20 Simple, Distinct Colors,為了繪製捷運路線圖需要 20 種不同且差異鮮明的顏色(若加上黑白共 22 種),作者花了不少時間,力求各顏色間不易混淆、色彩鮮明、具備對映顏色名稱,看起來也蠻順眼的,我很喜歡。

考慮色弱及視力障礙人士的無障礙需求,作者還整理了涵蓋 99% (19色)、99.99% (9色)、100% (5色) 人口比例的較高反差組合。

另外,選擇 Convenient 順序時,可依序取用,若需要六個顏色則取 1 - 6,需要 12 種取 1 - 12,數字小的優先使用,效果較好。

為了方便使用,我將這 20 種顏色轉成 CSS 樣式並分為前景版及背景版,背景版還需依據背景色選用醒目的文字顏色,我想到之前 Github Copilot 教我的魔術數字公式complementary = (r * 0.299 + g * 0.587 + b * 0.114) > 186 ? '#000000' : '#ffffff';

寫幾行 JavaScript 產生 CSS 樣式:

const pool = ['#e6194B', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#42d4f4', '#f032e6', '#bfef45', '#fabed4', '#469990', '#dcbeff', '#9A6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#a9a9a9', '#ffffff', '#000000'];
const complementary = (hex) => {
    const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return (parseInt(m[1], 16) * 0.299 + parseInt(m[2], 16) * 0.587 + parseInt(m[3], 16) * 0.114) > 186 ? '#000000' : '#ffffff';
}
console.log(pool.map((c, i) => `.dc-${i} { color:${c}; } .dbc-${i} { color:${complementary(c)}; background-color:${c}; }`).join('\n'));

最後輸出結果如下:

.dc-0 { color:'#e6194B'; } .dbc-0 { color:'#ffffff'; background-color:'#e6194B'; }
.dc-1 { color:'#3cb44b'; } .dbc-1 { color:'#ffffff'; background-color:'#3cb44b'; }
.dc-2 { color:'#ffe119'; } .dbc-2 { color:'#000000'; background-color:'#ffe119'; }
.dc-3 { color:'#4363d8'; } .dbc-3 { color:'#ffffff'; background-color:'#4363d8'; }
.dc-4 { color:'#f58231'; } .dbc-4 { color:'#ffffff'; background-color:'#f58231'; }
.dc-5 { color:'#911eb4'; } .dbc-5 { color:'#ffffff'; background-color:'#911eb4'; }
.dc-6 { color:'#42d4f4'; } .dbc-6 { color:'#ffffff'; background-color:'#42d4f4'; }
.dc-7 { color:'#f032e6'; } .dbc-7 { color:'#ffffff'; background-color:'#f032e6'; }
.dc-8 { color:'#bfef45'; } .dbc-8 { color:'#000000'; background-color:'#bfef45'; }
.dc-9 { color:'#fabed4'; } .dbc-9 { color:'#000000'; background-color:'#fabed4'; }
.dc-10 { color:'#469990'; } .dbc-10 { color:'#ffffff'; background-color:'#469990'; }
.dc-11 { color:'#dcbeff'; } .dbc-11 { color:'#000000'; background-color:'#dcbeff'; }
.dc-12 { color:'#9A6324'; } .dbc-12 { color:'#ffffff'; background-color:'#9A6324'; }
.dc-13 { color:'#fffac8'; } .dbc-13 { color:'#000000'; background-color:'#fffac8'; }
.dc-14 { color:'#800000'; } .dbc-14 { color:'#ffffff'; background-color:'#800000'; }
.dc-15 { color:'#aaffc3'; } .dbc-15 { color:'#000000'; background-color:'#aaffc3'; }
.dc-16 { color:'#808000'; } .dbc-16 { color:'#ffffff'; background-color:'#808000'; }
.dc-17 { color:'#ffd8b1'; } .dbc-17 { color:'#000000'; background-color:'#ffd8b1'; }
.dc-18 { color:'#000075'; } .dbc-18 { color:'#ffffff'; background-color:'#000075'; }
.dc-19 { color:'#a9a9a9'; } .dbc-19 { color:'#ffffff'; background-color:'#a9a9a9'; }
.dc-20 { color:'#ffffff'; } .dbc-20 { color:'#000000'; background-color:'#ffffff'; }
.dc-21 { color:'#000000'; } .dbc-21 { color:'#ffffff'; background-color:'#000000'; }

簡單寫個網頁測試效果:線上展示

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <style>
.dc-0 { color:#e6194B; } .dbc-0 { color:#ffffff; background-color:#e6194B; }
.dc-1 { color:#3cb44b; } .dbc-1 { color:#ffffff; background-color:#3cb44b; }
.dc-2 { color:#ffe119; } .dbc-2 { color:#000000; background-color:#ffe119; }
.dc-3 { color:#4363d8; } .dbc-3 { color:#ffffff; background-color:#4363d8; }
.dc-4 { color:#f58231; } .dbc-4 { color:#ffffff; background-color:#f58231; }
.dc-5 { color:#911eb4; } .dbc-5 { color:#ffffff; background-color:#911eb4; }
.dc-6 { color:#42d4f4; } .dbc-6 { color:#ffffff; background-color:#42d4f4; }
.dc-7 { color:#f032e6; } .dbc-7 { color:#ffffff; background-color:#f032e6; }
.dc-8 { color:#bfef45; } .dbc-8 { color:#000000; background-color:#bfef45; }
.dc-9 { color:#fabed4; } .dbc-9 { color:#000000; background-color:#fabed4; }
.dc-10 { color:#469990; } .dbc-10 { color:#ffffff; background-color:#469990; }
.dc-11 { color:#dcbeff; } .dbc-11 { color:#000000; background-color:#dcbeff; }
.dc-12 { color:#9A6324; } .dbc-12 { color:#ffffff; background-color:#9A6324; }
.dc-13 { color:#fffac8; } .dbc-13 { color:#000000; background-color:#fffac8; }
.dc-14 { color:#800000; } .dbc-14 { color:#ffffff; background-color:#800000; }
.dc-15 { color:#aaffc3; } .dbc-15 { color:#000000; background-color:#aaffc3; }
.dc-16 { color:#808000; } .dbc-16 { color:#ffffff; background-color:#808000; }
.dc-17 { color:#ffd8b1; } .dbc-17 { color:#000000; background-color:#ffd8b1; }
.dc-18 { color:#000075; } .dbc-18 { color:#ffffff; background-color:#000075; }
.dc-19 { color:#a9a9a9; } .dbc-19 { color:#ffffff; background-color:#a9a9a9; }
.dc-20 { color:#ffffff; } .dbc-20 { color:#000000; background-color:#ffffff; }
.dc-21 { color:#000000; } .dbc-21 { color:#ffffff; background-color:#000000; }
        </style>
        <style>
            input[type="number"] {
                width: 4em;
            }
            .blocks {
                display: flex;
                flex-direction: row;
                flex-wrap: wrap;
                padding: 6px;
            }
            .blocks > span {
                width: 2em; text-align: center;
                margin: 2px;
                border: 1px solid #ccc;
            }
        </style>
        <script src="https://unpkg.com/vue@latest"></script>
    </head>
    <body>
        <div id="app">
            <label>
                <input type="number" v-model="colorCount" min="4" max="22" /> Colors
            </label>
            <label>
                <input type="number" v-model="blockCount" min="10" max="255" /> Blocks
            </label>
            <label>
                <input type="checkbox" v-model="bgcolor" /> Background
            </label>
            <div class="blocks">
                <span v-for="item in items" :class="item.css">
                    {{item.seq}}
                </span>
            </div>
            
        </div>
        <script>
            const app = Vue.createApp({
                data: function () {
                    return {
                        colorCount: 20,
                        blockCount: 100,
                        bgcolor: false
                    };
                },
                computed: {
                    items: function () {
                        const items = [];
                        for (let i = 0; i < this.blockCount; i++) {
                            items.push({
                                seq: i + 1,
                                css: (this.bgcolor ? 'dbc-' : 'dc-') + (parseInt(Math.random() * this.colorCount) % this.colorCount)
                            });
                        }
                        items.sort(() => Math.random() - 0.5);
                        return items;
                    }
                },
            });
            app.mount('#app');
        </script>
    </body>
</html>

收入 UI 設計錦囊!

The suggestion of 20 distinct colors in same UI, this article shows a easy way to use them in HTML.


Comments

# by 小黑

「魔術數字公式」的似乎連結失效了

# by Ike

感覺 #42d4f4 搭 黑色字 會比較適合

# by Ka-iu

用我的網路打開線上展示會發現程式碼沒有執行,發現是因為這個 library 404: <script src="https://unpkg.com/vue@next"></script> 我從 Vue 官網找了這個套上去就正常了 <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> https://jsbin.com/puguges

# by JD

https://unpkg.com/vue@next 這個用不了 得換https://unpkg.com/vue@latest或其他

# by Jeffrey

to Kai-ui & JD, 感謝回報與補充,已修正。

Post a comment