Веб-исследователь
0,1
рейтинг
26 декабря 2007 в 16:06

Разработка → Как запретить браузеру выделять текст

Если Вы веб-разработчик, то у вас наверняка возникала необходимость в том, чтобы запретить пользователю выделение текста. Оговоримся, что я не имею ввиду полный запрет с целью защиты текста, а запрет на выделение всевозможных подписей, надписей и т.п. где выделение мешает работе интерфейса и пользователю (чаще всего при 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);

Вспомним про атрибут unselectable у Internet Explorer'а, и становится ясным что в даном случае мы боремся с выделением текста. Развив идею, получилось некоторое кроссбраузерное решение:
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.
Комментарии:
  1. Opera не дает обрабатывать событие dblclick, так что в этом браузере все равно возможно выделить текст двойным кликом.
  2. Ctrl+A:
    1. В Opera длительное (2-3 секунды) удержание данной комбинации вызывает выделение текста до ее отпускания. Причем если первым отжать клавишу А а потом Ctrl, то выделение пропадает. Иначе остается.
    2. Safari не обрабатывает keydown для клавиш при зажатом Ctrl. Потому выделение текста пропадает только после отпускания клавиш. Причем для этого браузера характерно поведение Opera, в плане порядка отпускания клавиш (если первым отжать Ctrl, то выделение останется).

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


