CSS遮罩層:hover狀態丟失及解決方案
CSS遮罩層,顧名思義就是在div上,再“鋪”一層半透明的div。在hover時,亦可進一步改變該遮罩層的色彩和透明度。我們可以通過css定位和背景色實現。
CSS遮罩層實現及hover狀態丟失問題
CSS代碼:
.block {
position: relative;
top: 100px;
left: 100px;
display: inline-block;
width: 300px;
border-radius: 4px;
border:1px solid ;
}
.block__overlay {
position: absolute;
top:0;
left:0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .3);
}
.block:hover .block__overlay {
background-color: rgba(100, 200, 0, .5);
}
Html代碼:
<div class="block">
<p>
在Mouse hover時,如果快速點擊鼠標,可能會丟失mouse hover的效果。這在windows上的瀏覽器經常出現,造成'閃爍'。雖然在macbook上出現的時候很少。
</p>
<p>
解決方案:點擊鼠標時,添加isActive 樣式,強制顯示'hover'里的樣式。等mouse out時,去掉isActive class。
</p>
<div class="block__overlay">
</div>
</div>
普通狀態下的效果:
鼠標Hover時的效果圖:
問題是,在鼠標hover的時候多次快速點擊鼠標,會導致hover狀態失效。這個問題在windows的瀏覽器(包括windows版本的Chrome, FireFox)時常發生,盡管在macOs的各種瀏覽器挺少發生。
Hover狀態丟失的簡單解決方案
基本思路是,點擊鼠標時給div添加isActive class,強制它顯示Hover里的樣式。在鼠標不斷點擊以致于丟失hover時,也會因為添加了isActive class而照樣顯示hover里的樣式。
/*.isActive 擁有:hover相同的樣式*/
.block:hover .block__overlay,
.block.isActive .block__overlay {
background-color: rgba(100, 200, 0, .5);
}
JS文件:
var block = document.getElementsByClassName("block")[0];
block.addEventListener('mouseout', function (evt) {
// mouse hover時,不斷:ideograph_advantage:?快速點擊鼠標,可能會觸發mouseout事件,盡管并不是真正將鼠標move out了。
// 這里通過offsetX,offsetY來判斷鼠標的位置,是否真正還在div內
if (evt.offsetX <= 0 || evt.offsetY <= 0 || evt.offsetX >= block.offsetWidth || evt.offsetY >= block.offsetHeight) {
console.log('Really moved out');
if (this.classList.contains('isActive')) {
this.classList.remove('isActive');
}
}
}, false);
block.addEventListener('click', function (evt) {
if (!this.classList.contains('isActive')) {
this.classList.add('isActive');
}
}, false);
Hover狀態丟失的通用解決方案
若div里有多個定位元素,鼠標在子元素內部向上移動時,雖然鼠標可能依舊在div內部,但是evt.offsetY可能是負數。依照上述簡單方案判斷結果是,鼠標在div外部,就不對了。為此我們需要一種通用的方案。
以下圖效果舉例。我們在div里添加一個紅色:o:?和對勾
CSS代碼:
.block {
position: relative;
top: 100px;
left: 100px;
display: inline-block;
width: 300px;
border: 1px solid;
border-radius: 4px;
}
.block__overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .3);
}
.block:hover .block__overlay,
.block.isActive .block__overlay {
background-color: rgba(100, 200, 0, .5);
}
.block__circle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
border: 8px solid red;
border-radius: 50%;
}
.block__circle::after {
content: '';
position: absolute;
top: 2px;
left: 9px;
width: 15px;
height: 25px;
border: 4px solid #eef;
border-top: none;
border-left: none;
-webkit-transform: rotate(30deg);
-moz-transform: rotate(30deg);
-ms-transform: rotate(30deg);
-o-transform: rotate(30deg);
transform: rotate(30deg);
}
HTML代碼:可以看到添加了block__circle.
<div class="block">
<p>
在Mouse hover時,如果快速點擊鼠標,可能會丟失mouse hover的效果。這在windows上的瀏覽器經常出現,造成'閃爍'。雖然在macbook上出現的時候很少。
</p>
<p>
解決方案:點擊鼠標時,添加isActive 樣式,強制顯示'hover'里的樣式。等mouse out時,去掉isActive class。
</p>
<div class="block__overlay">
</div>
<div class="block__circle">
</div>
</div>
在鼠標從紅色圓圈向上移動到圓圈外部 但仍在div內時,offsetY是小于0的。 如果依舊應用簡單方案里的js,就會錯誤地得出鼠標在div外的結論。
為此我們使用toElement屬性,它表示mouse移動到哪個元素。如果該元素是div的子孫元素,我們就認為鼠標還在div內。FireFox的event沒有toElement屬性,我們用getToElement函數解決。
function getToElement(evt) {
var node;
if (evt.type == 'mouseout') {
node = evt.relatedTarget;
} else if (evt.type == 'mouseover') {
node = evt.target;
}
if (!node) {
return;
}
while (node.nodeType != 1) {
node = node.parentNode;
}
return node;
}
HTMLElement.prototype.isChildOf = function (elem) {
if (elem && elem.children) {
for (var i = 0; i < elem.childElementCount; i++) {
var child = elem.children[i];
if (child == this) {
return true;
} else if (child.childElementCount > 0) {
return this.isChildOf(child);
}
}
}
return false;
}
var block = document.getElementsByClassName("block")[0];
block.addEventListener('mouseout', function (evt) {
var toElement = evt.toElement || getToElement(evt);
if (toElement == this || toElement.isChildOf(this)) {
console.log('Does NOT really move out');
} else {
console.log('Really moved out');
if (this.classList.contains('isActive')) {
this.classList.remove('isActive');
}
}
/***
* The below code: the old way no long works correctly, because offsetX, offsetY rely on fromElement.
* When mouse move up direction out of 'circle', the OffsetY could be negative, but mouse
* is still inside the outermost div.
*/
/*
if (evt.offsetX <= 0 || evt.offsetY <= 0 || evt.offsetX >= block.offsetWidth || evt.offsetY >= block.offsetHeight) {
console.log('OLD way: Really moved out');
if (this.classList.contains('isActive')) {
this.classList.remove('isActive');
}
} else {
console.log('OLD way: Doest NOT move out');
}*/
}, false);
block.addEventListener('click', function (evt) {
if (!this.classList.contains('isActive')) {
this.classList.add('isActive');
}
}, false);
控制臺查看鼠標點擊div后的class:
鼠標移走之后,div的class:
總結
本文介紹了CSS遮罩的簡單實現,以及在鼠標點擊div時如何保持遮罩層的hover 狀態。具體代碼可查看 https://github.com/JackieGe/a...
來自:https://segmentfault.com/a/1190000010748472