Frage

Ich versuche, eine horizontale Akkordeon mit Jquery zu bauen. Es scheint, „ok“ in Firefox zu arbeiten. Aber in Webkit (Safari 3 + 4 und Chrome) die Unterebene UL blinkt nach dem Ausblenden-Funktion. Jede Hilfe wäre sehr geschätzt. Um eine Arbeits Demo finden Sie unter: http://ableobject.com/horaccordion1.html

Hier ist das, was ich arbeite an:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>

    <title>untitled</title>
    <style type="text/css">
    #container {
        display: table; 
        margin: 0 auto; 
        text-align: center; /* for IE */
    }
            ul{
                    list-style: none;
                    background-color: yellow;
                    margin: 0;
                    padding: 0;
                    float: left;
                    height: 20px; /* For testing */     
            }
            ul li {
                   background-color: aqua;
                    float: left;
            }
            ul li ul {
                   background-color: blue;
                    display: none;
            }
            ul li ul li {
                   background-color: green;
            }
            a, a:link, a:hover, a:visited, a:active {
                    color: black;
                    text-decoration: none;
                    float: left;
            }
    </style>

   <script type="text/javascript">
/* Care of Hunter Daley */
    var $current = null;
        $(document).ready(function(){
         $("ul li ul").hide();  // hide submenus by default on load

           $("ul li a").click(function(){
              var $sub = $(this).next(); 
              if ($sub.css("display") == "none")
              {
                 if ($current != null)
                    $current.animate({ width: 'hide' }); // if you want to only show one sub at a time
                 $sub.animate({ width: 'show' }); 
                 $current = $sub;
              }
              else
              {
                 $sub.animate({ width: 'hide' });
                 $current = null;
              }
           });
        });
    </script>
</head>

<body>
    <div id="container">
    <ul>
            <li>
                    <a href="#">Top-level 1</a>
            </li>
            <li>
                    <a href="#">Top-level 2</a>

                    <ul>
                            <li><a href="#">Bottom Level A1</a></li>
                            <li><a href="#">Bottom Level A2</a></li>
                            <li><a href="#">Bottom Level A3</a></li>
                            <li><a href="#">Bottom Level A4</a></li>
                    </ul>
            </li>

            <li>
                    <a href="#">Top-level 3</a>
                    <ul>
                            <li><a href="#">Bottom Level B1</a></li>
                            <li><a href="#">Bottom Level B2</a></li>
                    </ul>
            </li>

            <li>
                    <a href="#">Top-level 4</a>
            </li>
    </ul>
</div>
</body>
War es hilfreich?

Lösung

Das klingt wie es zu einem Problem im Zusammenhang I mit webkit vor einer Weile hatte. Es gibt einen Webkit Fehler, der manchmal ein Element Eltern verursacht zu seiner ursprünglichen Größe nach einer Animation zurückzukehren, dass die Breite Elemente reduziert. Nach der Animation, der Eltern-Element springt auf seine ursprüngliche Größe wieder in Ordnung sein Inhalt gerecht zu werden.

Edit: Entfernte Kommentare über jQueryUI. Nicht sicher, warum ich dachte, dass Sie es verwendet haben.

Der Bug wurde hier diskutiert , die Details eine Abhilfe.

Ich legte einen Bugreport jQuery als auch.

Im Grunde müssen Sie gleichzeitig die Breite Ihres $sub geordneten Elements zu reduzieren, um den gleichen Betrag wie $sub reduziert wird. Also, wenn die Breite der $sub 100px ist, gäbe es eine separate animate() sein, um die Eltern zu reduzieren, indem 100px.

Ich habe irgendetwas davon mit Ihrem Beispiel nicht getestet, aber ich denke, es ist wahrscheinlich der Schlüssel.

Edit 2: Eine neue Version mit divs

CSS:

