4

I have DOM elements with :active CSS styling. If a user makes a click, but never releases the click, I want to be able to cancel the :active styling through Javascript.

I have tried doing document.activeElement.blur() but that doesn't work when the user does not release the click. (See fiddle here.)

How can I force blur an element if the user doesn't release their click?

Randomblue
  • 112,777
  • 145
  • 353
  • 547
  • 1
    Can you give an explanation to why you want to cancel out this behavior? – Mouser Mar 03 '15 at 19:21
  • @Mouser: Sure. I'm building an iOS app which has a web view, and I want to cancel the `:active` state when dragging. See [here](http://stackoverflow.com/questions/28839517/stop-user-interactions-on-uiwebview) for a full write-up of the problem. – Randomblue Mar 03 '15 at 19:32
  • 1
    Seems to be pretty hard core low level to me, almost not cancelable. I'm not a quitter myself, but I think you need to rethink how you set an element "active" state so you can control it yourself. I'm trying some ugly code on the Fiddle and it still wins with a flawless victory. – Mouser Mar 03 '15 at 19:45
  • Yes, seems very low level. I would be pretty bummed if I had to rewrite all my `:active` styling, especially the default browser styling. I'll add a 500 point bounty if a solution doesn't turn up. – Randomblue Mar 03 '15 at 19:51
  • 1
    Not going to post as an answer but this is a difference approach that could save you some time rewriting: http://jsfiddle.net/ds8wwwL6/2/ – Mouser Mar 03 '15 at 20:04

3 Answers3

3

@bobdye's example doesn't work because <div> elements aren't "focusable" by default.

You can force this behaviour by assigning a tabindex property to the div, here is a fiddle.

HTML

<div class="defocus">.::.:.:.::.</div>
<div class="defocus">:..:.:.:..:</div>
<div class="defocus">.::.:.:.::.</div>

You add the class="defocus" attribute to any element that needs to blur after x seconds.

CSS (relevant)

div:active {
    color:lightcoral;
}

JavaScript

(function () {
    window.addEventListener("load", function () {
        var seconds = 0.15 * 1000;
        var defocused = document.getElementsByClassName("defocus");
        for (var i = 0, l = defocused.length; i < l; i++) {
            var el = defocused[i];
            el.style.outline = 0; //optional
            el.setAttribute("tabindex", -1);
            el.addEventListener("mousedown", blur);
        }

        function blur(e) {
            var el = e.target;
            setTimeout(function (el) {
                el.blur();
            }, seconds, el);
        }
    });
})();
  • First we wrap this function in a seaf just as a commodity (it will prevent the blur function and variables from being accessible).
  • Then we get all the elements with a defocus class.
  • Then we iterate over them.
    • First we eliminate the focus outline some browsers use because it looks ugly in a div, but it's up to you.
    • Then we set a tabindex="-1". Using -1 as an index prevents it from acting as a tab break point but allows it to recieve focus and blur events.
    • Finally we add the blur() function to the mousedown event which will defocus de element after x seconds.
  • Then we define the blur() function which will take care of defocusing the element with a setTimeout().

That's it, hope it helps!

Note: I don't particularly care for the bounty, keep your rep!

Note: Thanks to @Adam for pointing out that seaf's variables need the var prefix to prevent them from being global.

Community
  • 1
  • 1
undefined
  • 3,949
  • 4
  • 26
  • 38
0

This Fiddle a simple example of canceling the active state if the user holds the mouse down for more than 500ms.

It uses a link:

<a id="testlink" href="#">Click this</a>

styled to be red if active, and this Javascript:

var lnk = document.getElementById('testlink');
var mousedown = false;
var timerId = null;

lnk.addEventListener('mousedown', function(e) {
    mousedown = true;
    timerId = window.setTimeout(function() {
        if (mousedown) {
            lnk.blur();
        }
    }, 500);
});
lnk.addEventListener('click', function(e) {
    mousedown = false;
    window.clearTimeout(timerId);
});

Obviously not customized for your particular case, but a "proof of concept".

0

to be added to other answers, you may use a transition (delayed or not):http://codepen.io/anon/pen/LEXZGB

*:active {
    background: red;
    filter:blur(5px);
    transition: filter 3s 1s;
}
<script src='http://s.codepen.io/assets/libs/prefixfree.min.js'></script>
see me blured if you click too long.
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129