Zum Inhalt springen

css only dropline menü

Erstellt am 6. Mai 2008 · 17 Antworten · letzte Antwort am 23. Juni 2008

Tags: Frage

triskal ·

hallo,

ich habe ein horizontales css-only-menü umgesetzt. es funktioniert derzeit wie in diesem beispiel: http://www.cssplay.co.uk/menus/dd_valid_2.html

schöner wäre es aber nun, wenn die jeweiligen menüpunkte nach der anwahl aufgeklappt bleiben könnten. exakt so wie in folgendem beispiel: http://www.cssplay.co.uk/menus/simple_dropline.html

ist ersichtlich was ich meine? stu verwendet ein php-skript um den current-<ul>s entsprechende css-klassen zuzweisen. das muss ich aber doch über TS lösen können, oder? meins sieht derzeit wie folgt aus:

MAINMENU = HMENU
MAINMENU {
  entryLevel = 1
  1 = TMENU
  1 {
    wrap = <ul> | </ul>
    expAll = 1
    NO.ATagTitle.field = subtitle//title
    NO.wrapItemAndSub = <li>|</li>
    NO.stdWrap.prepend = COA
    NO.stdWrap.prepend.10.wrap = ~&nbsp; |
    IFSUB = 1
    IFSUB {
      wrapItemAndSub = <li>|</li>
      allWrap = | <!--<![endif]-->
      linkWrap = |<!--[if IE 7]><!-->
      ATagBeforeWrap = 1
    }
    ACT < .NO
    ACT = 1
    ACT.ATagParams = class=dropact
    ACTIFSUB < .IFSUB
    ACTIFSUB.ATagParams = class=dropact
  }
  2 = TMENU
  2 {
    wrap = <!--[if lte IE 6]><table><tr><td><![endif]--><ul> | </ul><!--[if lte IE 6]></td></tr></table></a><![endif]-->
    expAll = 0
    NO.ATagTitle.field = subtitle//title
    NO.wrapItemAndSub = <li> | </li>
    NO.ATagParams = class=sub
    IFSUB = 1
    IFSUB {
      wrapItemAndSub = <li> | </li>
      allWrap = | <!--<![endif]-->
      linkWrap = |<!--[if IE 7]><!-->
      ATagBeforeWrap = 1
      ATagParams = class=sub
    }
  }
}

start in kleinen schritten: ich möchte erstmal nur erreichen, dass die beim rollover angezeigten submenüs auch im angeklickten (rootline?-) zustand zu sehen sind. um die reaktion der submenü-links kümmer ich mich dann im zweiten schritt.

kann mir hier jemand einen theoretischen ersten ansatz liefern? mein hirn ist noch so breit von der realisierung des jetzigen menü-zustands, dass ich gerade nicht mehr in der lage bin logisch und strukturiert zu denken...

freu mich über jeden hinweis.
danke und gruss, manuel

EDIT: gerne schiebe ich nach, dass das TS aus folgender quelle stammt: http://typo3.intervation.de/snippets/menues/drop-down-menu.html

triskal ·

ich wieder,

im prinzip muss ich das TS doch nur dazu bewegen mir folgenden HTML-code zu erzeugen:

<ul class="current">
  <li><a href="#">Aktueller Link Hauptmenü</a></li>
</ul>
<ul class="sub_active">
  <li class="current_sub"><a href="#">Aktueller Link Submenü</a></li>
  <li><a href="#">nicht-aktueller Submenü Link 1</a></li>
  <li><a href="#">nicht-aktueller Submenü Link 2</a></li>
  <li><a href="#">nicht-aktueller Submenü Link 3</a></li>
  <li><a href="#">nicht-aktueller Submenü Link 4</a></li>
</ul>

<ul class="select">
  <li><a href="#">Nicht-aktueller Hauptmenü Link<!--[if IE 7]><!--></a>
    <!--<![endif]--><!--[if lte IE 6]><table><tr><td><![endif]-->
    <ul class="sub">
      <li><a href="#">nicht-sichtbarer Submenü Link 1</a></li>
      <li><a href="#">nicht-sichtbarer Submenü Link 2</a></li>
      <li><a href="#">nicht-sichtbarer Submenü Link 3</a></li>
      <li><a href="#">nicht-sichtbarer Submenü Link 4</a></li>
    </ul>
	<!--[if lte IE 6]></td></tr></table></a><![endif]-->
  </li>
</ul>

