CSS 實現仿 Windows10 鼠標照亮邊框效果

安裝最新 Windows 10 update 以後,注意到系統 UI 裏有一個很棒的細節效果,在開始菜單的磁貼裏或者 UWP 風格的設置界面中,元素的高亮邊框是能夠感知鼠標的,邊框的高亮部分會跟隨鼠標的移動而移動。頓時靈機一動,這個效果用 CSS 能否實現?html

分析

拿桌面日曆中的效果爲例,鼠標移動時附近的邊框也漸變性可見。這個效果不就是探照燈效果嘛!這個徹底能夠用 CSS 中的 mask 蒙版配合一個徑向漸變實現。web

但問題是,mask 蒙版是做用於整個元素的,沒辦法只做用於 border 而不影響內容。這個,那隻能把 border 和實際內容分離用不一樣層來表示了。嗯,鼠標移動就更新蒙版位置,應該不成問題。瀏覽器

實現

準備工做

首先,擼好兩層日曆格子,一層展現日期信息,一層展現探照燈效果的邊框。用 flex 佈局也好,grid 也好,哪怕 inline-block 也都是沒有問題的,這都不重要,重要的是上下兩層的格子必定要對齊,而後咱們用 relative 的容器把這兩層 absolute 層圈起來,固定住。sass

<div class="calendar">
    <div class="calendar-header">
        <div class="week-day"></div>
        <div class="week-day"></div>
        <div class="week-day"></div>
        <div class="week-day"></div>
        <div class="week-day"></div>
        <div class="week-day"></div>
        <div class="week-day"></div>
    </div>
    <div class="calendar-body">
        <div class="grid-container border-layer">
            <div class="grid-item"></div>
            ...
            <div class="grid-item"></div>
        </div>
            <div class="grid-container number-layer">
            <div class="grid-item"><span>28</span><span>十四</span></div>
            <div class="grid-item"><span>29</span><span>十五</span></div>
            ...
            <div class="grid-item"><span>2</span><span>十九</span></div>
        </div>
    </div>
  </div>
複製代碼

層示意圖:bash

效果就是這樣了: 佈局

鼠標沒有放上去的時候,先把 border 層隱藏掉。flex

.border-layer {
 ...
  visibility: hidden;
}

.calendar:hover .border-layer {
  visibility: visible;
}
複製代碼

CSS Mask

CSS Mask 相似於 Photoshop 中的圖層蒙版,可使用一張圖做爲蒙版用做在目標元素上,圖片的 alpha 通道(也就是透明度信息)決定了目標元素哪部分可見(也能夠選擇使用亮度信息)。ui

舉個例子,若是蒙版圖片是一張半透明圖,則做用到實際元素上效果和設置 opacity: 0.5 效果同樣;若是蒙版圖片是一張中間鏤空的五角星,則效果就是元素被裁剪成五角星形狀。spa

Mask 的語法和 background 的語法幾乎徹底一致,這裏咱們用徑向漸變建立一個半徑 80px 從中心白色到邊緣透明的漸變圓,配合 mask-repeat 和 mask-size 防止 repeat 和變形。code

-webkit-mask-image: radial-gradient(circle at center, white 0%, transparent 80px);
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-size: 160px 160px; /* 半徑80px 因此 size 須要是 160px */
複製代碼

接下來咱們來更新 mask-position 。這裏有兩個點要注意,一是獲取鼠標對目標元素的相對座標,一是 position 偏移。

MouseEvent 中有一堆的 X/Y,咱們用相對 document 的座標 pageX/pageY,減去目標元素相對 document 的座標,就能獲得咱們須要的座標了。 向量公式: AB = AC - BC

不過,這裏 mask-position 的座標還須要處理一下。咱們定義的 mask 是一張 160x160 的圓形漸變,而 mask-position 和 background-position 同樣,定義的是蒙層左上角 (0,0) 的位置實際須要和容器的哪一個座標對齊。所以咱們須要把計算獲得的座標再減去 (80, 80) 才能讓漸變中心和鼠標的座標保持一致。

var borderLayer = document.querySelector(".border-layer");

document.querySelector(".calendar").addEventListener("mousemove", function(ev){
  var x = ev.pageX;
  var y = ev.pageY;
  var bounding = borderLayer.getBoundingClientRect();
  
  borderLayer.style.webkitMaskPosition = `${x - bounding.x - 80}px ${y -bounding.y - 80}px`;
});
複製代碼

最終效果:codepen.io/liuxiaole-t…

後記

把 border 分層而後應用 mask 的方案只能是在特定場合下有效,分離另外一個層增長了不少維護成本。在查閱 MDN 資料的時候,偶然發現竟然有個貨叫 mask-border ,貌似是做用於 border 的 mask,目前尚未瀏覽器實現。

相關文章
相關標籤/搜索