admin管理员组

文章数量:1198811

I'm trying to write a JavaScript which will highlight an element in the DOM when the user hovers over it. This is supposed to be a cross-browser external plug-in. Ideally, i'm trying to mimic the behaviour of the browser inspector tools.

I can't say I have no success, but I am stuck with two options, both with its own pros and cons.

Approach 1

I handle the mouseover event and simply add a border to the target element. When I hover on another element, I just reset the existing highlighted elements. The code for the same is below:

function addHighlight(target) {
    target.classList.add('highlighted');
}

function removeHighlight(target) {
    target.classList.remove('highlighted');
}

window.addEventListener('mouseover',function(e) {
    addHighlight(e.target);
});

window.addEventListener('mouseout',function(e) {
    removeHighlight(e.target);
});

Working Example here

Pros with this Approach

It works absolutely fine.

Cons with this approach

As I'm adding a border to existing DOM elements, it sort of re-arranges the elements on the page, and you can observe a slight shuffling effect of the elements. Doesn't look great.

Approach 2

I wanted the highlighting to be seamless. That is, preserving the look of the page and simply overlaying a highlight mask on top of the element.

TO do this, in the mouseover event, I dynamically created a mask element, whose position is set to absolute and its co-ordinates set to the exact co-ordinates of the target element. Below is my code:

window.addEventListener('mouseover',function(e) {
    applyMask(e.target);
});

function applyMask(target) {
    if(document.getElementsByClassName('highlight-wrap').length > 0) {
        resizeMask(target);
    }else{
        createMask(target);
    }
}

function resizeMask(target) {
    var rect = target.getBoundingClientRect();
    var hObj = document.getElementsByClassName('highlight-wrap')[0];
    hObj.style.top=rect.top+"px";
    hObj.style.width=rect.width+"px";
    hObj.style.height=rect.height+"px";
    hObj.style.left=rect.left+"px";
   // hObj.style.WebkitTransition='top 0.2s';
}

function createMask(target) {
    var rect = target.getBoundingClientRect();
    var hObj = document.createElement("div");
    hObj.className = 'highlight-wrap';
    hObj.style.position='absolute';
    hObj.style.top=rect.top+"px";
    hObj.style.width=rect.width+"px";
    hObj.style.height=rect.height+"px";
    hObj.style.left=rect.left+"px";
    hObj.style.backgroundColor = '#205081';
    hObj.style.opacity='0.5';
    hObj.style.cursor='default';
    //hObj.style.WebkitTransition='top 0.2s';
    document.body.appendChild(hObj);
}

function clearMasks() {
    var hwrappersLength = document.getElementsByClassName("highlight-wrap").length;
    var hwrappers = document.getElementsByClassName("highlight-wrap");
    if(hwrappersLength > 0) {
        for(var i=0; i<hwrappersLength; i++) {
            console.log("Removing existing wrap");
            hwrappers[i].remove();
        }
    }
}

Working example here

Pros with this approach I feel this is more elegant, and doesn't disturb the page, just overlays a mask on top of elements.

Cons

When the user hovers over the top most container (div), it creates a mask for that element. After that, all the subsequent mouseover events are ignored, as they are registered on the mask, and not on the actual underlying elements. I need to figure out a way around this.

Can anyone help me better Approach 2? Or suggest another approach?

Thanks, Sriram

I'm trying to write a JavaScript which will highlight an element in the DOM when the user hovers over it. This is supposed to be a cross-browser external plug-in. Ideally, i'm trying to mimic the behaviour of the browser inspector tools.

I can't say I have no success, but I am stuck with two options, both with its own pros and cons.

Approach 1

I handle the mouseover event and simply add a border to the target element. When I hover on another element, I just reset the existing highlighted elements. The code for the same is below:

function addHighlight(target) {
    target.classList.add('highlighted');
}

function removeHighlight(target) {
    target.classList.remove('highlighted');
}

window.addEventListener('mouseover',function(e) {
    addHighlight(e.target);
});

window.addEventListener('mouseout',function(e) {
    removeHighlight(e.target);
});

Working Example here

Pros with this Approach

It works absolutely fine.

Cons with this approach

As I'm adding a border to existing DOM elements, it sort of re-arranges the elements on the page, and you can observe a slight shuffling effect of the elements. Doesn't look great.

Approach 2

I wanted the highlighting to be seamless. That is, preserving the look of the page and simply overlaying a highlight mask on top of the element.

TO do this, in the mouseover event, I dynamically created a mask element, whose position is set to absolute and its co-ordinates set to the exact co-ordinates of the target element. Below is my code:

window.addEventListener('mouseover',function(e) {
    applyMask(e.target);
});

function applyMask(target) {
    if(document.getElementsByClassName('highlight-wrap').length > 0) {
        resizeMask(target);
    }else{
        createMask(target);
    }
}

function resizeMask(target) {
    var rect = target.getBoundingClientRect();
    var hObj = document.getElementsByClassName('highlight-wrap')[0];
    hObj.style.top=rect.top+"px";
    hObj.style.width=rect.width+"px";
    hObj.style.height=rect.height+"px";
    hObj.style.left=rect.left+"px";
   // hObj.style.WebkitTransition='top 0.2s';
}

function createMask(target) {
    var rect = target.getBoundingClientRect();
    var hObj = document.createElement("div");
    hObj.className = 'highlight-wrap';
    hObj.style.position='absolute';
    hObj.style.top=rect.top+"px";
    hObj.style.width=rect.width+"px";
    hObj.style.height=rect.height+"px";
    hObj.style.left=rect.left+"px";
    hObj.style.backgroundColor = '#205081';
    hObj.style.opacity='0.5';
    hObj.style.cursor='default';
    //hObj.style.WebkitTransition='top 0.2s';
    document.body.appendChild(hObj);
}

function clearMasks() {
    var hwrappersLength = document.getElementsByClassName("highlight-wrap").length;
    var hwrappers = document.getElementsByClassName("highlight-wrap");
    if(hwrappersLength > 0) {
        for(var i=0; i<hwrappersLength; i++) {
            console.log("Removing existing wrap");
            hwrappers[i].remove();
        }
    }
}

Working example here

Pros with this approach I feel this is more elegant, and doesn't disturb the page, just overlays a mask on top of elements.

Cons

When the user hovers over the top most container (div), it creates a mask for that element. After that, all the subsequent mouseover events are ignored, as they are registered on the mask, and not on the actual underlying elements. I need to figure out a way around this.

Can anyone help me better Approach 2? Or suggest another approach?

Thanks, Sriram

Share Improve this question asked Aug 20, 2018 at 7:21 Sriram SridharanSriram Sridharan 7402 gold badges22 silver badges47 bronze badges 1
  • 1 “As I'm adding a border to existing DOM elements, it sort of re-arranges the elements on the page, and you can observe a slight shuffling effect of the elements.” - use an outline instead of a border. – C3roe Commented Aug 20, 2018 at 7:27
Add a comment  | 

6 Answers 6

Reset to default 11

You should do this in CSS and not in JS. Use the :hover selector

.your-class:hover{
    background-color: #205081;
}

@LouieAlmeda's answer is the way to go

But if you want to keep the mask div you can do : http://jsbin.com/filelavegu/1/edit?html,css,js,output

the only difference with your is that I added

hObj.style.pointerEvents='none';

at the mask creation

It makes the pointerevent pass through the div

I changed the version by @jonatjano, such as

  • it takes in account the viewport scrolling
  • it is more compact
  • it works also pasted in the developer console (beware of confounding iframes btw)

Working example here

window.addEventListener('mouseover', function (e) {
    updateMask(e.target);
});

function updateMask(target) {
    let elements = document.getElementsByClassName("highlight-wrap")
    let hObj
    if (elements.length !== 0) {
        hObj = elements[0]
    } else {
        hObj = document.createElement("div");
        hObj.className = 'highlight-wrap';
        hObj.style.position = 'absolute';
        hObj.style.backgroundColor = '#205081';
        hObj.style.opacity = '0.5';
        hObj.style.cursor = 'default';
        hObj.style.pointerEvents = 'none';
        document.body.appendChild(hObj);
    }
    let rect = target.getBoundingClientRect();
    hObj.style.left = (rect.left + window.scrollX) + "px";
    hObj.style.top = (rect.top + window.scrollY) + "px";
    hObj.style.width = rect.width + "px";
    hObj.style.height = rect.height + "px";

}

@LouieAlmeda and @jonatjano are both right, i just want to add that if you don't like the re-arranges the elements on the page, you can add a border: 1px solid transparent to elements and then on mouse-over/hover just change the border-color

You can also use:

[attribute = value]:hover {
   css declarations;
}

and use it on all divs which should have hover effect.

This approach worked for me, applying the hover rule to all * elements.

*:hover {
    background-color: #205081 !important;
}

The !important ensures overwriting backgrounds set on individual HTML nodes. Keep CSS specificity mind, that is that the browser ignores this CSS rule if a similar rule with !important is present on the hovered element.

Thanks to Louie, extending his answer.

本文标签: htmlJavaScriptHighlight an element on HoverStack Overflow