wobei der obere block 'current' für aktuelle hauptmenü-einträge und der untere für die nicht-aktuellen hauptmenüeinträge erzeugt werden muss.

aber wie das ganze gewrapt werden muss um genau das zu erreichen, dass schnall ich gerade einfach nicht...

gruss, manuel

Dirk1 ·

Hallo,

ich mache das in der Art:

page.1.marks.MENU = HMENU
page.1.marks.MENU {
	entryLevel = 0
	1 = TMENU
	
	1.wrap = <ul> | </ul>
	1.NO = 1
	1.min = 100, 21
	1.noBlur = 1
	1.expAll = 1
	1.NO 	{
		wrapItemAndSub = <li class="nocurrent">|</li>
		ATagParams = class="outer nocurrent"
		}
	1.CUR < .1.NO
	1.CUR.wrapItemAndSub = <li class="current">|</li>
	1.CUR.ATagParams = class="outer current"

	1.ACT < .1.CUR
	1.ACT.ATagParams = class="outer act"

	1.IFSUB.wrapItemAndSub = <li class="sub nocurrent">|</li>
	1.IFSUB.ATagParams = class="outer more nocurrent"

	1.CURIFSUB.wrapItemAndSub = <li class="sub current">|</li>
	1.CURIFSUB.stdWrap.wrap = | 
	1.CURIFSUB.ATagParams = class="outer more current"
	
	1.ACTIFSUB.wrapItemAndSub = <li class="sub act">|</li>
	1.ACTIFSUB.ATagParams = class="outer more act"

	2 < .1
	2.wrap = <div id="inlay"><dl> | </dl></div>
	2.NO.wrapItemAndSub = <dd class="nocurrent left">|</dd> |*| <dd class="nocurrent middle">|</dd> |*| <dd class="nocurrent right">|</dd> 
	2.NO.ATagParams = class="inner nocurrent"
	2.CUR < .2.NO
	2.CUR.wrapItemAndSub = <dd class="current left">|</dd> |*| <dd class="current middle">|</dd> |*| <dd class="current right">|</dd> 
	2.CUR.ATagParams = class="inner current"

	2.NO.ATagParams = class="nocurrent"
	2.CUR.ATagParams = class="current"
	2.ACT.ATagParams = class="nocurrent act"
	2.IFSUB.ATagParams = class="more nocurrent"
	2.IFSUB.ATagParams = class="more nocurrent"

	2.ACTIFSUB.ATagParams = class="more act"

	2.CURIFSUB.ATagParams>
	2.CURIFSUB.ATagParams = class="more current"

}

Es ensteht etwas in der Art:

<ul>
   <li class="nocurrent">
      <dl>
        <dd class="nocurrent">..</dd>
            ...
        <dd>..</dd>
      </dl>
   </li>
   <li class="current">
      <dl>
        <dd class="current">..</dd>
            ...
        <dd class="nocurrent">..</dd>
      </dl>
   </li>
   <li class="nocurrent">
      <dl>
        <dd class="nocurrent">..</dd>
            ...
        <dd class="nocurrent">..</dd>
      </dl>
   </li>
   ...
</ul>

Die Listen sind also ineinander verschachtelt und auch die unsichtbaren immer da und können jederzeit über :hover sichtbar gemacht werden - oder eben über class "current". Für die innere Liste nehme ich nur aus praktischen Gründen <dl> (wegen der Unterscheidbarkeit). <ul> würde genau so gehen.

Wie das menu nun genau aussieht ist Sache von CSS.

Gruß
Dirk

triskal ·

hi dirk,

vielen dank für deine schnelle antwort. ich melde mich erst jetzt, weil ich die letzten tage versucht habe, deinen vorschlag umzusetzen.

es klappt insofern auch schon super, dass die submenüs wie gewünscht stehen bleiben. aber wie kann ich es steuern, dass sie ausgeblendet werden, wenn ich über andere hauptmenü-button rollover?!

ist mein problem nachvollziehbar? es sieht so aus, als wenn ich hier einen css-denkfehler hätte. tut mir auch leid, hier css thematisieren zu müssen, aber da du so ein menü wie es scheint schon erfolgreich umgesetzt hast, würde ich an dieser stelle sehr gerne noch mal deine hilfe in anspruch nehmen.

hier ein auszug des meines erachtens relevanten quelltextes:

/* erstmal alle dd's im sub-div 'inlay' ausblenden::: */
#inlay dl dd   { display:none; }

/* allgemeine formatierung der dl's im sub-div 'inlay'::: */
#inlay dl { 
  position:absolute;
  height:20px;
  line-height:20px;
  top:27px;
  left:0;
  width:750px;
}