Других особенностей не выявлено.
Тестировалось на FireFox 2.0.11, IE 6.0, Opera 9.24, Safari 3.0.3 (Win).
Конечно решение не идеальное, и требует JavaScript (с другой стороны это и нужно в веб-приложениях, которые и так используют JS). Но это лучше чем ничего, и довольно кроссбраузерно (конечно может потребоваться дополнительный код для некоторых браузеров и их версий).
Буду рад замечаниям, комментариям, дополнениям.
UPDATE Ввиду того, что многие к концу статьи видимо забывают начало, или не внимательно читают, повторяю первый суть первого абзаца. В данной статье я не решал задачу полного запрета выделения текста с целью его защиты от копирования, а имел ввиду запрет на выделение всевозможных подписей, надписей и т.п. там где выделение мешает работе интерфейса и пользователю (чаще всего при drag&drop, или выделении текста при двойном клике). Это в первую очередь касается веб-приложений и ни в коем случае не касается обычных информационных сайтов.
lahmatiy @lahmatiy
карма
128,6
рейтинг 0,1
Веб-исследователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (69)

  • 0
    Спасибо за хорошую статью.
  • –1
    Ммм ... а проще было бы накрыть текст каким-нибудь дивом и дать ему z-index чуть больше, чем у прошлого ? :)
    • +1
      А как же нажатие на элементы (кнопки, ссылки etc), эффект наведения (hover) etc?
      Данный скрипт всего лишь не дает выделять текст который не нужно никогда выделять, например, подписи к полям, заголовки колонок таблицы и т.п. Я об этом написал в начале статьи. Защищать текст от копирования никто не собирался.
      • 0
        Здесь тоже просто, кнопкам и ссылкам дать z-index ещё больше, тогда они будут поверх накрывающего дива.
        • 0
          Очень интересно как вы это сделаете кроссбраузерно, особенно в IE. Я как то пытался сделать подобное (совсем не для обсуждаемой задачи) почти везде работало, кроме IE.
          К тому же логика верстки настолько усложняет, что мама не горюй.
          • 0
            Ну, если мой вариант допилить напильником, уверен будет работать и в IE. Просто мысль в голову пришла только когда прочитал топик, раньше мыслей о запрете выделения текста не было :)
            • 0
              Попробуйте сделать. Будет интересно взглянуть, потому что в свое время у меня не получилось в IE вклинуть слой между слоем контейнером и некоторыми его элементами. В других браузерах было все отлично.
    • +2
      а еще в IE таким эффектом обладает position:absolute, правда, не везде применим.
    • 0
      Вот только у ИЕ дивы как-бы прозрачно-виртуальные, чтоли... В общем если просто сверху наложить див пустой, то ИЕ будет считать, что его и нету)
      А вот если в него прозрачный гиф положить... тогда опять таки не будет навигации никакой (особый изврат - на прозрачном гифе мапы расставить над ссылочки/кнопочками и повесить на них какие-либо события=))
      • 0
        уж проще тогда на лету вместо текста картинки генерить... :)
  • +1
    Если интуитивная реакция браузера на распространенные действия пользователя мешает интерфейсу, нафег такой интерфейс :)
    • +4
      Вот вам примеры:
      1. Некоторый текст, двойной клик по абзацу (параграфу) дает возможность его отредактировать (появляется окно с текстом для редактирования, или сам абзац заменяется TEXTAREA). К примеру в Opera это сделать невозможно (там нельзя перехватить dblclick), интуитивная реакция браузера в даном моменте никому не нужна.
      2. Drag&Drop. Вы начинаете тащить элемент. Под курсором таскается копия перетаскиваемого элемента, при этом текст на странице начинает выделяться, реагируя на движения мыши (как будто вы просто выделяете текст), что не очень приятно.
      3. Вы хотите выделить несколько строк в таблице. Нажимаете кнопку мыши, начинаете тащить, рисуется рамка выделения. После отпускания строки под рамкой выделяются. Но если вы начнете выделять рамкой нажав на текст, то текст таблицы тоже будет выделяться что в данном случае совсем не нужно.
      и т.д. и т.п.
      • 0
        В опере dblclick работает, во всяком случае в моей опере 3 месячной свежести. Там был прикол что не у всех элементов назначалось
        • 0
          Я смотрел в Операх до 9.5. Дело в том, что дабл клик придется на пустое место, то он срабатывает, а если по некоторому тексту, то ничего не происходит. Вернее происходит, сами знаете что - выделяется слово, выпадающее меню что сделать с этим словом...
      • 0
        Drag&drop совершенно точно не требует таких титанических усилий для устранения выделения.
        • 0
          Писали сами? Проверяли в разных браузерах, различных условиях?
    • +2
      При тестировании. Когда время ограничено, усложнить возможность копирования вопроса в поиск.
  • 0
    Удивительно, но факт. livejournal.com позволяет выделить текст во всех браузерах кроме оперы.
    • 0
      Не вижу описанной вами проблемы.
  • 0
    Есть еще режим каретки, когда Shift + стрелки действует как в текстоввых редакторах, выделяя текст. Режим, конечно, включается отдельно, но тогда уж стоит бороться и с ним, раз уж вы с Ctrl+A боретесь.
    • 0
      В целом я одобряю ваши исследования и мотивацию, заявленную в статье.
    • 0
      Ctrl+A скорее лишнее :)
      В основном борьба направлена на выделение текста мышью, когда оно не нужно. То есть вместо выделения пользователю предоставляется некоторая другая функциональность, к примеру Drag&Drop или действие на двойной клик.
      Есть еще задумки, чтобы выделяя текст выделялись только некоторые текстовые узлы. То есть не выделялись узлы которые не несут информационной нагрузки, к примеру, примеры заполнения полей формы или комментарии к полям, а остальные попадали в выделение.
      • 0
        Я и говорю, мотивация таких действий у вас разумная, и в целом молодца, проверяйте карму :)
  • –2
    А зачем пользователям запрещать выделять текст на сайте?
    А нельзя ли обойти все Ваши рецепты банально отключив javascript в браузере.
    В Опере по-моему(если мне не изменяет память) можно даже задать свой css для отображаения сайта
    • +3
      Пожалуйста, читайте внимательней:
      Оговоримся, что я не имею ввиду полный запрет с целью защиты текста, а запрет на выделение всевозможных подписей, надписей и т.п. где выделение мешает работе интерфейса и пользователю (чаще всего при drag&drop, или выделении текста при двойном клике). Это в первую очередь касается веб-приложений и ни в коем случае не касается информационных сайтов.
      • 0
        За статью спасибо, хорошая, но согласитесь, действует лиш на человека который не способен отключить яваскрипт в браузере :)

        А вообще, за целые сайты где например запрещенно выделение текста, или клик правой клавишей, я бы отрывал админам и вебмастерам таких сайтов руки. Так как видимо ставя защиту на правый клик, они не задумываются о том что может мне надо открыть линк в новом окне (Хот кей, типа ctrl+клик как в FF, или ctrl+shift+клик как в Opera не в счет :) )
        • +1
          Елки палки. Ну не путайте сайт с веб-приложением. Ajax и все такое без JS не работают. Попробуйте тот же Google Maps без JS.
          А насчет запрета правого клика и т.п. согласен, но вы говорите про сайты. А данный код направлен только на веб-приложения.
          • +1
            Да, извините, попутал - не внимательно прочитал.
        • 0
          читайте коммент выше :)
        • –2
          Все эти защиты — от лохов, не более.
          • 0
            Так это не защита, а по сути юзабилити, внимательно почитайте.
            • 0
              дык это не на статью реакция, а на коммент
              • 0
                Невнимателен был, сорри.
    • 0
      Использовать свою CSS можно в большинстве браузеров в Opera, FireFox, Internet Explorer. В некоторых только для всех сразу (как в IE). В некоторых можно и свои JS использовать.
      Только часто ли вы используете дополнительные CSS/JS в различного рода почтовых веб-клиентах, и других сервисах (Google Maps и т.п.). Есть всякие надстройки для популярных приложений, которые прячут ненужное, или добавляют доп. фишки, но основную суть оставляют (потому что они слишком сложно организованы, чтобы вмешиваться в их работу).
      К тому же, еще раз повторяюсь, тут смысл не в том как насолить пользователю, а в обратном. В веб-приложениях выделение текста часто мешает работе некоторой функциональности.
      • 0
        спасибо за ответ!
  • 0
    Я как то накрыл такой текст прозрачным гифом, но целиком вся бадяга всеравно выделяется.
  • –3
    Неправильная постановка задачи...
    Контент который такими способами защищают нужен лишь пользователям которые списки файлов по майкрософтовски делают - PrintScreen. Перехватите ?
    • НЛО прилетело и опубликовало эту надпись здесь
      • НЛО прилетело и опубликовало эту надпись здесь
        • –6
          По непокорной ВАМ Опере выделяется - ДВА клика - абзац - ТРИ клика БЛОК который МНЕ нужен. Вы вообще о семантическом таком вебе слыхали ?
  • –1
    тот кто захочет скопировать возьмет из исходников :) для остальных достаточно даже просто отключить джаваскрипт
    • 0
      Внимательно посмотрите про что статья.
      • +1
        Первый абзац надо продублировать в конце, походу люди дочитав до конца забывают начало :)
        • 0
          Хороший совет, сейчас так и сделаю :)
  • 0
    Большее спасибо за статью! Плюсую.
  • –2
    DRM для браузеров? O_o ;) Да ладно, DRM не существует в принципе, любая защита обходиться достаточно подготовленным пользователем. А обычные пользователи столкнуться только с проблемами. Например, если мы защитим статью от копирования таким DRM, то владельцы чужих сайтов легко скопируют прямо из HTML-кода, а обычные _ваши_ читатели не смогут скопировать длинное имя организации, чтобы поискать о нём в Интернете.
    А за саму статью, в техническом плане, спасибо :)
    • 0
      Да скока вас, перечитайте первый абзац, срочно!
    • –3
      Это не дрм а развитие "идей" самизнеетекого, эти имбицылы действительно думают что запретив копировть говонотекст подобным себе обретут идивидуальность. В производстве этого говнотекста.
      Блять вообще чего это я поцанам реальным обьясняю.. Щаз "насрут" опять в "карму" гыгыгыгы адинадин
  • 0
    очень интересная и полезная статья!
  • 0
    Наверное, многого прошу слишком. Но итоговый листинг кода, готового к употреблению, был бы очень полезен :)
    • 0
      Итоговый листинг это как раз таки текст функции preventSelection. Включаете этот код в свое приложение и вперед.
  • 0
    Нихрена себе вы тут наваяли (я извиняюсь за выражение)!
    Во-первых Ctrl+A запрещать не стоит. Иногда надо-таки выделить и скопировать. Для закрывания текста от случайных щелчков мышью можно
    а) сделать интерфейс картинкой (дополнительные возможности оформления и вёрстки)
    б) навесить поверх слой с прозрачным гифом.
    в) вообще нужно делать грамотный интерфейс и тогда задача что-то закрыть от выделения стоять не будет.
  • +2
    Очень не люблю, когда блокируется или отключается базовая функциональность браузера (выделение текста, констекстное меню, главное меню и панель управления) или javascript-ом изменяются размеры или координаты окна - руки бы поотрывал.
    не дает выделять текст который не нужно никогда выделять, например, подписи к полям, заголовки колонок таблицы
    У некоторых разработчиков нередки проблемы с самоидентификацией — они ошибочно считают, что они — люди имеющие право решать, что пользователю браузера можно и нужно, а что нет :) Пользуясь браузером я расчитываю на его проверенную временем функциональность — может быть, я хочу погуглить или перевести на другой язык, или послать по аське как раз этот кусочек текста, который разработчик вдруг запретил к выделению.

    Обычно так пытаются защитить текст от копирования — жалкие попытки, только мешающие честным пользователям (например, я люблю выделять мышкой текст во время чтения, а иногда без этого не обойтись, если разработчику взбрело в голову установить чёрный фон, а при включении пользовательского стиля дизайн расползается до нечитаемого состояния) и никак не препятствующие украсть текст тому, кому это действительно нужно.
    Некоторые "веб-дизайнеры" любят изменять размеры окна и удалять главное меню и панель инструментов — вероятно они не допускают мысли, что их сайт открывают не в отдельном окне, а в семнадцатой по счёту вкладке браузера.
    К счастью, Firebug и знание основ html/css/javascript позволяют отключать такие запреты. Для некоторых сайтов с подобными блокировками у меня уже есть букмарки с javascript-кодом для блокировки таких блокировок :)

    И, хотя тот же Гугл разницу между десктопными и браузерными приложениями сводит на нет, и в его качественно реализованных веб-приложениях такое изменение стандартного интерфейса сделано очень гармонично и интуитивно понятно, хотелось бы иногда сохранить возможность пользоваться "родной" функциональностью браузера, например, вызывать контекстное меню браузера для доступа к стандартным функциям и плагинам или выделять "невыделяемый" текст, когда хочешь скопировать в буфер обмена длинное имя документа в Google Docs без его открытия (виндовская комбинация "тык мышью, F2, ctrl+c" не действует, а открываются гуглодоки через GPRS чертовски медленно, а для некоторых ещё и дорого) — через какую-нибудь комбинацию клавиш или магическую кнопку "native behaviour" или что-то в этом роде.

    Спасибо за статью и приведённое решение.

    • 0
      Все крайне положительно, но все таки существует масса ситуаций когда выделение не желательно.(драг=анд-дроп в том числе)
      поэтому не стоит начинать холи-вар, выделение это одно, а специфические ситуации это одно.

      Кстати в большинстве случев блокирование селекшена ( череез onSelectStart and onMouseDown ) более чем достаточно. если кто то готов использовать ctrl-a - он сам себе злобный буратино
    • 0
      Еще один невнимательный читатель :)
      Я знаю, что многие программисты, особенно начинающие, считают что если есть такая возможность, к примеру, запретить контекстное меню, то значит нужно ей воспользоваться (с мыслями, я защищаю свой код или все равно оно никому не нужно). Но подумайте, что лучше сделать так, как делают в некоторых почтовых веб клиентах, что по вызову контекстного меню на письме (в списке писем) выпадало меню с действиями по этому письму (ответить, переслать, удалить, а может быть так же скопировать адрес отправителя, тему письма и т.п.) или стандартное которое тут скорее ни к чему. Другое решение ткнуть в письмо, тем самым его выделив, потом ищем кнопки с действиями, потому что браузер (на данный момент, из известных мне, только опера) не дает мне сделать свое меню. К тому же первый вариант можно докрутить таким образом, что если есть выделенный фрагмент текста на странице, то не вмешиваться и показывать стандартное меню. Что в этом плохого? Улучшаем юзабилити и только. С другой стороны в руках мало квалифицированного программиста, возможность перебить контекстное меню может быть большим злом. В итоге страдают все :(
      И потом вот вы говорите "они ошибочно считают, что они — люди имеющие право решать, что пользователю браузера можно и нужно, а что нет", вот вы правы в том, что не все знают что такое хороший сайт/приложение и как их делать, потому ляпают как попало. Но почему Опера решает за меня что я могу сделать на СВОЕМ сайте и что я не могу. По сути это решают те программисты, которые ее писали. Событие contextmenu не является стандартом, это придумали в MS, но другие браузеры (например, FF и Safari) тоже внедрили это у себя. Опера - нет, имеют право, по идее. Но потом делают хак для сайтов где это используется, чтобы там контекстное меню работало (функция fakeOncontextmenu в browser.js). Это как? Здесь можно использовать, здесь нельзя? И почему тогда в Опера это решают, а не решает это разработчик?
      Это мне напоминает ситуацию с IE7, когда они наконец реализовали полную поддержку CSS1. Но не стали поддерживать text-decoration: blink, и только потому, что они (!) считаю это злом. В итоге это единственный браузер где это не поддерживается, и blink мы делаем через JS. Конечно это не самая нужная функция, но опять кто-то решает за других.
      Браузеры сейчас стараются быть более похожими друг на друга в моменте обработки HTML/CSS/DOM/JS etc. Но только не Опера. После того как несколько лет копировала поведение IE, напрочь отказалась от этого, выкинула все плохое и, в том числе, хорошее. Я понимаю, у нее своя линия, свой путь. Но "договориться" с ней бывает очень сложно, или даже невозможно. Для информационных сайтов идеальный браузер, для веб-приложений хуже некуда. Видимо из-за этого новый Mail Yahoo отказывается в ней работать.
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    спасибо за основательный подход! мало кто держал бы контрол-А несколько секунд для того, чтобы проверить и сообщать нам что будет. мог бы - плюсовал бы карму.
  • 0
    В Gecko браузерах также есть режим перемещения по документу курсором, включаемый по F7, такой фишки нет ни в Opera ни в IE
    • 0
      спасибо за информацию
  • 0
    Про закрытие при помощи CSS свойства в FireFox... К FireFox есть плагины позволяющие отключить на странице CSS. Так что если текст нужен - то было бы желание.
  • 0
    Заметил у этого метода небольшой баг - если выбрать из меню браузера "Выделить все", то все выделяется, тестировалось на Firefox
  • 0
    Отличная статья - отлично пригодилось! То, что надо! :)
    Спасибо!
  • 0
    Вы писали как вызывать функцию. Но у меня возникли проблемы… Я вызываю с помощью onmouseover. Но тогда выделяется все оставшееся поле. Как мне сделать, чтобы запрещалось выделять только определенный элемент. Или как закрывать функцию, если использовать onmouseout?
  • 0
    Спасибо! Пользуюсь.
  • 0
    Спасибо тебе, добрый человек =)
  • 0
    Для Crome в варианте со стилями надо добавить
    -webkit-user-select: none;
  • 0
    К сожалению решение со скриптом глючит в ИЕ — при определенных обстоятельствах текст можно на короткий момент выделить и когда скрипт снимает выделение командой document.selection.clear(); то выделенный текст просто удаляется.
  • 0
    А как такое поведение запретить самим сайтам? есть какие нибудь плагины которые выключают все эти user-select: none; ???
    • 0

      Можно юзерстилем глобальным:


      * { user-select: all !important; -moz-user-select: all !important;; -webkit-user-select: all !important;; }

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.