今天處理了一個有點意思的東西,目前開發中的專案,由於按鈕顏色可以被使用者客製化,所以原本寫好的 hover, focus 與 disabled 的 CSS 樣式就無用武之地了。
原本用 SCSS 寫的按鈕,大概會有像下面的樣式設定:
$orange-color: #ec7100; $white-color: #fff;
.ant-btn.orange-btn { border-width: 0; background-color: $orange-color; color: $white-color; transition: .5s;
&:hover, &:focus { border-width: 0; background-color: darken($orange-color, 10%); color: $white-color; } &:disabled, &[disabled], &[disabled]:hover, &[disabled]:focus { border-width: 0; background-color: lighten($orange-color, 30%); color: $white-color; } }
|
但是因為按鈕的背景色會從元件外再傳入使用者設定後的顏色,所以如果直接用 inline style 的方式覆蓋按鈕的背景色,這樣會讓原本辛辛苦苦寫的 hover, focus 以及 disabled 狀態的顏色變化都失效。
身為一個前端工程師,對於這種小小狀態變化還是會計較的,所以上網查了一下有沒有方法可以在 inline style 的寫法下,還可以有 hover 的效果,果然找到了這篇 How to Style Hover in React 教學,所以我就舉一反三再去找到另一篇教怎麼用 js 來模擬 Sass/SCSS 中的 darken 與 lighten 的效果(Lighten or Darken Hex Color in JavaScript)。雖然計算出來的數值可能不太一樣,不過已經可以達到想要的效果了。
處理的專案使用了 Ant Design 這套元件庫,所以接下來的範例也會同樣使用 antd 來製作範例。
基本上需要新增一個參數來記錄 hover 狀態,接著再到按鈕上添加 onMouseEnter 與 onMouseLeave 來偵測並改變 hover 的狀態,大致會有下面的 code
const App = ({ bgColor = "#8d86c9" }) => { const [isHover, setIsHover] = useState(false);
return ( <Button onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} > Click me </Button> ) }
|
Lighten and Darken Hex Color
這邊要改變顏色就會用到剛剛另一個網頁的教學,我沒有仔細研究到底怎麼把 hexColor 轉乘 RGB 後再怎麼處理,不過大致上就是希望原本顏色變暗,第二個參數就用負數,希望顏色變亮,第二個參數就用正數
const shadeColor = (hexColor, magnitude) => { hexColor = hexColor.replace(`#`, ``); if (hexColor.length === 6) { const decimalColor = parseInt(hexColor, 16); let r = (decimalColor >> 16) + magnitude; r > 255 && (r = 255); r < 0 && (r = 0); let g = (decimalColor & 0x0000ff) + magnitude; g > 255 && (g = 255); g < 0 && (g = 0); let b = ((decimalColor >> 8) & 0x00ff) + magnitude; b > 255 && (b = 255); b < 0 && (b = 0); return `#${(g | (b << 8) | (r << 16)).toString(16)}`; } else { return hexColor; } };
|
Display hover effect
能夠正確取得 hover 狀態後,就在要寫入的 inline style 加入判斷來改變按鈕背景顏色。
而我希望 mouse hover 時,按鈕的背景色能加深一些些,所以用 shadeColor(bgColor, -30)
const shadeColor = (hexColor, magnitude) => { }
const App = ({ bgColor = "#8d86c9" }) => { const [isHover, setIsHover] = useState(false); const buttonStyle = { color: "#FFFFFF", borderWidth: 0, backgroundColor: isHover ? shadeColor(bgColor, -30) : bgColor };
return ( <Button onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} style={buttonStyle} > Click me </Button> ) }
|
Display disabled status
既然都能夠顯示 hover 效果了,遇到按鈕需要 disable 就可以依此類推的方式來寫。
在 disabled 狀態下,我希望按鈕背景色變淺變亮,所以用 shadeColor(bgColor, 70)
const shadeColor = (hexColor, magnitude) => { };
const App = ({ bgColor = "#8d86c9" }) => { const isDisabled = true; const [isHover, setIsHover] = useState(false); const buttonStyle = { color: "#fff", borderWidth: 0, backgroundColor: isDisabled ? shadeColor(bgColor, 70) : isHover ? shadeColor(bgColor, -30) : bgColor };
return ( <Button disabled={isDisabled} onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} style={buttonStyle} > Click me </Button> ) }
|
Demo
上面寫的程式碼只是部分而已,需要比較完整的範例可以到這裡來看 demo(請耐心等候畫面產生)
Reference