.title {
       list-style: none;
       margin: 0;
       padding: 0;
       float: left;
       height: 32px; /* For testing */
       font-family: helvetica;
       font-size: 18px;
       clip: auto; overflow: hidden;
}
.menu {
       height: 32px; /* For testing */
       clip: auto; overflow: hidden;
       float: left;
}
a, a:link, a:hover, a:visited, a:active {
       color: black;
       text-decoration: none;
       padding: 12px;
       font-weight: 700;
       float: left;
       color: #222;
}

 .menu a, .menu a:link, .menu a:hover, .menu a:visited, .menu a:active {
   color: black;
   text-decoration: none;
   padding: 12px;
   font-weight: normal;
   float: left;

}

javascript:

    // Prevents us from having to check for null.
    var $current = $('#someFictionalElement');
    var $previous = null;
    $(document).ready(function(){
    $(".menu").css({width: 0});  // hide submenus by default on load

    $(".title").click(
        function() {
            $previous = $current;
            $current = $(this);
            var $currentMenu = $current.next();

            $previous.next().animate({ width: 0 }, {duration: 1000, queue: false} );

    // Make sure that if there's no menu text (like Top Level 1 and 4) that it does not animate.
    // This is because of the pixels added for Firefox (see comment below)
            if( $currentMenu.width() == 0 && $currentMenu.text() != ''  ) {

    // Expand the menu but keep it hidden so we can get its width
                $currentMenu.css({visibility: 'hidden', width: ''});

    // Store the width, and add a few pixels for Firefox
                var currentWidth = $currentMenu.width() + 3;

    // Make menu visible and set with to 0 in preparation for the animation
                $currentMenu.css({visibility: 'visible', width: 0})
                            .animate({ width: currentWidth }, 1000);
            }
    });

    $(".title a").hover(
        function(){$(this).animate ({ opacity: 0.7 }, 200);},
        function(){$(this).animate ({ opacity: 1 }, 600);}
    );
});

HTML:

<body>
    <div id="container">
        <div class='title' id='level1'>
            <a href="#">Top-level 1</a>
        </div>
        <div class='menu'></div>
        <div class='title' id='level2'>
            <a href="#">Top-level 2</a>
        </div>
        <div class='menu'>                         
            <a href="#">Bottom Level A1</a>
            <a href="#">Bottom Level A2</a>
            <a href="#">Bottom Level A3</a>
            <a href="#">Bottom Level A4</a>
        </div>
        <div class='title' id='level3'>
            <a href="#">Top-level 3</a>
        </div>
        <div class='menu'>
            <a href="#">Bottom Level B1</a>
            <a href="#">Bottom Level B2</a>
        </div>
        <div class='title' id='level4'>
            <a href="#">Top-level 4</a>
        </div>      
        <div class='menu'></div>
    </div>
</body>

Andere Tipps

Ich poste das als eine separate Antwort nur für den Fall finden Sie noch die vorherige nützlich.

Bitte beachten Sie Folgendes:

  • Ich habe nicht getestet in IE.
  • Dies geht zurück auf eine ‚verschachtelte‘ -Version, also habe ich die Klasse und Variablennamen ein wenig.
  • Ein leeres Menü ist nicht mehr erforderlich, wenn kein Menü angezeigt werden soll.
  • Die Breite jeder ‚Container‘-Menü wird jetzt die gleiche Menge wie das Menü reduziert. Dies ist, was webkit temporären Flash eliminiert (die die ursprüngliche Strategie war).
  • Sie werden bemerken, die das Timing der Animation des Menüs als das etwas anders des Containers-Menü. Im Grunde wollen Sie den Behälter ein wenig voraus zu sein, wenn erweitert, und das Menü ein wenig voraus zu sein, wenn zu reduzieren. Wenn der Zeitpunkt gleich eingestellt ist, können Sie einige Blinken des Menüs angezeigt wird.
  • Wie in den Kommentaren erklärt, am Anfang jedes Menü ‚speichert‘ seine Breite, wenn durch das Setzen eines vorher nicht vorhandenen Attribut namens ‚voller Breite‘ voll ausgebaut. Er ruft dann den Wert dieses Attributs, wenn nötig. Sie könnten nur verwenden, wie leicht globale Variablen oder jQuery-Daten () Funktion, um die Informationen zu speichern. Der Punkt ist, dass die Dinge vereinfacht werden, wenn jedes Menü ist sich dessen bewusst, wie groß es sein sollte, wenn es erweitert wird.

