Skip to content

Instantly share code, notes, and snippets.

@hans2103
Created August 31, 2020 06:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hans2103/5a555bd37f970c478223d59804ae0403 to your computer and use it in GitHub Desktop.
Save hans2103/5a555bd37f970c478223d59804ae0403 to your computer and use it in GitHub Desktop.
(function() {
'use strict';
var DURATION = 150;
var ringElem = null;
var movingId = 0;
var prevFocused = null;
var keyDownTime = 0;
var win = window;
var doc = document;
var docElem = doc.documentElement;
var body = doc.body;
docElem.addEventListener('keydown', function(event) {
var code = event.which;
// Show animation only upon Tab or Arrow keys press.
if (code === 9 || (code > 36 && code < 41)) {
keyDownTime = Date.now();
}
}, false);
docElem.addEventListener('focus', function(event) {
var target = event.target;
if (target.id === 'flying-focus') {
return;
}
var isFirstFocus = false;
if (!ringElem) {
isFirstFocus = true;
initialize();
}
var offset = offsetOf(target);
ringElem.style.left = offset.left + 'px';
ringElem.style.top = offset.top + 'px';
ringElem.style.width = target.offsetWidth + 'px';
ringElem.style.height = target.offsetHeight + 'px';
if (isFirstFocus || !isJustPressed()) {
return;
}
onEnd();
target.classList.add('flying-focus_target');
ringElem.classList.add('flying-focus_visible');
prevFocused = target;
movingId = setTimeout(onEnd, DURATION);
}, true);
docElem.addEventListener('blur', function() {
onEnd();
}, true);
function initialize() {
ringElem = doc.createElement('flying-focus'); // use uniq element name to decrease the chances of a conflict with website styles
ringElem.id = 'flying-focus';
ringElem.style.transitionDuration = ringElem.style.WebkitTransitionDuration = DURATION / 1000 + 's';
body.appendChild(ringElem);
}
function onEnd() {
if (!movingId) {
return;
}
clearTimeout(movingId);
movingId = 0;
ringElem.classList.remove('flying-focus_visible');
prevFocused.classList.remove('flying-focus_target');
prevFocused = null;
}
function isJustPressed() {
return Date.now() - keyDownTime < 42
}
function offsetOf(elem) {
var rect = elem.getBoundingClientRect();
var clientLeft = docElem.clientLeft || body.clientLeft;
var clientTop = docElem.clientTop || body.clientTop;
var scrollLeft = win.pageXOffset || docElem.scrollLeft || body.scrollLeft;
var scrollTop = win.pageYOffset || docElem.scrollTop || body.scrollTop;
var left = rect.left + scrollLeft - clientLeft;
var top = rect.top + scrollTop - clientTop;
return {
top: top || 0,
left: left || 0
};
}
var style = doc.createElement('style');
style.textContent = "#flying-focus {\
position: absolute;\
margin: 0;\
background: transparent;\
-webkit-transition-property: left, top, width, height;\
transition-property: left, top, width, height;\
-webkit-transition-timing-function: cubic-bezier(0,1,0,1);\
transition-timing-function: cubic-bezier(0,1,0,1);\
visibility: hidden;\
pointer-events: none;\
box-shadow: 0 0 2px 3px #78aeda, 0 0 2px #78aeda inset; border-radius: 2px;\
}\
#flying-focus.flying-focus_visible {\
visibility: visible;\
z-index: 9999;\
}\
.flying-focus_target {\
outline: none !important; /* Doesn't work in Firefox :( */\
}\
/* http://stackoverflow.com/questions/71074/how-to-remove-firefoxs-dotted-outline-on-buttons-as-well-as-links/199319 */\
.flying-focus_target::-moz-focus-inner {\
border: 0 !important;\
}\
/* Replace it with @supports rule when browsers catch up */\
@media screen and (-webkit-min-device-pixel-ratio: 0) {\
#flying-focus {\
box-shadow: none;\
outline: 5px auto -webkit-focus-ring-color;\
outline-offset: -3px;\
}\
}\
";
body.appendChild(style);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment