CSS/JavaScript/взлома: обнаружение: посещение стиля по ссылке * без * проверки непосредственно или сделать это быстрее меня
Это для исследовательских целей http://cssfingerprint.com
Рассмотрим следующий код:
<style>
div.csshistory a { display: none; color: #00ff00;}
div.csshistory a:visited { display: inline; color: #ff0000;}
</style>
<div id="batch" class="csshistory">
<a id="1" href="#" onclick="location.href='http://foo.com'; return false;">anything you want here</a>
<a id="2" href="#" onclick="location.href='http://bar.com'; return false;">anything you want here</a>
[etc * ~2000]
</div>
Моя цель - определить, была ли рендерирована foo с помощью: посещенного стиля.
-
Я хочу определить, посетил ли foo.com без прямого просмотра $('1').getComputedStyle
(или в Internet Explorer, currentStyle
) или любого другого прямого метода для этого элемента.
Цель этого заключается в том, чтобы обойти потенциальное ограничение браузера, которое предотвратило бы прямой контроль стиля посещенных ссылок.
Например, возможно, вы можете поместить подэлемент в тег <a>
или напрямую проверить стиль текста; и т.д. Любой метод, который прямо или нецелесообразно полагаться на $('1').anything
, является приемлемым. Возможно, необходимо сделать что-то умное с ребенком или родителем.
Обратите внимание, что только для целей этого сценария сценарий заключается в том, что браузер будет ссылаться на JavaScript обо всех свойствах элемента <a>
(но не на других) и что он будет отображать только color:
в :visited
. Поэтому способы, которые полагаются, например, размер текста или background-image
не будет соответствовать этому требованию.
-
Я хочу улучшить скорость моих текущих методов скремблирования.
Большинство времени (по крайней мере, с помощью метода jQuery в Firefox) расходуется на document.body.appendChild(batch)
, поэтому найти способ улучшить этот вызов, вероятно, будет наиболее эффективным.
См. http://cssfingerprint.com/about и http://cssfingerprint.com/results для текущих результатов теста скорости.
Используемые мной методы можно увидеть на http://github.com/saizai/cssfingerprint/blob/master/public/javascripts/history_scrape.js
Подводя итоги для tl; dr, они:
- установите цвет или дисплей на: посещенный на каждый из них и проверьте каждый из них напрямую w/
getComputedStyle
- поместите идентификатор ссылки (плюс пробел) внутри тега
<a>
и с помощью jQuery: visible selector извлеките только видимый текст (= просмотренные идентификаторы ссылок)
FWIW, я белая шляпа, и я делаю это в консультации с EFF и некоторые другие довольно известные исследователи безопасности.
Если вы внесете новый метод или ускорителю, вы получите благодарность http://cssfingerprint.com/about (если вы хотите быть:-P ) и, возможно, в будущей опубликованной статье.
ETA: награда будет вознаграждена только за предложения, которые
- может в Firefox избегать гипотетического ограничения, описанного в пункте 1 выше, или
- выполняйте как минимум на 10% быстрее, в любом браузере, для которого у меня достаточно текущих данных, чем мои наилучшие методы, перечисленные на графике http://cssfingerprint.com/about
В случае, если более чем одно предложение соответствует любому критерию, выигрывает тот, который лучше всего выигрывает.
ETA 2: Я добавил варианты ширины двух предыдущих лучших методов тестирования (reuse_noinsert, лучше всего на Firefox/Mozilla и mass_insert, его очень близком конкуренте). Несколько раз просмотрите http://cssfingerprint.com из разных браузеров; Я автоматически получу результаты теста скорости, поэтому мы узнаем, насколько это лучше, чем предыдущие методы, и если да, то насколько. Спасибо!
ETA 3: Текущие тесты показывают экономию скорости, используя offsetWidth
(а не getCalculatedStyle
/currentStyle
) ~ 2 мс (1,8%) в Chrome и ~ 24 мс (4.3%) в Firefox, что не 10% я хотел получить солидную награду. Есть идея, как выложить остальную часть этого 10%?
Ответы
Ответ 1
[новое обновление]
Если вы хотите получить результаты только для визуального представления, самым быстрым методом будет использование счетчика CSS.
CSS
body{
counter-reset: visited_counter;
}
a:visited{
counter-increment: visited_counter;
}
#results:before{
content:counter(visited_counter);
}
Это добавит количество посещенных ссылок перед элементом с идентификаторами 'results'.
К сожалению, нет способа получить к нему доступ из JavaScript, вы можете отображать его только.
[начальный ответ]
Вы знаете, что jQuery поддерживает селектор :visited
прямо?
Как $('a:visited')
[обновление]
В качестве альтернативы вы можете применить свойство CSS, которое не полагается на getComputedStyle
для извлечения..
Как a:visited{height:1px;display:block;}
, а затем проверьте offsetHeight
.
Ответ 2
- добавьте дочерний элемент внутри якоря (например, span)
- использовать
color : inherit
- определить цвет дочернего элемента (JS)
caveat: afaik он не будет работать на lte ie7
для lte ie7 ull имеем to
- добавить
visibility : hidden
в a:visited
и visibility : inherit
для дочернего
- проверьте видимость дочернего элемента, используя javascript (hidden = visited)
Ответ 3
Аналогичная идея, но обойти стороной .getComputedStyle()
:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<style type="text/css">
a:visited { display: inline-block; font-family: monospace; }
body { font-family: sans-serif; }
</style>
<script type="text/javascript">
function test() {
var visited = document.getElementById("v").childNodes[1].firstChild.clientWidth;
var unvisited = document.getElementById("u").childNodes[1].firstChild.clientWidth;
var rows = document.getElementsByTagName("tr");
for (var i = 1, length = rows.length; i < length; i++) {
var row = rows[i];
var link = row.childNodes[1].firstChild;
var width = link.clientWidth;
row.firstChild.appendChild(document.createTextNode(link.href));
row.childNodes[2].appendChild(document.createTextNode(width === visited ? "yes" : (width === unvisited ? "no" : "unknown")));
}
}
</script>
</head>
<body onload="test()">
<table>
<tr><th>url</th><th>link</th><th>visited?</th></tr>
<tr id="u"><td></td><td><a href="http://invalid_host..mplx/">l</a></td><td></td>
<tr id="v"><td></td><td><a href="css-snoop.html">l</a></td><td></td>
<tr><td></td><td><a href="http://stackoverflow.com/">l</a></td><td></td>
<tr><td></td><td><a href="http://www.dell.com/">l</a></td><td></td>
</table>
</body>
</html>
Трюк, конечно же, заключается в том, что посещаемые и невидимые ссылки имеют разную ширину (здесь, используя sans-serf vs. monospace fonts) и устанавливая их на inline-block
, чтобы их ширину можно было получить через clientWidth
, Протестировано для работы с FF3.6, IE7, Chrome 4 и Opera 10.
В моих тестах доступ к clientWidth
был последовательно быстрее, чем все, что основывалось на вычисленных стилях (иногда на ~ 40%, но широко варьировалось).
(О, и извинения за глупость <body onload="...">
, это было слишком долго, поскольку я пытался делать события в IE без рамки, и мне надоело бороться с ним.)
Ответ 4
Поскольку все версии IE (да, даже версия 8, если вы включили quirks) поддерживают выражения CSS, свойство цвета по-прежнему небезопасно. Вероятно, вы можете ускорить тестирование IE с помощью этого (непроверенного):
a:visited { color: expression( arrVisited.push(this.href) ); }
Кроме того, на ваш вопрос это не распространяется, но вы можете, конечно, установить свойства в дочерних узлах очень легко, чтобы инициировать обнаружение, и любое решение также должно было бы предотвратить это:
a.google:visited span { background-image: url(http://example.com/visited/google); }
Вам необходимо защитить соседних братьев и сестер, а не только потомков:
a.google:visited + span { }
Также непроверенный, но вы, вероятно, можете сделать тяжелое ускорение, используя свойство content
, чтобы изменить DOM, а затем некоторый XPath, чтобы найти новые узлы.
a.google:visited:before {content: "visited"; visibility: hidden;}
XPath:
visited links = document.evaluate('//a[text()="visited"]')