Also hier ist es. Hoffe, es hilft!

CSS

#container {
    margin: 0 auto 0 auto; 
    text-align: center;
    display: table;
}

.menuContainer {
       margin: 0;
       padding: 0;
       float: left;
       height: 32px; /* For testing */
       font-family: helvetica;
       font-size: 18px;
       clip: auto; overflow: hidden;
}
.menu {
       height: 32px; /* For testing */
       clip: auto; overflow: hidden;
       float: left;
}
a, a:link, a:hover, a:visited, a:active {
       color: black;
       text-decoration: none;
       padding: 12px;
       font-weight: 700;
       float: left;
       color: #222;
}

.menu a, .menu a:link, .menu a:hover, .menu a:visited, .menu a:active {
   color: black;
   text-decoration: none;
   padding: 12px;
   font-weight: normal;
   float: left;
}

Javascript

var $currentMenuContainer = $('#someFictionalElement');
var $previousMenuContainer = null;

$(document).ready(function() {

// Iterate through each .menu element, setting the full width of each menu to a 'custom'
//        attribute called 'fullWidth'. Since the full width should never change, this
//        makes it easy to recall it quickly. You could use global variables instead.
// After setting 'fullWidth', it then collapses each menu and title.
$(".menu").each(function() {
    var $theMenu = $(this);
    var $theMenuContainer = $theMenu.parent();
    $theMenu.attr({fullWidth: ($theMenu.width() + 3)});   // Add a few pixels for firefox
    var menuContainerWidth = $theMenuContainer.width() - $theMenu.attr('fullWidth') + 6;  // Add DOUBLE the pixels here
    $theMenu.css({width: 0});
    $theMenuContainer.css({width: menuContainerWidth});
});

    $(".menuContainer a").click(
        function() {
// Set the current and previous elements properly
            $previousMenuContainer = $currentMenuContainer;
            $currentMenuContainer = $(this).parent();
            var $previousMenu = $previousMenuContainer.find('.menu');
            var $currentMenu = $currentMenuContainer.find('.menu');

// Collapse the previous menu
            $previousMenu.animate({ width: 0 }, {duration: 480, queue: false} );

// Subtract the width of the previous menuContainer's menu from the menuContainer (only if its menu is displayed)
            if($previousMenu.width() > 0) $previousMenuContainer.animate({width: ('-=' + $previousMenu.attr('fullWidth'))}, 500);

// Expand the current menu and its menuContainer if it's not showing
            if($currentMenu.width() == 0) {
                // Increase the menuContainer width by the full width of its menu
                $currentMenuContainer.animate({width: ('+=' + $currentMenu.attr('fullWidth'))}, 480);
                // Increase the menuContainer to its full width
                $currentMenu.animate({ width: $currentMenu.attr('fullWidth') }, 500);
            }
    });

    $(".menuContainer a").hover(
        function(){$(this).animate ({ opacity: 0.7 }, 200);},
        function(){$(this).animate ({ opacity: 1 }, 600);}
    );
});

HTML

<div id="container">
    <div class='menuContainer'>
        <a href="#">Top-level 1</a>
    </div>
    <div class='menuContainer'>
        <a href="#">Top-level 2</a>
        <div class='menu'>                         
            <a href="#">Bottom Level A1</a>
            <a href="#">Bottom Level A2</a>
            <a href="#">Bottom Level A3</a>
            <a href="#">Bottom Level A4</a>
        </div>
    </div>
    <div class='menuContainer'>
        <a href="#">Top-level 3</a>
        <div class='menu'>
            <a href="#">Bottom Level B1</a>
            <a href="#">Bottom Level B2</a>
        </div>
    </div>
    <div class='menuContainer'>
        <a href="#">Top-level 4</a>
    </div>
</div>

Edit: Fügen Sie die folgende DTD zum oberen Rand der Seite -

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top