2

UI 設計小錦囊 - 20 種差異鮮明色彩組合

 8 months ago
source link: https://blog.darkthread.net/blog/20-distinct-colors/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

UI 設計小錦囊 - 20 種差異鮮明色彩組合

2024-01-03 10:28 PM 0 438

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

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

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

Fig1_638398894075441030.gif

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

Fig2_638398895478303595.png

為了方便使用,我將這 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@next"></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>

Fig3_638398894080392622.gif

收入 UI 設計錦囊!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK