19

I'm wondering how to enable the clicking on a :before pseudo-element (the orange part of the div on the JSfiddle I link to below). I've read that since pseudo-elements aren't in the DOM you would need a hack for this. Unfortunately, I can't find an existing Stackoverflow Q&A that actually shows working code.

Link: http://jsfiddle.net/Vv6Eb/4/

HTML:

<div></div>

CSS:

div { position:relative; background-color:#333;
      padding:20px; margin:20px; float:left; 
}

div:before { content:""; display:block; 
    padding:5px; background-color:#f60; border:2px solid white; 
    position: absolute; top:-2px; right:-2px; border-bottom-left-radius: 10px; 
}
5
  • 2
    Perhaps you could include more information on what you want to happen? It's possible there is some other workaround to achieve the intended result. Commented Oct 2, 2012 at 14:57
  • 2
    You can't bind directly to a pseudo-element, but you can bind to the element that's creating it and clicking the pseudo-element will always trigger the event that's bound to the generating element. If you specifically must only bind to the orange part, you need to create a new element. Commented Oct 2, 2012 at 15:11
  • @JamesMontagne, all i'm interested in is being able to click on the pseudo-element like one would click on a <a> or <button>. ComputerArts suggestion works for me though is there something else you're thinking? Commented Oct 2, 2012 at 15:14
  • 1
    @timpeterson I think I may have misunderstood your intent. The question sounded as though you were trying to trigger a click on the element in javascript. I was wondering what purpose that served. Now I see that you were in fact looking to attack a click handler. Commented Oct 2, 2012 at 15:20
  • Possible duplicate of Only detect click event on pseudo-element Commented Jan 7, 2019 at 11:32

6 Answers 6

16

If you know where the circle "should" be, you can use trigonometry to see if the click is within the circle: http://jsfiddle.net/Vv6Eb/19/

$("div").click(function(e){
    var $me = $(this),
        width = $me.outerWidth(),
        height = $me.outerHeight(),
        top = $me.position().top,
        left = $me.position().left;

    var len = Math.sqrt(Math.pow(width - e.offsetX, 2) + Math.pow(e.offsetY, 2));

    if (len < 10)
        alert('ding');
});​
Sign up to request clarification or add additional context in comments.

1 Comment

don't use pow to calculate square, use *
13

A workaround for this would be to dynamically append a <span> to the item and assigning a click method to it. Like this fiddle.

var item = $('<span />');
item.click(function() { alert('click'); });
$('div').append(item);

CSS

div { position:relative; background-color:#333;
      padding:20px; margin:20px; float:left;
}

div span { content:""; display:block;
    padding:5px; background-color:#f60; border:2px solid white;
    position: absolute; top:-2px; right:-2px; border-bottom-left-radius: 10px;
}

Comments

2

I know you are trying to use :before, but for this situation, can't you just create a new div with a class to use as a hook and append it to the original div?

Something like this might work:

var newDiv = $("<div class='orangeCircle'>");
$(".parentDivToOrangeCircle").append(newDiv);

And the CSS:

.parentDivToOrangeCircle { position:relative; background-color:#333;
    padding:20px; margin:20px; float:left; 
}

.orangeCircle {
    padding:5px; background-color:#f60; border:2px solid white; 
    position: absolute; top:-2px; right:-2px; border-bottom-left-radius: 10px; 
}

1 Comment

-@Jordan, i don't need to use :before. If there is any another way I'd greatly appreciate to see what the code would look like.
1

Do simply like using jquery

  $(document).on("click", "span", function(e){
         if (e.offsetX > $(this)[0].offsetWidth) {
               alert('clicked on after');
    } 
    else
    {
    alert('clicked on main span');
    }
        
    })
div { margin: 20px; }
span:after { content: 'AFTER'; position: absolute; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div><span>ELEMENT</span></div>

Comments

0

My purpose was solved by another workaround which is just adding a child DIV. Wrapping up all child elements inside the parent into this new child DIV:

My working sample as same as the problem statement: See Fiddle

HTML:

<div class="parentDiv">
    :before
    <div class="childDiv">
        <!-- child elements -->
    </div>
</div>

**Note: Ignore the :before in the HTML, just showing to understand.

CSS:

div.parentDiv{position:relative; background-color:#333; padding:0; margin:20px; float:left; }
div.parentDiv:before { content:""; display:block; padding:5px; background-color:#f60; border:2px solid white; position: absolute; top:-2px; right:-2px; border-bottom-left-radius: 10px; cursor:pointer}

div.childDiv{padding:20px; margin:0}

jQuery:

jQuery(document).ready(function($){
    $('div.parentDiv').click(function(e){
        if( $(e.target).closest('.childDiv').length==0 ){
            //so clicked on psudo :before element!
            //do your work here ;)
            alert('Psudo :before element is clicked!');
        }
    });
});

Comments

0

There is an article about this on Medium.

Also, the CodePen

The basic idea is tracing where the pseudo-element will be. The code snippet below shows the more general case of a rectangle without a border-radius and closes the parent when the pseudo-element is clicked.

const dismissable = document.querySelectorAll(".dismissable")

dismissable.forEach((d) => {
  d.addEventListener("click", (e)=>{
    // First we get the pseudo-elements style
    const target = e.currentTarget || e.target
    const after = getComputedStyle(target, ":after")
    if (after) {
      // Then we parse out the dimensions
      const atop = Number(after.getPropertyValue("top").slice(0, -2))
      const aheight = Number(after.getPropertyValue("height").slice(0, -2))
      const aleft = Number(after.getPropertyValue("left").slice(0, -2))
      const awidth = Number(after.getPropertyValue("width").slice(0, -2))
      // And get the mouse position
      const ex = e.layerX
      const ey = e.layerY
      // Finally we do a bounds check (Is the mouse inside of the after element)
      if (ex > aleft && ex < aleft+awidth && ey > atop && ey < atop+aheight) {
        console.log("Button clicked")
        target.style.display = "none"
      }
    }
  })
})
.dismissable {
  position: relative;
  width: 300px;
  height: 300px;
  border: 1px solid black;
  border-radius: 5px;
}

.dismissable:hover::after {
  content: "x";
  font-size: 3rem;
  display: block;
  position: absolute;
  top: 10px;
  left: 10px;
  cursor: pointer;
}
<div class="dismissable"></div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.