Jump to content
  • 0

Клик меню на :target


gordi
 Share

Question

Есть меню с одним уровнем вложения - http://trifler.ru/blog/i/menus/click/target.htm

Вывод вложений осуществлен при помощи псевдокласса :target

Каким образом решить проблему в IE6(7,8)?

Как понимаю нужен Java Script.

Использование jQuery и других, не предлагать.

Простой скрипт для эмуляции :target только для IE6(7,8)

Edited by gordi
Link to comment
Share on other sites

25 answers to this question

Recommended Posts

  • 0

Навскидку получилось как-то так:

document.attachEvent('onclick', function() {
setTimeout(function() {
var target = document.getElementById(location.hash.replace('#',''));
if (target && target != window.targetedDl) {
if (window.targetedDl) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = '0';
}
window.targetedDl = target;
window.targetedDl.getElementsByTagName('dd')[0].style.height = 'auto';
}
},1);
});

Только зелененькой подсветки активной dt-шки по наведению пока нет, но это добавляется двумя строчками или одним доп. классом...

Link to comment
Share on other sites

  • 0

Навскидку получилось как-то так:

document.attachEvent('onclick', function() {
setTimeout(function() {
var target = document.getElementById(location.hash.replace('#',''));
if (target && target != window.targetedDl) {
if (window.targetedDl) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = '0';
}
window.targetedDl = target;
window.targetedDl.getElementsByTagName('dd')[0].style.height = 'auto';
}
},1);
});

Только зелененькой подсветки активной dt-шки по наведению пока нет, но это добавляется двумя строчками или одним доп. классом...

Спасибо, Илья.

Даже этого вполне достаточно.

Обновленный пример - http://trifler.ru/blog/i/menus/click/target01.htm

Подсветку заголовка отрытого раздела (dt), лучше сделать без класса.

Также желательно, чтобы при отключенном скрипте, меню в IE6(7,8) было полностью раскрыто.

Хотя и вашего скрипта для минимальной поддержки IE6(7,8) хватит за глаза :)

Еще раз спасибо.

Edited by gordi
Link to comment
Share on other sites

  • 0

Полное раскрытие при отключенном — имхо, проще всего взять добавочный <style> из первого примера и обернуть в <noscript>. И, тыща пардонов, но на всякий случай — ссылка на конкурентов...

Link to comment
Share on other sites

  • 0

Полное раскрытие при отключенном — имхо, проще всего взять добавочный <style> из первого примера и обернуть в <noscript>. И, тыща пардонов, но на всякий случай — ссылка на конкурентов...

C <noscript> попробуем :)

Что же до конкурентов, насколько помню, первое меню с использованием :target датировано 2009 годом,

по крайней мере, такая запись в моих архивах имеется.

У всех конкурентов одна проблема - выпадающий лист фиксирован по высоте :)

в моем случае, этого удалось избежать.

Edited by gordi
  • Like 1
Link to comment
Share on other sites

  • 0

У всех конкурентов одна проблема - выпадающий лист фиксирован по высоте :)

в моем случае, этого удалось избежать.

На самом деле у вас не одинаковое отображение для ИЕ678 и всем остальными, я имею ввиду обновленную ссылку

У вас в адекватных браузерах:

во первых, при актиивном меню, фон зеленый

во вторых, при нажатии на элемент подменю, все подменю скрывается

В не адекватных, это не работает

И это с использованием скриптов? Без скриптов можно сделать нормально выпадение для всех браузеров используя :hover, :focus и:active

Ну если уж вам так принципиально :target то пожалуйста...

И еще у "конкурентов" фиксированная высота ставится в 99% случаев только для того, чтобы работали css transition

Если у вас этого не требуется то в коде конкурентов меняем height: 100px; на height: auto; и идем праздновать.

Edited by leoni4
Link to comment
Share on other sites

  • 0

У всех конкурентов одна проблема - выпадающий лист фиксирован по высоте :)

в моем случае, этого удалось избежать.

На самом деле у вас не одинаковое отображение для ИЕ678 и всем остальными, я имею ввиду обновленную ссылку

У вас в адекватных браузерах:

во первых, при актиивном меню, фон зеленый

во вторых, при нажатии на элемент подменю, все подменю скрывается

В не адекватных, это не работает

И это с использованием скриптов? Без скриптов можно сделать нормально выпадение для всех браузеров используя :hover, :focus и:active

Ну если уж вам так принципиально :target то пожалуйста...

И еще у "конкурентов" фиксированная высота ставится в 99% случаев только для того, чтобы работали css transition

