: активный псевдокласс не работает в мобильном сафари

109

В Webkit на iPhone / iPad / iPod указание стиля для псевдокласса: active для <a>тега не срабатывает при нажатии на элемент. Как я могу заставить это сработать? Пример кода:

<style> 
a:active { 
    background-color: red;
}
</style>
<!-- snip -->
<a href="#">Click me</a>
Джесси Русак
источник

Ответы:

238
<body ontouchstart="">
    ...
</body>

Примененный только один раз, в отличие от каждого элемента кнопки, казалось, исправляет все кнопки на странице. В качестве альтернативы вы можете использовать небольшую библиотеку JS под названием Fastclick . Он ускоряет события щелчка на сенсорных устройствах и решает эту проблему.

Wilsonpage
источник
19
Разве не достаточно просто добавить ontouchstartбез =""? (HTML5)
feklee
2
Для будущих читателей я разместил демо здесь: http://jsbin.com/EjiWILe/3/ . Проверьте работоспособность на вашем устройстве iOS.
mhulse
6
Можете ли вы объяснить, почему вы применили пустой слушатель к телу? Как это работает?
Маурицио Баттагини
2
Я использовал: focus, и это тоже работает. Спасибо за магию.
TecBrat
Я получаю зависания страниц на iOS 9.1 и 9.3 с использованием этого метода ... в этих версиях была ошибка js, но все еще 0,5% пользователей этих ОС
Раскин
55

Как указывалось в других ответах, iOS Safari не запускает :activeпсевдокласс, если к элементу не привязано событие касания, но до сих пор это поведение было «волшебным». Я наткнулся на эту небольшую аннотацию к библиотеке разработчика Safari, которая объясняет это (выделено мной):

Вы также можете использовать -webkit-tap-highlight-colorсвойство CSS в сочетании с настройкой события касания, чтобы настроить кнопки так, чтобы они работали так же, как на рабочем столе. В iOS события мыши отправляются так быстро, что данные о неактивном или активном состоянии никогда не принимаются. Следовательно, :activeпсевдосостояние запускается только тогда, когда для HTML-элемента установлено событие касания - например, когда ontouchstart установлен для элемента следующим образом:

<button class="action" ontouchstart=""
        style="-webkit-tap-highlight-color: rgba(0,0,0,0);">
    Testing Touch on iOS
</button>

Теперь, когда кнопка нажата и удерживается на iOS, кнопка меняет свой цвет на указанный цвет без появления окружающего прозрачного серого цвета.

Другими словами, установка ontouchstartсобытия (даже если оно пустое) явно указывает браузеру реагировать на события касания.

