Как починить :hover под мобильные устройства?

Рейтинг: 7Ответов: 2Опубликовано: 11.09.2014

Всем привет, прошу совета.
Есть выпадающее меню, реализованное через css :hover, т.е. есть пункт меню, при наведении срабатывает hover и подменю у данного пункта меняет свойство display на block, после того как убрали мышь, снова становится none. На обычном ПК все хорошо, но на мобильных из-за отсутствия возможности просто навести данная реализация не работает. Как можно это поправить? Чтобы на мобильных устройствах меню тоже выпадало (сейчас при клике оно выпадает, но сразу же переходит по ссылке на первом пункте). Если же это нереально, то как можно реализовать меню, чтобы оно было выпадающим и работало на всех устройствах (те примеры, что я находил через jquery, не подходят, т.к. там основные пункты меню не работают как ссылки, т.е. при клике на них меню просто выпадает, а нужен переход).

Пример

<div class="menu"><ul>
<li><a href="../about">О компании</a><ul><a href="../vakansii" class="pp">Вакансии</a></ul></li>
<li><a href="../work">Проекты</a><ul><a href="../otzyivyi" class="pp">Отзывы</a></ul></li>
</ul>
</div>

Тут из пункта О компании выпадает Вакансии.

Ответы

▲ 10Принят

Проблема актуальна, можно решать таким образом:

<div class="top-menu" data-hover="hover-on-menu">
<a href="/to/your/url" data-hover="hover-on-link">Hello</a>

<script>

var touchHover = function() {
    $('[data-hover]').click(function(e){
        e.preventDefault();
        var $this = $(this);
        var onHover = $this.attr('data-hover');
        var linkHref = $this.attr('href');
        if (linkHref && $this.hasClass(onHover)) {
            location.href = linkHref;
            return false;
        }
        $this.toggleClass(onHover);
    });
};

$(document).ready(function() { touchHover(); });

</script>

Даем объектам атрибут data-hover с наименованием класса, который отображает состояние hover этого элемента, в дополнение проверяем на ссылку, если ссылка то переходим "по второму клику".

▲ 1

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

<!DOCTYPE html>
<html lang="ru">
    <head>
        <meta charset="utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <title>hi</title>

<style>/*тестовые стили... как и все тут*/
    .menu{
        background: rgba(100,100,100,0.5);

        width: 80%;
        height: 2em;

        margin: 0px auto;

        display: block;
        position: relative;
    }
    .menu li{
        background: rgba(255,0,0,0.5);

        display: block;
        position: relative;
        width: 150px;

        font-size:14px;

        overflow: hidden;

        float: left;

        padding: 0.25em;
        margin: 0.25em;

    }
    .menu li a{
        color: black;
    }

    .drop_down ul{
        background: rgba(255,255,0,0.5);
        overflow: hidden;

         transition: height 0.5s 0.2s ease-out;
            -webkit-transition: all 0.5s 0.2s ease-out;
                -moz-transition: all 0.5s 0.2s ease-out;
                    -o-transition: all 0.5s 0.2s ease-out;
                        -ms-transition: all 0.2s ease-out;
    }

    .close{/*состояние если закрыт*/
        opacity:0;
        height:0px;
    }
    .drop_down:hover ul, .open{/*состояние если открыт*/
        opacity:1;
        height:auto;

    }

    .drop_down:after{
    /*Это что бы по клику сразу же не переходил по ссылке, а дождался открытия категории*/

    content: "";
    display:block;
    width:100%;
    height:100%;
    background: red;
    opacity:0;
    position: absolute;
        top:0px;
        left:0px;

        /*отсрочка анимации, что бы срабатывал не моментально, а с задержкой*/
        transition:all 1s 1s ease-out;
        -webkit-transition:all 1s 1s ease-out;
            -moz-transition:all 1s 1s ease-out;
                -o-transition:all 1s 1s ease-out;
                    -ms-transition:all 1s 1s ease-out;
}

.drop_down:hover:after{
    /*улетаем далеко и сиангулируем*/
    top:-1000px;
    height:0px;
}

    .drop_down:before{

    /*полезно показать, что что то тут вываливается*/

    content: "";
    display: block;
    width:0px;
    height:0px;

    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 5px solid #000;

    position: absolute;
        right:10px;
        top: 0.85em;

        opacity:0.5;

        transform: rotate(180deg);
        -webkit-transform: rotate(180deg);
        -moz-transform: rotate(180deg);
        -ms-transform: rotate(180deg);
        -o-transform: rotate(180deg);

        transition:all 0.3s 0.1s ease-out;
            -webkit-transition:all 0.3s 0.1s ease-out;
                -moz-transition:all 0.3s 0.1s ease-out;
                    -ms-transition:all 0.3s 0.1s ease-out;
                        -o-transition:all 0.3s 0.1s ease-out;
}

.drop_down:hover:before{

        transform: rotate(0deg);
            -webkit-transform: rotate(0deg);
                -moz-transform: rotate(0deg);
                    -ms-transform: rotate(0deg);
                        -o-transform: rotate(0deg);

        opacity:0.9;
        top:0.5em;
}

    .drop_down ul li{
        background: rgba(0,0,255,0.5);

    }
    .drop_down ul li a{
        color:#fff;
    }

</style>
    </head>
<body>

<ul class="menu">
    <li><a href="#">Пункт 1</a></li>
    <li><a href="#">Пункт 2</a></li>
    <li><a href="#">Пункт 3</a></li>
    <li class="drop_down"><!--на выпадающее меню вешаем дропдаун класс-->
        <a href="#">Выпадающее меню</a>
        <ul class="close"><!-- вставляем наш второй уровень с классом "закрыт" -->
                <li><a href="#">Пункт A</a></li>
                <li><a href="#">Пункт B</a></li>
                <li><a href="#">Пункт C</a></li>
        </ul>
    </li>
</ul>
<script>
        var  close_open = false;//переменная закрыт-открыт(...там какой то есть недачет в таком подходе, но я забыл какой. ...но оно работает)
    $( ".drop_down" ).click(function() {//если кликнули по дропдауну, то если переменная close-open равна ложь, то открыть меню(удалить класс close, добавить класс open), присвоив переменной true. открыли.
        if(close_open == false){
            $( ".drop_down ul" ).removeClass("close").addClass("open");
            close_open=true;
        }else{//если переменная true, то мы удаляем класс open, добавлям класс close. закрыли
            $( ".drop_down ul" ).removeClass("open").addClass("close");
            close_open=false; // присвоили переменной false. меню ведь закрыто теперь.
        }
    });

    $( "body" ).click(function() {
//тут я не очень разобрался. в мобилках логает механизм закрытия. поэтому я дополнительно говорю, если кликнуть на body то что бы все закрылось. ...но как правило под курсором не body, а какой то левй контейнер или сложная структура. ...поэтому я хз, как тут поступить.
        $( ".drop_down ul" ).removeClass("open").addClass("close");
            close_open=false;
    }
</script>
</body>
</html>

Идея с active провалилась. При клике, конечно, у нас блок появляется, но как только отпустить курсор (а может быть, и палец), все пропадает. Была идея сделать задержку анимацией, но, что-то там не срослось.