Если у вас этого не требуется то в коде конкурентов меняем height: 100px; на height: auto; и идем праздновать.

1. Читайте внимательно комментарии к скрипту, минимальная поддержка IE6(7,8) есть и большего требовать едва ли имеет смысл.

2. Есть в моей коллекции меню и на :hover, :focus, :active, но иногда хочется и другого, было бы интересно увидеть именно вашу реализацию на :hover, :focus и :active, без ссылок на те или иные источники, которые в основном дублируют друг друга :)

3. "...меняем height: 100px; на height: auto;...", а так ли все просто? Попробуйте, буду рад, если у вас все выйдет гораздо проще и лучше.

Link to comment
Share on other sites

  • 0

Как определить поддержку браузером псевдокласа?

Тоесть мне нужно проверить:

если :target поддерживается - то никакого js, иначе - запускаем скрипт который реагирует на hashchange и ставит на блок который я вляется ":target" определенный класс, и стили применяем через этот класс. Для браузеров не поддерживающих hashchange эмулируем его с помощью бесконечного повторение функции через setTimeout

Пока что нагуглил и слепил такое:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<title></title>
<style type="text/css">
* {margin:0;padding:0;}
.target {
background:#eee;border:#999 1px solid;
margin:10px auto;padding:5px;width:200px;
}
.target dt a {
background:#000;color:#fff;display:block;
font:bold 13px georgia,arial;margin:2px 0;
padding:3px 5px;text-decoration:none;
}
.target dt a:hover {background:#905;color:#fff;}

.target :target dt a{background:#080;color:#fff;cursor:text;}
.target .target-box dt a{background:#080;color:#fff;cursor:text;}

.target dd {background:#fff;padding:0 5px;overflow:hidden;height:0;}

.target :target dd{height:auto;}
.target .target-box dd{height:auto;}

.target dd a {color:#000;display:block;padding:2px 5px;text-decoration:none;}
.target dd a:hover {color:#a00;}
</style>
<!--[if lte IE 8]>
<script type="text/javascript">
// domReady
function initPage(fn) {
var scope = this, calledFlag;
(function(){
if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', function(){
if(!calledFlag) { calledFlag = true; fn.call(scope); }
}, false)
}
if (!document.readyState || document.readyState.indexOf('in') != -1) {
setTimeout(arguments.callee, 9);
} else {
if(!calledFlag) { calledFlag = true; fn.call(scope); }
}
}());
}
initPage(function() {
hasTarget();
});

var targetClass = 'target-box';
function hasTarget() {
var targetH = getHashValue();
if(targetH) {
var target = document.getElementById(targetH);
if(target) {
addClass(target, targetClass);
}
}
}

function getHashValue() {
var arr = window.location.hash.split("#");
var hasValue = arr[1];
if (typeof hasValue == "undefined") {
return false;
}
var hashLen = hasValue.indexOf("?");
if(hashLen>0){
hasValue = hasValue.substring(0,hashLen);
}
return hasValue;
}

function onHashChange(event) {
var lastHash = getHashValue();
var hash= getHashValue();

if('onhashchange' in window) {
function setEvHash() {
hash = getHashValue();
event(hash, lastHash);
lastHash = hash;
}

if (window.addEventListener) window.addEventListener("hashchange", setEvHash, false);
else if (window.attachEvent) window.attachEvent("onhashchange", setEvHash);
}
else {
(function watchHash() {
hash = getHashValue();
if (hash !== lastHash) {
event(hash, lastHash);
lastHash = hash;
}
var t = setTimeout(watchHash, 100);
})();
}
}

function hasClass(obj, cname) {
return (obj.className ? obj.className.match(new RegExp('(\\s|^)'+cname+'(\\s|$)')) : false);
}
function addClass(obj, cname) {
if (!hasClass(obj, cname)) obj.className += " "+cname;
}
function removeClass(obj, cname) {
if (hasClass(obj, cname)) obj.className=obj.className.replace(new RegExp('(\\s|^)'+cname+'(\\s|$)'),' ');
}

onHashChange(function(hash, lastHash) {
if(hash) {
var target = document.getElementById(hash);
if(target) {
addClass(target, targetClass);
}
}
if(lastHash) {
var lastTarget = document.getElementById(lastHash);
if(lastTarget) {
removeClass(lastTarget, targetClass);
}
}
});
</script>
<![endif]-->
</head>
<body>
<div class="target">
<dl id="t1">
<dt><a href="#t1">Раздел 1</a></dt>
<dd>
<a href="#">Пункт № 1</a>
<a href="#">Пункт № 2</a>
<a href="#t5">Раздел 5</a>
</dd>
</dl>
<dl id="t2">
<dt><a href="#t2">Раздел 2</a></dt>
<dd>
<a href="#">Пункт № 1</a>
<a href="#">Пункт № 2</a>
<a href="#">Пункт № 4</a>
<a href="#">Пункт № 4</a>
</dd>
</dl>
<dl id="t3">
<dt><a href="#t3">Раздел 3</a></dt>
<dd>
<a href="#">Пункт № 1</a>
<a href="#">Пункт № 2</a>
</dd>
</dl>
<dl id="t4">
<dt><a href="#t4">Раздел 4</a></dt>
<dd>
<a href="#">Пункт № 1</a>
<a href="#">Пункт № 2</a>
</dd>
</dl>
<dl id="t5">
<dt><a href="#t5">Раздел 5</a></dt>
<dd>
<a href="#">Пункт № 1</a>
<a href="#">Пункт № 2</a>
</dd>
</dl>
<a href="#t6">hash без цели ;-)</a>
</div>
</body>
</html>

Link to comment
Share on other sites

  • 0

leoni4,

Да, и мне пожалуйста покажите тестовую страницу с готовым примером, работающим во-всех браузерах. ИЕ6+ :)

Выложу свой пример подобного меню.

Есть не большие разночтения при работе в IE6

http://trifler.ru/blog/i/menus/click/click.htm

Как определить поддержку браузером псевдокласа?

Тоесть мне нужно проверить:

если :target поддерживается - то никакого js, иначе - запускаем скрипт который реагирует на hashchange и ставит на блок который я вляется ":target" определенный класс, и стили применяем через этот класс. Для браузеров не поддерживающих hashchange эмулируем его с помощью бесконечного повторение функции через setTimeout

Пока что нагуглил и слепил такое:

...

Спасибо.

Практически идеально и как раз то, что нужно:)