На мой взгляд, это ошибочное поведение и, вероятно, восходит к тому времени, когда «мобильный» Интернет практически не существовал (взгляните на эти скриншоты на связанной странице, чтобы понять, что я имею в виду), и все было ориентировано на мышь. Интересно отметить, что другие, более новые мобильные браузеры, такие как Android, отображают псевдосостояние `: active 'при касании нормально, без каких-либо взломов, подобных тому, что требуется для iOS.

(Примечание: если вы хотите использовать свои собственные стили в iOS, вы также можете отключить серый полупрозрачный блок по умолчанию, который iOS использует вместо :activeпсевдосостояния, используя -webkit-tap-highlight-colorсвойство CSS, как описано на той же связанной странице выше .)


После некоторых экспериментов ожидаемое решение по установке ontouchstartсобытия для <body>элемента, к которому затем всплывают все события касания, не работает полностью. Если элемент виден в области просмотра при загрузке страницы, то он работает нормально, но прокрутка вниз и нажатие на элемент, который находился вне области просмотра, не вызывает :activeпсевдосостояние, как должно. Итак, вместо

<!DOCTYPE html>
<html><body ontouchstart></body></html>

прикрепите событие ко всем элементам вместо того, чтобы полагаться на всплытие события до тела (используя jQuery):

$('body *').on('touchstart', function (){});

Однако я не знаю, как это повлияет на производительность, так что будьте осторожны.


РЕДАКТИРОВАТЬ: В этом решении есть один серьезный недостаток: даже прикосновение к элементу во время прокрутки страницы активирует :activeпсевдосостояние. Чувствительность слишком сильная. Android решает эту проблему, вводя очень небольшую задержку перед отображением состояния, которая отменяется при прокрутке страницы. В свете этого я предлагаю использовать это только для избранных элементов. В моем случае я разрабатываю веб-приложение для использования в поле, которое в основном представляет собой список кнопок для навигации по страницам и отправки действий. Поскольку в некоторых случаях вся страница состоит из кнопок, для меня это не сработает. Однако вы можете :hoverвместо этого установить псевдосостояние. После отключения серого поля по умолчанию это работает отлично.

user128216
источник
6
Отличное объяснение того, почему, а не только как ! Спасибо!
coderfin,
6
Проголосовали за то, чтобы дать разработчикам понимание, а не просто «волшебный» рецепт. Это бесконечно информативнее, чем другие; спасибо, что написали это для нас.
user508633
Проголосовали за подробное объяснение + предостережения. Это должен быть правильный ответ.
Master of Ducks
39

Добавьте обработчик событий для ontouchstart в свой тег <a>. Это заставляет CSS волшебным образом работать.

<a ontouchstart="">Click me</a>
Джесси Русак
источник
3
Извините, это старый ответ, но почему он работает? Я не возражаю против «волшебства» как причины, но если бы вы могли объяснить, почему это работает, я бы хотел прочитать более подробную информацию.
mhulse
1
@mhulse Я тоже хотел бы знать, почему.
Джесси Русак
Ха! Мы в одной лодке. Я постараюсь провести небольшое исследование и опубликовать здесь ссылку на (полу) официальные документы по этому вопросу. Мне нравится, что эта техника работает, мне просто интересно, почему?
mhulse
7

Это работает для меня:

document.addEventListener("touchstart", function() {},false);

Примечание. Если вы проделаете этот трюк, также стоит удалить цвет выделения по умолчанию, применяемый в Mobile Safari, используя следующее правило CSS.

html {
    -webkit-tap-highlight-color: rgba(0,0,0,0);
}
dhqvinh
источник
5

По состоянию на 8 декабря 2016 года принятый ответ ( <body ontouchstart="">...</body>) не работает для меня в Safari 10 (iPhone 5s): этот хакерский метод работает только для тех элементов, которые были видны при загрузке страницы.

Однако добавление:

<script type='application/javascript'>
  document.addEventListener("touchstart", function() {}, false);
</script>

to the headдействительно работает так, как я хочу, с обратной стороной, что теперь все события касания во время прокрутки также запускают :activeпсевдосостояние для затронутых элементов. (Если это проблема для вас, вы можете рассмотреть обходной :hover путь FighterJet .)

Али
источник
4
//hover for ios
-webkit-tap-highlight-color: #ccc;

Это работает для меня, добавьте в свой CSS элемент, который вы хотите выделить

Красный глаз
источник
3

Вы используете все псевдоклассы или только один? Если вы используете как минимум два, убедитесь, что они в правильном порядке, иначе все сломаются:

a:link
a:visited
a:hover
a:active

..в этой последовательности. Кроме того, если вы просто используете: active, добавьте ссылку:, даже если вы ее не стилизуете.

tahdhaze09
источник
отличный совет о важности порядка при стилизации псевдоклассов.
brianarpie
1

Я опубликовал инструмент, который должен решить эту проблему за вас.

На первый взгляд проблема выглядит простой, но на самом деле поведение касания и щелчка нужно настраивать довольно широко, включая функции тайм-аута и такие вещи, как «что происходит, когда вы прокручиваете список ссылок» или «что происходит, когда вы нажимаете ссылку, а затем переместите мышь / палец из активной области "

Это должно решить все сразу: https://www.npmjs.com/package/active-touch

Вам нужно либо назначить: active стили классу .active, либо выбрать собственное имя класса. По умолчанию скрипт будет работать со всеми элементами ссылки, но вы можете перезаписать его своим собственным массивом селекторов.

Честные, полезные отзывы и вклад очень ценятся!

dmitrizzle
источник
2
Эта библиотека добавляет 9 (непассивных) прослушивателей событий к каждому элементу ссылки, но не вызывает removeEventListener - я думаю, это будет большим недостатком для одностраничных приложений
Дренай
1
Спасибо, Райан. Я не поддерживаю и не использую этот код более года; Я сниму. После некоторых размышлений и экспериментов я изменил дизайн приложения вместо того, чтобы пытаться заставить взаимодействия, которые не учитываются или не продумываются браузерами.
dmitrizzle
1

Для тех, кто не хочет использовать ontouchstart, вы можете использовать этот код

<script>
 document.addEventListener("touchstart", function(){}, true);
</script>
Нуб Дев
источник
1

Я пробовал этот ответ и его варианты, но, похоже, ни один из них не работал надежно (и мне не нравится полагаться на «магию» для подобных вещей). Вместо этого я сделал следующее, которое отлично работает на всех платформах, а не только на Apple:

  1. ПЕРЕИМЕНОВАНА декларация CSS , которые используются :activeдля .active.
  2. Составлен список всех затронутых элементов и добавлены pointerdown/mousedown/touchstartобработчики событий для применения .activeкласса и pointerup/mouseup/touchendобработчики событий для его удаления. Используя jQuery:

    let controlActivationEvents = window.PointerEvent ? "pointerdown" : "touchstart mousedown";
    let controlDeactivationEvents = window.PointerEvent ? "pointerup pointerleave" : "touchend mouseup mouseleave";
    
    let clickableThings = '<comma separated list of selectors>';
    $(clickableThings).on(controlActivationEvents,function (e) {
        $(this).addClass('active');
    }).on(controlDeactivationEvents, function (e) {
        $(this).removeClass('active');
    });

Это было немного утомительно, но теперь у меня есть решение, которое менее уязвимо для сбоев между версиями ОС Apple. (А кому нужна такая поломка?)

даффинм
источник
Я думаю, это дает ответ на вопрос. Кажется, нет надежного способа заставить псевдокласс: active работать в мобильном Safari. Но это можно надежно смоделировать, используя данное мной решение. Я сделал это в своем приложении, и оно отлично работает на всех платформах. И я добавил код для пояснения.
daffinm
0

Решение состоит в том, чтобы полагаться на :targetвместо :active:

<style> 
a:target { 
    background-color: red;
}
</style>
<!-- snip -->
<a id="click-me" href="#click-me">Click me</a>

Стиль будет срабатывать, когда привязка будет нацелена на текущий URL-адрес, который устойчив даже на мобильных устройствах. Недостатком является то, что вам нужна другая ссылка, чтобы очистить привязку в URL-адресе. Полный пример:

a:target { 
    background-color: red;
}
<a id="click-me" href="#click-me">Click me</a>
<a id="clear" href="#">Clear</a>

rgmt
источник
-3

Нет 100% -ного отношения к этому вопросу, но вы также можете использовать взлом css sibling для достижения этого

HTML

<input tabindex="0" type="checkbox" id="145"/>
<label for="145"> info</label>
<span> sea</span>

SCSS

input {
    &:checked + label {
      background-color: red;
    }
  }

Если вы хотите использовать чистую подсказку html / css

span {
  display: none;
}
input {
    &:checked ~ span {
      display: block;
    }
  }
Seeliang
источник
-6
<!DOCTYPE html>

<html lang="en">

<head>
<meta charset="utf-8">

<title></title>

<style>
        a{color: red;}
        a:hover{color: blue;}
</style>
</head>

<body>

        <div class="main" role="main">
                <a href="#">Hover</a>
        </div>

</body>
</html>
ТройМ
источник
1
Согласно FAQ, подписи и самореклама запрещены.
LittleBobbyTables - Au Revoir