Forward mouse event
by mnk
HTML
<p>We're buttons. Hover over the dummy to unleash its power.</p>
<div class="btn">
button
</div>
<div class="dummy">
dummy
</div>
CSS
body {
display: flex;
flex-direction: column;
align-items: center;
}
.btn, .dummy {
display: flex;
justify-content: center;
align-items: center;
border-radius: 30px;
width: 140px;
height: 76px;
margin-bottom: 1rem;
border: 4px solid transparent;
cursor: pointer;
-webkit-transition: all .5s ease-in-out;
-moz-transition: all .5s ease-in-out;
-ms-transition: all .5s ease-in-out;
-o-transition: all .5s ease-in-out;
transition: all .5s ease-in-out;
}
.btn {
color: blueviolet;
border-color:blueviolet;
}
.btn:hover {
background-color: violet;
}
.dummy {
background-color: #f0f0f0;
}
.dummy:hover {
background-color: #aaaaaa;
}
JavaScript
const btn = document.querySelector('.btn')
const dummy = document.querySelector('.dummy')
function collectHoverRules() {
const rules = [];
for (const sheet of document.styleSheets) {
try {
for (const r of sheet.cssRules) {
if (r.selectorText && r.selectorText.includes(':hover')) rules.push(r);
}
} catch (err) {
// ignore cross-origin stylesheets
}
}
return rules;
}
function applyHoverStylesFromRules(target, hoverRules) {
// save inline style so we can restore later
if (target.__hover_savedStyle === undefined) {
target.__hover_savedStyle = target.getAttribute('style') || '';
}
let addedCss = '';
for (const rule of hoverRules) {
// a rule may have multiple selectors comma-separated
const selectors = rule.selectorText.split(',');
for (let sel of selectors) {
sel = sel.trim();
if (!sel.includes(':hover')) continue;
const baseSel = sel.replace(/:hover/g, '').trim();
// check if target would match the selector without :hover
try {
if (baseSel && target.matches(baseSel)) {
addedCss += rule.style.cssText + ';';
}
} catch (e) {
// some selectors may be invalid after stripping :hover; ignore them
}
}
}
if (addedCss) {
target.style.cssText += ';' + addedCss;
target.__hover_applied = true;
}
}
function restoreHoverStyles(target) {
if (target.__hover_savedStyle !== undefined) {
target.setAttribute('style', target.__hover_savedStyle);
delete target.__hover_savedStyle;
delete target.__hover_applied;
}
}
// usage:
const hoverRules = collectHoverRules();
dummy.addEventListener('mouseenter', () => applyHoverStylesFromRules(btn, hoverRules));
dummy.addEventListener('mouseleave', () => restoreHoverStyles(btn));
dummy.addEventListener('click', function(e) {
console.log('dummy clicked')
btn.click()
})
btn.addEventListener('click',...