Обновленный пример - http://trifler.ru/blog/i/menus/click/target02.htm

Edited by gordi
Link to comment
Share on other sites

  • 0

mishka, респект за большую и поучительную работу, но... обязательны ли такие сложности? Судя по этой и этой таблицам, единственные мало-мальски актуальные браузеры, не рубящие фишку :target-а — это непарнокопытные из Редмонда по 8-ю версию включительно, из них onhaschange понимает лишь IE8. Стоит ли ради него одного ветвить алгоритм? И от чего еще может поменяться location.hash, кроме как от клика по ссылке? И еще, что дает ограничение значения hash вопросом, разве вопрос в hash умеет делать какую-то магию?

Вот случай пустого hash (просто решетка в адресе) я в своем варианте прощелкал, это да...

Link to comment
Share on other sites

  • 0

Ну я же говорил что слепил то что нашел:

http://www.davidpirek.com/blog/on-hash-change-javascript-listener

http://y3x.ru/2011/06/hashchange/

Почему здесь автор в hash проверяет именно "?" - пока не знаю.

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

Если считаешь что ветвить алгоритм не стоит, то пусть так вот в условных коментариях и остается.

Ток порядок в коде навести нужно, так как это по-быстрому клепалось.

Можно было бы и для всех браузеров оставить, но в ФФ видно дергание - пока обрабатывается джс на доли секунды видно оба открытых блока. Некрасиво.

Link to comment
Share on other sites

  • 0

SelenIT, вобщем ты прав.

Я пришел к выводу что если поддерживать ие6-8, то написать общий джс, и не парится. И стили задавать через класс, а не через :target

При загрузке проверить хеш, и в случае если есть блок соответствующий ":target", то добавить нужный класс, и этот блок запомнить как активный.

Линкам которые предназначены для открытия аккордеона, задать определенный класс, и по этому классу навесить функцию на клик.

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

Это будет не так громоздко как я сделал выше.

Link to comment
Share on other sites

  • 0

Мой вариант с зеленой подсветкой и сбросом выделения при переходе на "левый" hash, с учетом пожелания автора, что "лучше без классов", вышел таким:

function changeTarget() {
setTimeout(function() {
var targetId = location.hash.replace('#','');
var lastTarget = (window.targetedDl && window.targetedDl.id) || '';
if (targetId != lastTarget) {
if (window.targetedDl) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = '0';
window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '';
}
if (window.targetedDl = document.getElementById(targetId)) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = 'auto';
window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '#080';
}
}
},1);
}

Не учитывает вариант смены #хэша вручную (вот что я пропустил по сравнению с вариантом зацикленного таймера), но, имхо, вероятность такого действия со стороны обычного пользователя архаичных IE стремится к нулю :).