/* formatierung der links im sub-div 'inlay'::: */
#inlay dl dd a.current,
#inlay dl dd a.nocurrent {
  font-size:11px;
  font-weight:normal;
  text-decoration:none;
  background:none;
  color:#575757;
}

/* dto. */
#inlay dl dd a.current,
#inlay dl dd a.nocurrent:hover {
  background:#F0A001;
  color:#575757;
  text-decoration:none;
}

/* bei aktuellem hauptmenü-topic, die entsprechenden dd's einblenden::: */
#m1 ul li.current #inlay dl dd { display:block; }

/* beim rollover nicht-aktueller hauptmenü-topics, die entsprechenden dd's einblenden:::*/
#m1 ul li.nocurrent:hover #inlay dl dd,
#m1 ul li.nocurrent a:hover #inlay dl dd { display:block; }

die letzten zwei css-geschichten sind glaube ich relevant für meine problematik. prinzipiell müsste ich so etwas coden können:

#m1 ul li.nocurrent:hover #m1 ul li.current #inlay dl dd,
#m1 ul li.nocurrent a:hover #m1 ul li.current #inlay dl dd { display:none; }

aber das klappert leider nicht...
kannst du mir sagen, wie du das gelöst hast?

danke und gruss, manuel

Dirk1 ·

Hallo Manuel,

vielleicht wäre es besser, wenn du deine Operationen zur Sichtbarkeit nicht auf die einzelnen unterpunkte, sondern auf die komplette Liste anwenden würdest.

Du willst doch dass das komplette Untermenu erscheint und verschwindet. Oder?

Also z.B.

#m1 ul li.nocurrent #inlay dl { display:none; }
#m1 ul li.nocurrent:hover #inlay dl { display:block; }

Das ist eigentlich schon das ganze Prinzip. das Ganze wirkt natürlich nur auf hierarchisch untergeordnete Bereiche. Effekte auf parallele Bereiche sind nicht möglich. Du kannst andere Bereiche höchstens überdecken. Das reicht aber für deinen Zweck, glaube ich.

Dein

#m1 ul li.nocurrent a:hover #inlay dl dd { display:block; }

Verstehe ich nicht. Das würde bedeuten deine Liste ist innerhalb des <a>-Tags.
Das wäre aber kein valider HTML-Code - oder ist das für den IE6?
Dafür hätte ich eine bessere Lösung.

Gruß
Dirk

triskal ·

hi dirk,

erneut bedanke ich mich für deine hilfe. das mit dem überdecken war der entscheidende hinweis. somit läuft das menü jetzt schonmal im firefox und ie7. wie genau sieht denn dein trick für den ie6 aus? arbeitest du wie stu mit den table-tags?

ein weiteres problem besteht jedoch noch. und zwar ist per css doch ein li:hover genauso möglich wie ein a:hover, oder? aber genau das krieg ich nicht hin. beim rollover über einen hauptmenü-link wird das submenü angezeigt. versuche ich dann den mauszeiger dort hinzusteuern, verliert er den kontakt zum hauptmenü-link und das submenü verschwindet. es sind nur zwei, drei pixel die hier zwischen dem a-tag des hauptmenüs und der dl aus dem submenü fehlen. es sieht so aus, als wenn nur das a:hover zieht, nicht das li:hover. wie müssen a-, li- und hover-tags im hauptmenü css-technisch korrekt aufgebaut werden, damit das richtig funktioniert?

danke und gruss, manuel

Dirk1 ·

Hallo manuel,

arbeitest du wie stu mit den table-tags?

Tut er das wirklich?

und zwar ist per css doch ein li:hover genauso möglich wie ein a:hover, oder?

Aber leider nicht im IE6. Der kann das nur mit <a>-tags.
Deshalb lösen viele das Problem, indem sie den fraglichen Bereich in ein <a> </a> verpacken.

Das ist aber nicht HTML-konform.

versuche ich dann den mauszeiger dort hinzusteuern, verliert er den kontakt zum hauptmenü-link und das submenü verschwindet.

Ist das submenu html-mässig verschachtelt?

<li class="menu-item">
<a ...>...</a>
Unternmenu-elemente

</li>

..erlaubt von dem aussen-liegenden <li> einen Zugriff auf das Untermenu.
Aber nicht von <a> aus, da die beiden Blöcke NACHEINANDER kommen und nicht ineinander verschachtelt sind.

