Начало } Защита } Как запретить браузеру выделять текст


 

Если Вы веб-разработчик, то у вас наверняка возникала необходимость в том, чтобы запретить пользователю выделение текста. Оговоримся, что я не имею ввиду полный запрет с целью защиты текста, а запрет на выделение всевозможных подписей, надписей и т.п. где выделение мешает работе интерфейса и пользователю (чаще всего при drag&drop, или выделении текста при двойном клике). Это в первую очередь касается веб-приложений и ни в коем случае не касается информационных сайтов. Что же мы можем сделать? До сих пор думал немногое. Но прежде чем перейти к рассмотрению нового (лично для меня) методу, рассмотрим какие возможности борьбы с выделением текста предлагают нам браузеры.
Internet Explorer

Данный браузер дает нам две возможности:

1. Для элементов устанавливаем атрибут unselectable со значением on. Но тут есть один нюанс: текст блока с таким атрибутом нельзя выделить (то есть нельзя начать выделение с данного элемента, и клик по такому элементу не будет снимать выделение с текста, если такой выделен), но если он содержит другие элементы (к примеру "безобидные" SPAN, B и т.д.) то текст в них выделить можно. К тому же если выделение текста начато с блока без такого атрибута, то текст внутри блока с атрибутом unselectable так же будет выделен. В такой ситуации решение одно - ставить всем (!) элементам данный атрибут, что неудобно и не практично.

2. Перехват события selectstart. Другими словами добавив элементу onselectstart="return false" (к примеру к BODY) запрещает выделение текста внутри него. Опять же нюанс: если начать выделять текст за пределами такого блока, то текст внутри него выделяется без проблем.
FireFox (браузеры на движке gecko), Safari (браузеры на движке KHTML)

Данные браузеры имеют более совершенный механизм, запрещающий выделение текста в любом виде. Делается это через CSS свойство user-select со значение none, которое включили в CSS3. Но до того как это свойство утверждено, браузеры демократично сделали это собственной фишкой движка назвав свойство -moz-user-select и -khtml-user-select соответственно. Получается, чтобы запретить выделять текст внутри блока, достаточно написать:
-moz-user-select: none;
-khtml-user-select: none;
user-select: none;

И дело в шляпе.
Другие браузеры

А вот что касается других браузеров, то у них таких механизмов замечено не было. Вообще никаких. Конечно же Opera впереди планеты всей, для нее запрет выделения текста равносильно самому злостному преступлению.

Изучая файл Оперы с хаками для сайтов, наткнулся на интересные строки:
document.addEventListener('mousemove',function(e){
if( e.target.getAttribute('unselectable')=='on' )
e.target.ownerDocument.defaultView.getSelection().removeAllRanges();
},false);
function preventSelection(element){
var preventSelection = false;

function addHandler(element, event, handler){
if (element.attachEvent)
element.attachEvent('on' + event, handler);
else
if (element.addEventListener)
element.addEventListener(event, handler, false);
}
function removeSelection(){
if (window.getSelection) { window.getSelection().removeAllRanges(); }
else if (document.selection && document.selection.clear)
document.selection.clear();
}
function killCtrlA(event){
var event = event || window.event;
var sender = event.target || event.srcElement;

if (sender.tagName.match(/INPUT|TEXTAREA/i))
return;

var key = event.keyCode || event.which;
if (event.ctrlKey && key == 'A'.charCodeAt(0)) // 'A'.charCodeAt(0) можно заменить на 65
{
removeSelection();

if (event.preventDefault)
event.preventDefault();
else
event.returnValue = false;
}
}

// не даем выделять текст мышкой
addHandler(element, 'mousemove', function(){
if(preventSelection)
removeSelection();
});
addHandler(element, 'mousedown', function(event){
var event = event || window.event;
var sender = event.target || event.srcElement;
preventSelection = !sender.tagName.match(/INPUT|TEXTAREA/i);
});

// борем dblclick
// если вешать функцию не на событие dblclick, можно избежать
// временное выделение текста в некоторых браузерах
addHandler(element, 'mouseup', function(){
if (preventSelection)
removeSelection();
preventSelection = false;
});

// борем ctrl+A
// скорей всего это и не надо, к тому же есть подозрение
// что в случае все же такой необходимости функцию нужно
// вешать один раз и на document, а не на элемент
addHandler(element, 'keydown', killCtrlA);
addHandler(element, 'keyup', killCtrlA);
}

Скопировать в буффер

Вызвав данную функцию, например:
preventSelection(document);

вы запретите выделение во всем документе, кроме элементов INPUT и TEXTAREA.

Комментарии:

Opera не дает обрабатывать событие dblclick, так что в этом браузере все равно возможно выделить текст двойным кликом.
Ctrl+A:

В Opera длительное (2-3 секунды) удержание данной комбинации вызывает выделение текста до ее отпускания. Причем если первым отжать клавишу А а потом Ctrl, то выделение пропадает. Иначе остается.
Safari не обрабатывает keydown для клавиш при зажатом Ctrl. Потому выделение текста пропадает только после отпускания клавиш. Причем для этого браузера характерно поведение Opera, в плане порядка отпускания клавиш (если первым отжать Ctrl, то выделение останется).

Выделении текста двойным кликом:

Safari & FireFox выделяют слово, и сразу снимают выделение. То есть присутствует эффект кратковременного выделения текста.
Opera не дает запретить поведение по умолчанию. Она выделяет слово и вызывает контекстное меню.

Других особенностей не выявлено.

Тестировалось на FireFox 2.0.11, IE 6.0, Opera 9.24, Safari 3.0.3 (Win).

Конечно решение не идеальное, и требует JavaScript (с другой стороны это и нужно в веб-приложениях, которые и так используют JS). Но это лучше чем ничего, и довольно кроссбраузерно (конечно может потребоваться дополнительный код для некоторых браузеров и их версий).

JavaScript не копировать