На правах курьеза (пока что) в IE7 (точнее, в IE9 as IE7) работает вот такой забавный вариант. Ограничения — все участвующие в процессе id-шки должны быть нормальными по старым стандартам (непустыми и начинающимися с буквы, вместо href="#" для сброса выделения приходится указывать что-то типа href="#top"), и есть риск проблем с др. псевдоклассами (и псевдоэл-тами CSS2), которых IE7 не знал. К сожалению, IE8, похоже, вместо того, чтобы воспринимать незнакомый ":target" как столь удобный ":unknown", игнорирует строку с ним напрочь (нашел когда внезапно начать соблюдать стандарт, называется;). Теоретически, можно вручную распарсить innerHTML тега style (как быть с внешними CSS, надо покумекать) и провернуть эту же логику "в обход", но реализация становится куда сложнее. Вот думаю, есть ли смысл ковырять в эту сторону?..

Link to comment
Share on other sites

  • 0

Мой вариант с зеленой подсветкой и сбросом выделения при переходе на "левый" hash, с учетом пожелания автора, что "лучше без классов", вышел таким:

function changeTarget() {
setTimeout(function() {
var targetId = location.hash.replace('#','');
var lastTarget = (window.targetedDl && window.targetedDl.id) || '';
if (targetId != lastTarget) {
if (window.targetedDl) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = '0';
window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '';
}
if (window.targetedDl = document.getElementById(targetId)) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = 'auto';
window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '#080';
}
}
},1);
}

Не учитывает вариант смены #хэша вручную (вот что я пропустил по сравнению с вариантом зацикленного таймера), но, имхо, вероятность такого действия со стороны обычного пользователя архаичных IE стремится к нулю :).

Спасибо, Илья.

Это вариант короче.

Но или что-то сделал не так или...

Не работает.

Ограничился добавлением двух строк из этого варианта в ваш первый.

window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '';

window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '#080';

Скрипт стал таким:


<!-- for IE6,IE7 and IE8 -->
<!--[if lt IE 9]>
<script type="text/javascript">
document.attachEvent('onclick', function() {
setTimeout(function() {
var target = document.getElementById(location.hash.replace('#',''));
if (target && target != window.targetedDl) {
if (window.targetedDl) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = '0';
window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '';
}
window.targetedDl = target;
window.targetedDl.getElementsByTagName('dd')[0].style.height = 'auto';
window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '#080';
}
},1);
});
</script>
<![endif]-->

Обновление - http://trifler.ru/blog/i/menus/click/target03.htm

На правах курьеза (пока что) в IE7 (точнее, в IE9 as IE7) работает вот такой забавный вариант. Ограничения — все участвующие в процессе id-шки должны быть нормальными по старым стандартам (непустыми и начинающимися с буквы, вместо href="#" для сброса выделения приходится указывать что-то типа href="#top"), и есть риск проблем с др. псевдоклассами (и псевдоэл-тами CSS2), которых IE7 не знал. К сожалению, IE8, похоже, вместо того, чтобы воспринимать незнакомый ":target" как столь удобный ":unknown", игнорирует строку с ним напрочь (нашел когда внезапно начать соблюдать стандарт, называется;). Теоретически, можно вручную распарсить innerHTML тега style (как быть с внешними CSS, надо покумекать) и провернуть эту же логику "в обход", но реализация становится куда сложнее. Вот думаю, есть ли смысл ковырять в эту сторону?..

А тут трудно сказать :)

Скрипт по объему будет больше, чем стили и html-код самого меню, стоит ли не адекватность IE лечить в таком случае? :)

Хотя и сам многие вещи делаю чисто из спортивного интереса :)

*******

Для полного "счастья" в скрипт последнего обновления меню после строки:

window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '#080';

Стоит добавить

window.targetedDl.getElementsByTagName('a')[0].style.cursor = 'text';

Тогда при наведении курсора мыши на заголовок открытого раздела, будет полная идентичность с вменяемыми браузерами.

Edited by gordi
Link to comment
Share on other sites

  • 0

Виноват, полностью мой скрипт выглядит так:

function changeTarget() {
setTimeout(function() {
var targetId = location.hash.replace('#','');
var lastTarget = (window.targetedDl && window.targetedDl.id) || '';
if (targetId != lastTarget) {
if (window.targetedDl) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = '0';
window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '';
window.targetedDl.getElementsByTagName('a')[0].style.cursor = '';
}
if (window.targetedDl = document.getElementById(targetId)) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = 'auto';
window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '#080';
window.targetedDl.getElementsByTagName('a')[0].style.cursor = 'text';
}
}
},1);
}
document.attachEvent('onclick', changeTarget);
document.attachEvent('onreadystatechange', function() {
if(document.readyState=='complete') changeTarget();
});