Wenn du also W3C-konformen Code produzieren willst, kannst du beim <a> element als hover-Effekt nur Eigenschaften des <a>-Elementes selbst manipulieren.

Also hover für das submenu nur über das aussen liegende <li>, oder was immer man da verwendet hat.

Das kann aber IE6 wie gesagt nicht. Man kann es ihm aber beibringen mit einem htc-script, EINER Zeile (!) in der CSS-Datei und NULL Eingriff in HTML oder Typo3.
Details verrate ich dir, wenn du dein Verfahren im Firefox und IE7 sauber zu laufen gebracht hast.

Man kann sich aber auch auf den Standpunkt stellen, dass der IE6 dann eben nicht hovern kann - sozusagen als Anreiz zum Update. Deine Navigation sollte aber natürlich trotzdem funktionieren und daher auch nicht auf den hover -Effekt angewiesen sein.

Gruß
Dirk

triskal ·

hi dirk,

ok. in ff und ie7 funktioniert es soweit. hier der beweis: [LINK GELÖSCHT]

verrätst du mir die 'zauber-css-zeile' für den ie6?

danke und gruss, manuel

Dirk1 ·

Gerne:

Du erstellst eine Datei (Inhalt folgt am Ende), die du z.B. in folgender Weise über CSS referenzierst:

body {behavior:url("fileadmin/hover.htc")}

CSS-Validatoren meckern diese Zeile allerdings an.
Vielleicht kann man das über Kommentar-Tricks (mit denen ich mich nicht beschäftigt habe) aber auch noch irgend wie hin bekommen. Denn es ist ja wirklich nur für IE6.

Zu beachten ist allerdings noch, dass die Klassen mit dem voll qualifizierten Objekttyp angesprochen werden müssen.
Also nicht #ml .. li:hover {..}, sondern div#ml .. li:hover {..}
Funktioniert sonst nicht - daran bin ich mal fast einen vollen Tag verzweifelt.

Was dir dann noch passieren kann, ist die Kollision mit Javascript. Ich hatte z.B. mit der Extension JW_Calendar das Problem, dass das menu immer so seltsam flackerte. Aber auch dafür gibts eine Lösung.

<attach event="ondocumentready" handler="parseStylesheets" />
<script>
/**
 *	HOVER - V1.00.031224 - whatever:hover in IE
 *	---------------------------------------------
 *	Peterned - http://www.xs4all.nl/~peterned/
 *	(c) 2003 - Peter Nederlof
 *
 *	howto: body { behavior:url("csshover.htc"); }
 *	---------------------------------------------
 */

var CSSBuffer, doc = window.document;

function parseStylesheets() {
	var rules, sheet, sheets = doc.styleSheets;
	var bufferIndex = sheets.length;	
	var head = doc.getElementsByTagName('head')[0];
	var buffer = doc.createElement('style');

	buffer.setAttribute('media', 'screen');
	buffer.setAttribute('type', 'text/css');
	head.appendChild(buffer);
	CSSBuffer = sheets[bufferIndex];

	for(var i=0; i<sheets.length -1; i++) {
		sheet = sheets[i];
		if(!sheet.media || sheet.media == 'screen') {
			rules = sheet.rules;
			for(var j=0; j<rules.length; j++) {
				parseCSSRule(rules[j]);
			}
		}
	}
}
	function parseCSSRule(rule) {
		var select = rule.selectorText, style = rule.style.cssText;
		if(!select || !style || select.indexOf(':hover') < 0) return;
		var newSelect = select.replace(/\:hover/g, '.onHover');
		CSSBuffer.addRule(newSelect, style);
		
		var affected = select.replace(/\:hover.*$/g, '');
		var elements = getElementsBySelect(affected);
		for(var i=0; i<elements.length; i++) {
			if(elements[i].nodeName == 'A') continue;
			new HoverElement(elements[i]);
		}
	}

/**
 *	HoverElement
 *	-------------------------
 *	applies the hover
 */

function HoverElement(element) {
	if(element.isHoverElement) return;
	element.isHoverElement = true;
	element.attachEvent('onmouseover', 
		function() { element.className += ' onHover'; });

	element.attachEvent('onmouseout', 
		function() { element.className = element.className.replace(/onHover/g, ''); });
}

/**
 *	domFinder
 *	-----------------------------------
 *	returns list of elements based on css selector
 */

function getElementsBySelect(rule) {
	var nodeList = [doc], sets = rule.split(' ');
	for(var i=0; i<sets.length; i++) {
		nodeList = domFinder.filterNodes(sets[i], nodeList);
	}	return nodeList;
}

