I want to change the position of my label when the checkbox is checked. This works fine if I don't transition the top offset property of my label. However, if I add a transition to this value (see the commented code), click on the label and don't move the cursor of my mouse the label seems that is still on hover state. That means, even though I don't hover on it, the cursor is a pointer and the background-color green (hover state of label).
If you see the demo, you'll understand what I mean.
My HTML code is the following:
<section>
<input type="checkbox" id="checkbox_id">
<label for="checkbox_id">Click me</label>
<div>
This is the first link
This is the second link
</div>
</section>
My CSS:
* {
margin: 0;
}
section {
position: relative;
padding: 20px;
background: yellow;
}
input[type="checkbox"] {
display: none;
}
label, a {
height: 30px;
padding: 10px 0;
margin: 10px;
}
label {
display: block;
background: tomato;
cursor: pointer;
width: 100%;
position: absolute;
top: 0;
/*transition: top .3s ease;*/
}
label:hover {
background: green;
}
input[type="checkbox"]:checked + label {
top: 100%;
}
a {
display: block;
background: tomato;
}
a:first-child {
margin-top: 50px;
}
Any idea why that's happening?
So, a little bit of jQuery might help us out here. Take a look at this jsFiddle.
CSS change:
.label--hovered { background: green; }
instead of:
label:hover { background: green; }
i.e. converted it to a class.
JavaScript:
$(document).ready(function(){
$('label').hover(function(){
$(this).removeAttr('style').addClass('label--hovered');
}, function(){
$(this).css('cursor', 'default').removeClass('label--hovered');
}).click(function(){
$(this).trigger('mouseleave');
});
});
Does this help?
You are using the syntax for the transition property but on transform. Additionally, transform doesn't take a top value. It takes scale, rotation, skew etc. You probably want this:
transition: top .3s ease;
Also don't forget to add vendor prefixes. (ie. webkit).
Related
First off I would like to stay that I am new to HTML and CSS, so pardon me if the answer is obvious. I am completely confused as to what is going on right now with my CSS code. I designed a login page with an label text moving up a bit and changing color when the user clicks on the input element. Everything worked perfectly as intended. Now I am making a signup form using the same animations as the login page for consistency. However, for some strange reason, although I am using the same code (with the only difference being position type [login used absolute and signup uses relative], and more input elements), the movement transition doesn't work at all. The text still changes color, and the label element moves up immediately without the transition animation. Any ideas as to why this is occurring would be greatly appreciated.
If it helps, I took the idea from a youtube video: https://www.youtube.com/watch?v=eeHqZeJ9Vqc
All the input elements are following this layout:
.center-card {
margin: 3vh auto 0 auto;
width: 30%;
min-width: 30%;
height: 85vh;
background: white;
border-radius: 10px;
}
.form-wrap {
margin: 0 auto;
width: 90%;
min-width: 90%;
}
.form-wrap form {
width: 100%;
}
.form-wrap label {
font-size: 16px;
}
.signup-inputs {
border-bottom: 2px solid #adadad;
}
.signup-inputs input,
.signup-inputs select {
width: 100%;
padding: 0 5px;
font-size: 16px;
border: none;
background: none;
outline: none;
position: relative;
top: 2.3vh;
}
.signup-inputs label {
position: relative;
bottom: 1vh;
left: 0.5vh;
color: #adadad;
pointer-events: none;
/*transform: translateY(-50%);*/
-webkit-transition: 0.5s;
-moz-transition: 0.5s;
-o-transition: 0.5s;
transition: 0.5s;
}
.inline-spacing {
width: 45%;
}
/* Container wrap for (decision maker and number of employees) and (email and phone number)*/
.decisionMaker-Employees,
.email-phone {
display: flex;
justify-content: space-between;
}
.password-margin {
margin-bottom: 3vh;
}
.signup-inputs span::before {
content: '';
width: 0%;
height: 0.3vh;
background: #2691d9;
position: relative;
top: 3.8vh;
display: flex;
transition: 0.5s;
-webkit-transition: 0.5s;
-moz-transition: 0.5s;
-o-transition: 0.5s;
}
.signup-inputs input:focus~label,
.signup-inputs input:valid~label,
.signup-inputs select:focus~label,
.signup-inputs select:valid~label {
top: -4vh;
color: #2691d9;
}
.signup-inputs input:focus~span::before,
.signup-inputs input:valid~span::before,
.signup-inputs select:focus~span::before,
.signup-inputs select:valid~span::before {
width: 100%;
}
<div class="center-card">
<h1>Create an Account</h1>
<div class="form-wrap">
<form method="post">
<!-- Signup Name -->
<div class="signup-inputs">
<input type="text" id="name" name="name" required>
<span></span>
<label for="name">Name</label>
</div>
Your signup is probably not working due to the fact that you are using position: relative;
This type of positioning is probably the most confusing and misused. What it really means is “relative to itself”. If you set position: relative; on an element but no other positioning attributes (top, left, bottom or right), it will have no effect on it’s positioning at all, it will be exactly as it would be if you left it as position: static; But if you do give it some other positioning attribute, say, top: 10px;, it will shift its position 10 pixels down from where it would normally be. I’m sure you can imagine, the ability to shift an element around based on its regular position is pretty useful. I find myself using this to line up form elements many times that have a tendency to not want to line up how I want them to.
There are two other things that happen when you set position: relative; on an element that you should be aware of. One is that it introduces the ability to use z-index on that element, which doesn’t work with statically positioned elements. Even if you don’t set a z-index value, this element will now appear on top of any other statically positioned element. You can’t fight it by setting a higher z-index value on a statically positioned element.
The other thing that happens is it limits the scope of absolutely positioned child elements. Any element that is a child of the relatively positioned element can be absolutely positioned within that block. This brings up some powerful opportunities which I talk about here.
Therefore, maybe try using the same position: absolute; on your signup as you did on your login.
I have some checkboxes in a grid and want to use vanilla-css and html to make a custom checkbox. That works fine. The problem is the remaining box of the original checkbox, that stays in my grid and makes it behave in strange ways as it takes a cell. Even when I make it transparent or deactivate it, as it is often suggested.
In the original example they moved it out of the screen area, but I can make it escape the grid.
I think this is the part where it fails to behave like I want to:
[type="checkbox"]:not(:checked),
[type="checkbox"]:checked {
position: absolute;
left: -9999px;
}
Here is a minimal example: https://jsfiddle.net/3mzsLj1v/14/
Here is the example I used: https://css-tricks.com/the-checkbox-hack/
Here is the real code I work on: https://codepen.io/vaeng/pen/XWXKoMb
Thanks for your help. I am sure this is very common, but being a beginner, I might not use css in the correct way?
In both your "minimal" and "real code" examples, your "New Checkboxes" comments are not properly opened.
In minimal example:
Line 23: *New Checkboxes*/ s/b /*New Checkboxes*/
In real code example:
Line 123: * New Checkboxes and radio buttons*/ s/b /* New Checkboxes and radio buttons*/
If you fix these lines, your code should work as intended.
Also, I noticed in line 102 that you put // before visibility: hidden;. If you want to comment this line, this syntax is not valid in CSS.
You see, your label and input element are on the same level, and even with position: absolute; your input still a part of the grid. Replaced your input inside the label, added span element and rewrited CSS.
Although in your code was
* New Checkboxes*/
/* Base for label styling */
[type="checkbox"]:not(:checked),
[type="checkbox"]:checked {
position: absolute;
left: -9999px;
}
The first comment was closed incorrect, so next statement didn't work.
.body {
height: 100%;
}
.outer-box {
display: grid;
margin: auto;
background-color: green;
width: 300px;
align-self: center;
grid-gap: 10px;
}
.inner-box {
display: grid;
width: 80%;
background-color: red;
align-self: center;
margin: 5px 5px 5px 5px;
}
/* New Checkboxes*/
/* Base for label styling */
[type="checkbox"] {
position: absolute;
left: -9999px;
}
[type="checkbox"]:not(:checked)+span,
[type="checkbox"]:checked+span {
position: relative;
padding-left: 1.95em;
cursor: pointer;
}
/* checkbox aspect */
[type="checkbox"]:not(:checked)+span:before,
[type="checkbox"]:checked+span:before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 1em;
height: 1em;
border: 1px solid grey;
background: transparent;
}
/* checked mark aspect */
[type="checkbox"]:not(:checked)+span:after,
[type="checkbox"]:checked+span:after {
content: '\2713\0020';
position: absolute;
top: .05em;
left: .2em;
font-size: 1.3em;
line-height: 0.8;
color: whitesmoke;
transition: all .2s;
font-family: Arial;
}
/* checked mark aspect changes */
[type="checkbox"]:not(:checked)+span:after {
opacity: 0;
transform: scale(0);
}
[type="checkbox"]:checked+span:after {
opacity: 1;
transform: scale(1);
}
<div class="outer-box">
<div class="inner-box">
Some text
</div>
<div class="inner-box">
<label for="box1" class="container">
<input type="checkbox" id="box1"><span>Selectbox1</span>
</label>
<label for="box2" class="container">
<input type="checkbox" id="box2"><span>Selectbox2</span>
</label>
</div>
</div>
And please, don't use display: grid; for every element. It's very specific setting only for cases, when you really need you use grid.
I have a problem with my custom checkbox.
If you click on a checkbox element, move the mouse cursor and then release the click inside the checkbox area, the checkbox is checked.
However, if you do the same on a custom checkbox (here, a div inside a label), the checkbox isn't checked.
It's a problem because if you want to quickly check a checkbox, you may move the mouse after pressing the button of the mouse and before releasing it, thus not toggling the checkbox.
The user is obligated to click without moving the mouse.
I know I can use JS to emulate a checkbox with a div, but I want the HTML to be semantically correct, so: Is it possible to fix it without js?
Here's the code :
/* 1. Hide the checkbox */
.hidden {
/* https://zellwk.com/blog/hide-content-accessibly/ */
border: 0;
clip: rect(0, 0, 0, 0);
height: auto;
margin: 0;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
white-space: nowrap;
}
/* 2. Use a label to retrieve the click event */
label {
/* not used directly to prevent the bug in firefox https://bugzilla.mozilla.org/show_bug.cgi?id=608180 */
pointer-events: none;
display: inline-flex;
}
label > input {
/*usefull for testing only*/
pointer-events : all;
}
label > .customCheckbox {
cursor: pointer;
display: inline-flex;
justify-content: center;
align-items: center;
position: relative;
--size:200px;
width: var(--size);
height: var(--size);
font-size: calc(var(--size)/2);
pointer-events: all;
}
label > .customCheckbox::selection{
/* prevent highliting the text within the custom checkbox */
background: none;
}
label > .customCheckbox:after {
z-index: -1;
content: "✔";
display: inline-flex;
justify-content: center;
align-items: center;
position: absolute;
width: 100%;
height: 100%;
box-sizing: border-box;
border-radius: calc(var(--size)/4);
border: solid black calc(var(--size)/10);
}
label > input:not(:checked) + div.customCheckbox:after {
background:#0000;
content: "\a0";
}
<input type="checkbox"/>
<label >
<input type="checkbox" class="hidden"/>
<div class="customCheckbox"></div>
</label >
I need the checkbox to be inside the label because I can't use the "for" attribute.
Thanks a lot for your help!
EDIT: for those wondering, here's the js solution (not ideal but since I can't do it in CSS, it's better than nothing) :
let checkboxes = document.getElementsByClassName("customCheckbox");
for(let i=0; i<checkboxes.length; i++){
checkboxes[i].addEventListener('mouseover', (e)=>{handleMouseOverCheckbox(e)})
checkboxes[i].addEventListener('mousedown', (e)=>{handleMouseOverCheckbox(e)})
}
function handleMouseOverCheckbox(e) {
e.srcElement.previousElementSibling.disabled = "true";
if (e.buttons == 1) {
e.srcElement.previousElementSibling.checked= !e.srcElement.previousElementSibling.checked;
}}
EDIT 2 : Here's the best solution I could come up with, thanks to
#zer00ne
codepen.io/DesignThinkerer/pen/bGVBLjM
A checkbox within a label is no problem. The problem arises when that checkbox is altered for the sake of accessibility instead of complete removal using display: none. When an interactive element like an input or button exists in the DOM, it will still be a factor no matter how its hidden unless display: none is applied.
In the Original Post the checkbox is almost impossible to click due to its 0px height and 1px width and yet when the div is clicked, the checkbox is clicked... sometimes not. Normally if the label was able to detect a click, that click would trigger a click event to the nested checkbox as well. In the OP code that's not happening because the label has pointer-events: none.
So the div is getting clicked and by some magical miracle this gains features that would not normally be attributed to it? Divs are not interactive they cannot affect elements that are not nested within themselves (i.e. like the checkbox that sits before the div). Nope, the div is useless, its the checkbox itself that's getting clicked due to the fact it is the only element within the inert label that gains focus by default. Gaining focus on an input doesn't necessarily guarantee a click event -- matter of fact a focus event selects an element and a click event sets an element as active. So what happens when a user double-clicks or moves the mouse quickly before the next click clears a label? Undesirable behavior as described in OP.
In the following demo, the checkboxes are hidden as per OP (also set width and height to 0) and removed pointer-events: none from the label and added it to the checkboxes. In this setup the label gains focus and click events and the click event will trigger the checkbox. The checkbox having been isolated from any extra clicks due to pointer-events: none and z-index: -1 should behave as expected.
As proof of concept I have added some JavaScript to demonstrate said code stability. The two event handlers are for demonstration purposes. The JS does not facilitate, stabilize, or modify performance of the HTML/CSS behavior.
On any change event on a checkbox (via label) will trigger function changeHandler() to gather all the values of the checked checkboxes and display them in an output.
If there's a checkmark in a box and there's a value displayed that corresponds to said checked checkbox, then it successfully passes as valid behavior.
Clicking button.show will trigger function clickHandler() to toggle the .reveal class to each checkbox.
While clicking rapidly observe that the revealed checkboxes are checked and its corresponding custom label is checked as well. Also notice that the value should also be displayed as well.
BTW
"....target doesn't work in IE IIRC"
event.target is the standard property to use in every modern browser. event.srcElement is a deprecated property used by IE which is almost entirely unsupported.
pointer-events: all assigned to input and .customCheckbox
The value all applies to SVG only. Only the values of none and auto are relevant to HTML. auto is default.
Demo
I cannot reproduce the described behavior except in the code provided in OP. If you can reproduce that behavior on my demo, please record a short video of it and post that and the machine/device, OS, and browsers (I will assume everything is reasonably up to date).
const main = document.forms.main;
main.onchange = checkHandler;
function checkHandler(e) {
const fc = this.elements;
const chx = [...fc.hidden];
const ui = e.target;
if (ui.matches('.hidden')) {
let text = chx.flatMap(c => c.checked ? [c.value] : []);
fc.view.value = '';
fc.view.value = text.join(', ');
}
}
main.onclick = clickHandler
function clickHandler(e) {
const fc = this.elements;
const chx = [...fc.hidden];
const ui = e.target;
if (ui.matches('button.show')) {
chx.forEach(c => c.classList.toggle('reveal'));
}
}
:root,
body {
--size: 10rem;
font: 400 small-caps 2vw/1.5 Times;
width: 100%;
height: 100%;
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
font: inherit;
}
.display {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
width: max-content;
max-height: min-content;
margin: 10px;
border: calc(var(--size) / 20) solid #000;
border-radius: 24px;
}
.view {
display: inline-block;
min-width: 35ch;
font-size: 1.5rem;
height: 1.5rem;
line-height: 1;
}
.show {
display: inline-block;
width: 12ch;
padding: 1px 3px;
margin: 4px;
border: 2px solid #000;
border-radius: 8px;
background: none;
text-align: center;
font-size: 1.25rem;
cursor: pointer;
}
.mask {
position: relative;
z-index: 2;
display: block;
width: var(--size);
height: var(--size);
padding: 0;
margin: 0 5px;
border: solid black calc(var(--size) / 10);
border-radius: calc(var(--size) / 4);
font-size: calc(var(--size) * 0.8);
background: none;
cursor: pointer;
}
.icon {
position: absolute;
z-index: 1;
top: -1.5rem;
right: 1rem;
display: inline-block;
margin: 0;
padding: 0;
border: 0;
}
.hidden {
position: relative;
z-index: -1;
display: inline-block;
width: 0;
height: 0;
margin: 0;
padding: 0;
border: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
pointer-events: none;
opacity: 0;
}
.reveal {
z-index: 0;
top: -24px;
left: 4px;
width: 1px;
height: 1px;
opacity: 1;
}
.icon::after {
content: attr(data-blank);
}
.hidden:checked+.icon::after {
content: attr(data-check);
}
<!DOCTYPE html>
<html>
<head lang='en'>
<meta charset='utf-8'>
<style></style>
</head>
<body>
<form name='main'>
<fieldset name='display' class='display'>
<output name='view' class='view'></output>
<button name='show' class='show' type='button'>Show</button>
</fieldset>
<fieldset name='display' class='display'>
<label name='mask' class='mask'>
<input name='hidden' class="hidden" type="checkbox" value='Check I'>
<fieldset name='icon' class='icon' data-check='✔' data-blank=' '></fieldset>
</label>
<label name='mask' class='mask'>
<input name='hidden' class="hidden" type="checkbox" value='Check II'>
<fieldset name='icon' class='icon' data-check='✔' data-blank=' '></fieldset>
</label>
<label name='mask' class='mask'>
<input name='hidden' class="hidden" type="checkbox" value='Check III'>
<fieldset name='icon' class='icon' data-check='✔' data-blank=' '></fieldset>
</label>
<label name='mask' class='mask'>
<input name='hidden' class="hidden" type="checkbox" value='Check IV'>
<fieldset name='icon' class='icon' data-check='✔' data-blank=' '></fieldset>
</label>
</fieldset>
</form>
<script></script>
</body>
</html>
I have an FAQ section. Each question is preceded by a green triangle as shown below:
Clicking on the green triangle turns the triangle 90 degrees. However, it does not rotate around the center of the triangle. Instead it rotates around the right corner. See how its shifted to the right because of this.
I have tried tried tansform-origin but it seems to move the center too far even if I use %.
Here is the HTML:
<div class="question-container">
<div class="question">
<p><span class="triangle">▸</span> Why choose ProveWord?</p>
</div><!--question -->
<div class="answer">
<p>ProvenWord does all that is necessary to make your work its best. That is why we always perform proofreading andediting on your document.</p>
</div><!-- answer -->
</div><!-- question-container -->
Here is the CSS:
.question-container {
width: 450px;
margin: 0 auto;
}
.question {
height: 36px;
background-color: #efefef;
border-radius: 8px;
text-align: left;
margin-bottom: 10px;
}
.question p {
line-height: 34px;
padding-bottom: 10px;
}
.triangle {
font-size: 18px;
color: #608b32;
padding: 0 8px 0 12px;
cursor: pointer;
display: inline-block;
transition: transform 0.5s ease-in-out;
}
.triangle.rotate {
color: red;
transform: rotate(90deg);
}
.answer {
width: 85%;
display: none;
margin: 0 auto;
}
.answer p {
line-height: 130%;
text-align: justify;
padding-bottom: 20px;
}
Here is the JS:
$('.triangle').on('click', function(){
var self = $(this).closest('.question-container').find('.answer');
vis = $('.answer').not(self).filter(':visible');
if (vis.length) {
vis.slideUp(function() {
vis.closest('.question-container').find('.triangle').toggleClass('rotate');
self.slideToggle('slow');
});
}else{
self.slideToggle('slow');
}
$(this).toggleClass('rotate');
});
I'm a NOOB with the CSS and rotation. Any help appreciated.
Here is how I would have done it, with a little JavaScript I made a Fiddle for you
I created a button over your<div class='question'> JavaScript gets the event on click and adds the class rotate to your triangle element. Clicking again on it removes the class and it becomes green again.
HTML :
<a href="#" id="button">
<div class="question">
<p><span class="triangle">▸</span> Why choose ProveWord?</p>
</div>
</a><!--question -->
CSS :
.triangle {
font-size: 18px;
color: #608b32;
padding: 0 8px 0 12px;
display: inline-block;
-webkit-transition: all 0.5s ease;
transition: all 0.5s ease;
}
.triangle.rotate {
color: red;
-webkit-transform:rotate(90deg);
-ms-transform:rotate(90deg);
}
JavaScript :
$("#button").click(function() {
$(".triangle").toggleClass('rotate');
});
The answer of #Theo is fine, but you should know that you can achieve a similar result in (at least) two other ways:
Without JavaScript: (you will have to reskin the checkbox into the arrow you desire)
input ~ p {
display: none;
}
input:checked ~ p {
display: block;
}
<label>wesh</label><input type="checkbox"/>
<p>
dfsdfsf
dfsdfsf
dfsdfsf
dfsdfsf
dfsdfsf
dfsdfsf
</p>
The general sibling combinator (~) separates two selectors and matches the second element only if it follows the first element (though not necessarily immediately), and both are children of the same parent element.
More on MSDN
Or even better,
Without JavaScript nor CSS:
<details>
<summary>wesh</summary>
<p>
dfsdfsf
dfsdfsf
dfsdfsf
dfsdfsf
dfsdfsf
dfsdfsf
</p>
</details>
The HTML Details Element () is used to create a disclosure widget in which information is visible only when the widget is toggled into an "open" state. A summary or label can be provided using the element.
More on msdn
Demo on jsfiddle
Just been playing about with pointer-events property in CSS.
I have a div that I want to be invisible to all mouse events, except for :hover.
So all click commands go through the div to the one below it, but the div can report whether the mouse is above it or not still.
Can anyone tell me if this can be done?
HTML:
<div class="layer" style="z-index:20; pointer-events:none;">Top layer</div>
<div class="layer" style="z-index:10;">Bottom layer</div>
CSS:
.layer {
position:absolute;
top:0px;
left:0px;
height:400px;
width:400px;
}
Hover only. It is very easy. No JS... Prevent link default action too.
a:hover {
color: red;
}
a:active {
pointer-events: none;
}
Link here
Edit:
supported in IE 11 and above
http://caniuse.com/#search=pointer-events
"Stealing" Xanco's answer but without that ugly, ugly jQuery.
Snippet: Notice DIVs are in reverse order
.layer {
position: absolute;
top: 0px;
left: 0px;
height: 400px;
width: 400px;
}
#bottomlayer {
z-index: 10
}
#toplayer {
z-index: 20;
pointer-events: none;
background-color: white;
display: none
}
#bottomlayer:hover~#toplayer {
display: block
}
<div id="bottomlayer" class="layer">Bottom layer</div>
<div id="toplayer" class="layer">Top layer</div>
I don't think it's possible to achieve your aims in CSS alone. However, as other contributors have mentioned, it's easy enough to do in JQuery. Here's how I've done it:
HTML
<div
id="toplayer"
class="layer"
style="
z-index: 20;
pointer-events: none;
background-color: white;
display: none;
"
>
Top layer
</div>
<div id="bottomlayer" class="layer" style="z-index: 10">Bottom layer</div>
CSS (unchanged)
.layer {
position:absolute;
top:0px;
left:0px;
height:400px;
width:400px;
}
JQuery
$(document).ready(function(){
$("#bottomlayer").hover(
function() {
$("#toplayer").css("display", "block");
},
function() {
$("#toplayer").css("display", "none");
}
);
});
Here's the JSFiddle: http://www.jsfiddle.net/ReZ9M
You can also detect hover on different element and apply styles to it's child, or using other css selectors like adjacent children, etc.
It depends on your case though.
On parent element hover. I did this:
.child {
pointer-events: none;
background-color: white;
}
.parent:hover > .child {
background-color: black;
}
Pure CSS solution to your request (the opacity property is there just to illustrate the need for the transitions):
.hoverOnly:hover {
pointer-events: none;
opacity: 0.1;
transition-delay: 0s;
}
.hoverOnly {
transition: ,5s all;
opacity: 0.75;
transition-delay: 2s;
}
What it does:
When the mouse enters the box, it triggers the :hover state. However, in that state, the pointer-events are disabled.
But if you do not set the transitions timers, the div will cancel the hover state when the mouse moves; the hover state will flicker while the mouse is moving inside the element. You can perceive this by using the code above with the opacity properties.
Setting a delay to the transition out of the hover state fixes it. The 2s value can be tweaked to suit your needs.
Credits to transitions tweak: patad on this answer.
Just pure css, doesn't need jquery:
div:hover {pointer-events: none}
div {pointer-events: auto}
I use the :hover pseudo-element of an equal-sized parent/container to simulate a hover over my overlay div, then set the overlay's pointer-events to none to pass through clicks to elements below.
let button = document.getElementById('woohoo-button');
button.onclick = () => console.log('woohoo!');
let overlay = document.getElementById('overlay');
overlay.onclick = () => console.log(`Better change my pointer-events property back to 'none'`);
#container {
display: flex;
align-items: center;
justify-content: center;
position: relative;
background-color: green;
width: 300px;
height: 300px;
}
#overlay {
background-color: black;
width: 100%;
height: 100%;
opacity: 0;
z-index: 1;
/* Pass through clicks */
pointer-events: none;
}
/*
Set overlay hover style based on
:hover pseudo-element of its
container
*/
#container:hover #overlay {
opacity: 0.5;
}
#woohoo-button {
position: absolute;
width: 100px;
height: 100px;
background-color: red;
}
<div id="container">
<div id="overlay"></div>
<button id="woohoo-button">
Click Me
</button>
</div>