Ну и для полной совместимости можно в те же условные комменты добавить <noscript> с добавочным стилем из первого примера внутри...

Link to comment
Share on other sites

  • 0

Виноват, полностью мой скрипт выглядит так:

function changeTarget() {
setTimeout(function() {
var targetId = location.hash.replace('#','');
var lastTarget = (window.targetedDl && window.targetedDl.id) || '';
if (targetId != lastTarget) {
if (window.targetedDl) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = '0';
window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '';
window.targetedDl.getElementsByTagName('a')[0].style.cursor = '';
}
if (window.targetedDl = document.getElementById(targetId)) {
window.targetedDl.getElementsByTagName('dd')[0].style.height = 'auto';
window.targetedDl.getElementsByTagName('a')[0].style.backgroundColor = '#080';
window.targetedDl.getElementsByTagName('a')[0].style.cursor = 'text';
}
}
},1);
}
document.attachEvent('onclick', changeTarget);
document.attachEvent('onreadystatechange', function() {
if(document.readyState=='complete') changeTarget();
});

Ну и для полной совместимости можно в те же условные комменты добавить <noscript> с добавочным стилем из первого примера внутри...

Еще раз большое спасибо.

Наверно не понимаю, но если в условные комментарии добавляю


<noscript>
<style type="text/css">
.target dd {display:block;height:auto;}
.target dt a {background:#080;color:#fff;cursor:text;}
.target dt a:hover {background:#080;color:#fff;}
</style>
</noscript>

и удаляю из них скрипт, меню не разворачивается в IE или туплю :)

Link to comment
Share on other sites

  • 0

Удалять-то скрипт зачем? Пусть <noscript> лежит себе рядом...

Хотелось имитировать отсутствие/отключение скрипта и получается,

что при отсутствии скрипта стили не работают, видимо из-за <noscript>...</noscript>,

а удаление <noscript>...</noscript> приводит к тому, что если скрипт подключен, стили его перебивают :)

Edited by gordi
Link to comment
Share on other sites

  • 0

Так не получится, noscript реагирует на физическую возможность выполнения скрипта, а не на его наличие/отсутствие. В IE9 (по-моему, в IE8 тоже) скрипт можно выключить из Developer tools-ов (или просто не включать "заблокированное активное содержимое" при открытии файла локально), в более старых он выключается в "Свойствах обозревателя" (в неожиданном месте, на вкладке "секьюрити").

Link to comment
Share on other sites

  • 0

Так не получится, noscript реагирует на физическую возможность выполнения скрипта, а не на его наличие/отсутствие. В IE9 (по-моему, в IE8 тоже) скрипт можно выключить из Developer tools-ов (или просто не включать "заблокированное активное содержимое" при открытии файла локально), в более старых он выключается в "Свойствах обозревателя" (в неожиданном месте, на вкладке "секьюрити").

Спасибо, разобрался.

Последняя редакция меню - http://trifler.ru/blog/i/menus/click/target04.htm

Link to comment
Share on other sites

  • 0

Вдогонку: есть подозрения, что громоздкий обработчик

document.attachEvent('onreadystatechange', function() {...

можно заменить на однострочный

document.attachEvent('onfocusin', changeTarget);

не только без потерь, но даже с выгодой (появляется реакция на смену hash вручную). Вот только history не поддается, но чего ж хотеть от полувымерших динозавров?..

Link to comment
Share on other sites

  • 0

Вдогонку: есть подозрения, что громоздкий обработчик

document.attachEvent('onreadystatechange', function() {...

можно заменить на однострочный

document.attachEvent('onfocusin', changeTarget);

не только без потерь, но даже с выгодой (появляется реакция на смену hash вручную). Вот только history не поддается, но чего ж хотеть от полувымерших динозавров?..

Попробовал :)

Работает, но все остальное не понимаю :)

В JS не силен :(

Попытался пристроить меню на полноценную страничку.

Первое разочарование, при использовании:

margin-bottom:-32767px;padding-bottom:32766px;

для эмуляции колонок равной высоты страница ведет себя, как-то странно.

Разбираюсь :)

Edited by gordi
Link to comment
Share on other sites

  • 0

Емнип, способ с гигантскими паддингами всегда глючил с внутристраничными якорями, это было едва ли не главным ограничением этого подхода...

Точно :)

Сколько времени убил решая проблему, а вот забыл :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. See more about our Guidelines and Privacy Policy