var domFinder = {
	findNodes:function(tag, docs) {
		var res, nodes = [];
		for(var i=0; i<docs.length; i++) {
			res = docs[i].getElementsByTagName(tag);
			for(var j=0; j<res.length; j++) nodes[nodes.length] = res[j];
		}	return nodes;
	},

	filterNodes:function(select, docs) {
		var filtered = [], nodes,rule,atr,s = (/#|\./).exec(select);
		if(!s) return this.findNodes(select, docs);
		nodes = this.findNodes((rule = select.split(s))[0], docs);
		atr = (s == '#')? 'id':'className';
		for(var i=0; i<nodes.length; i++) {
			if(new RegExp('(^|\\s)' +  rule[1] + '(\\s|$)').exec(nodes[i][atr]))
				filtered[filtered.length] = nodes[i];
		}	return filtered;
	}
}
</script>

Gruß
Dirk

triskal ·

hi dirk,

es funktioniert, vielen dank. ich habe beide skripts getestet, aber nur das neuere von beiden aktiv bekommen. das ist allerdings sicher auf einen fehler meinerseits zurückzuführen.

es macht den anschein, als wenn auch beim neuen skript die klassen mit dem voll qualifizierten objekttyp angesprochen werden müssen. anders hat es bei mir jedenfalls nicht funktioniert.

was bekommst du für deine tatkräftige unterstützung?

danke und gruss, manuel

triskal ·

hi dirk,

bist du noch da? oder sonst wer der das problem kennt?

und zwar werfen die meisten ie's (sowohl 6er als auch 7er) eine fehlermeldung die wie folgt lautet: 'probleme mit dieser website verhindern evtl., dass die seite nicht richtig dargestellt wird. [...]'

leider kann ich den fehler bei mir nicht provozieren, da meine ie-konfigurationen irgendwie anders zu sein scheinen...

die funktionalität ist wohl trotzdem gegeben, aber viele scheint diese fehlermeldung einfach zu nerven.

jemand eine idee? wie hängt das mit diesen htc-dateien zusammen?

danke und gruss, manuel

Dirk1 ·

Da wirst du wohl nicht drum herum kommen, den Fehler zu reproduzieren.
Wie soll andernfalls eine vernünftige Analyse statt finden.

Welche IE-Versionen sind denn im Spiel?

triskal ·

hi dirk,

entschuldige dass meine vorherigen bemerkungen so wenig informativ waren. ich sitze mittlerweile an einem anderen rechner, kann den fehler im ie6 reproduzieren und genauer eingrenzen:

der fehler tritt nur dann auf, wenn der browser (ie) neu gestartet wird und ich per domain.org die entsprechende url anwähle. zu diesem zeitpunkt funktionieren die menüeffekte auch nicht. ein anklicken der hauptmenüpunkte (ohne rollover) ist trotzdem möglich.

wähle ich einen menüpunkt an, ist der fehler weg. gehe ich zurück zur startseite, entweder über das hauptmenü das den link www.domain.org/index.php?id=start anspringt, ist der fehler nicht da. wähle ich erneut die url domain.org an, wird der fehler ebenfalls nicht mehr angezeigt.

schließe ich jedoch den browser, öffne ihn erneut und wähle die url www.domain.org an, ist der fehler wieder da.

und nun zur fehlermeldung:
unten links in der statuszeile: [ausrufezeichen in gelbem dreieck] fertig, es sind fehler aufgetreten. [klick auf die fehlermeldung/meldungstext:] probleme mit dieser website verhindern eventuell, [...]

[details:]
zeile: 0
zeichen: 0
fehler: access is denied to http://www.domain.org/fileadmin/template/hover.htc
code: 0
URL: http://domain.org
[/details]

oh. gerade fällt mir auf, wo ich die letzte zeile der details erblicke, der fehler tritt nur dann auf, wenn ich die url http://domain.org anwaehle. bei http://www.domain.org tritt der fehler ebenfalls nicht auf. welche auswirkungen hat das fehlende www. und was hat das mit der hover.htc zu tun?

gruss, manuel

Dirk1 ·

Ich tippe auf Pfadprobleme.
Er findet die hover.htc nicht.

Wie ist deine Dateistruktur aufgebaut?

Du könntest spasseshalber die hover.htc aus dem html-head heraus referenzieren (natürlich hier den Pfad zu der Datei entsprechend anpassen).

Dirk